Compare commits
336 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68605ddb35 | ||
|
|
132ce24328 | ||
|
|
4af127196c | ||
|
|
39bccaf895 | ||
|
|
54c5958715 | ||
|
|
6b79ebf003 | ||
|
|
75d5cb180d | ||
|
|
245f81be26 | ||
|
|
1f950e0663 | ||
|
|
aecb5448ea | ||
|
|
c02ac7dacc | ||
|
|
332e02d9fd | ||
|
|
a2b3db6793 | ||
|
|
6883c81322 | ||
|
|
600c55f5f8 | ||
|
|
bf20aec94f | ||
|
|
26c269e8ba | ||
|
|
db42feed35 | ||
|
|
10f97cffa1 | ||
|
|
22e6621300 | ||
|
|
4d2b62e4a1 | ||
|
|
dd0d48cd08 | ||
|
|
2de512b447 | ||
|
|
1765d82ad9 | ||
|
|
c52cca09f1 | ||
|
|
545d5c7573 | ||
|
|
99d0847caa | ||
|
|
3b7fe2ec58 | ||
|
|
92fc80095d | ||
|
|
751e36cba7 | ||
|
|
487e616801 | ||
|
|
d5915cd287 | ||
|
|
d1f63ab55f | ||
|
|
857515576e | ||
|
|
69c6177be5 | ||
|
|
38fa63324c | ||
|
|
940f5486aa | ||
|
|
11622795e1 | ||
|
|
cb7603feea | ||
|
|
7b5e8e15d5 | ||
|
|
9a74710c1e | ||
|
|
3f7bf56be2 | ||
|
|
501c2fbabd | ||
|
|
3dad820014 | ||
|
|
2f82021b5d | ||
|
|
a3287bb2bc | ||
|
|
6c82f1a96f | ||
|
|
f2446c0781 | ||
|
|
4d6ee68054 | ||
|
|
854238ef98 | ||
|
|
2b41745a05 | ||
|
|
c2e15151a6 | ||
|
|
b25f52a40d | ||
|
|
145ec33620 | ||
|
|
307e19fd52 | ||
|
|
9eb9ea0263 | ||
|
|
f8fc8e7f60 | ||
|
|
3d1cfba85c | ||
|
|
1f6fc63f46 | ||
|
|
3931c0ed4d | ||
|
|
74eb7763cf | ||
|
|
e0e65c022f | ||
|
|
574526aca0 | ||
|
|
29f21decb4 | ||
|
|
b70dd619a4 | ||
|
|
0d5814dad1 | ||
|
|
5f64ead354 | ||
|
|
80c8b22faa | ||
|
|
696edc1f1d | ||
|
|
a1336c8d2e | ||
|
|
1187f1a1b6 | ||
|
|
dc921e4c04 | ||
|
|
bff6a2d4d6 | ||
|
|
36c3418a3e | ||
|
|
a7e32bc69b | ||
|
|
139ad5828a | ||
|
|
1636ca7e13 | ||
|
|
46a8ddc207 | ||
|
|
26e0324f4a | ||
|
|
c1faeeaabf | ||
|
|
a93c8a56bb | ||
|
|
b33cee7271 | ||
|
|
6e68e12b60 | ||
|
|
013f852e7e | ||
|
|
99dbaea143 | ||
|
|
a09a1520a1 | ||
|
|
a7a064119d | ||
|
|
6458988cc8 | ||
|
|
9b1876b235 | ||
|
|
0d9ee4203c | ||
|
|
2ea03601f5 | ||
|
|
3d4a54418c | ||
|
|
ba4f161122 | ||
|
|
17718cbbca | ||
|
|
f9ad597d2b | ||
|
|
c8b6a8c5ed | ||
|
|
df8591b1ef | ||
|
|
9478e0faa1 | ||
|
|
91a6eb7763 | ||
|
|
d512f0ba81 | ||
|
|
31995965f9 | ||
|
|
d35840d825 | ||
|
|
e270b4f73b | ||
|
|
1a754f4012 | ||
|
|
4757d9dfa8 | ||
|
|
74bb34bbc8 | ||
|
|
1b235ebaa4 | ||
|
|
44d486dfeb | ||
|
|
5cc982188a | ||
|
|
aadbe02df4 | ||
|
|
20bed84910 | ||
|
|
fc3113f243 | ||
|
|
be368738ba | ||
|
|
4209f690a8 | ||
|
|
a3a2614124 | ||
|
|
50f6db9344 | ||
|
|
17d554d269 | ||
|
|
1bef713de5 | ||
|
|
beee6f409c | ||
|
|
540f510eb0 | ||
|
|
92334b2f54 | ||
|
|
515f51d84a | ||
|
|
51dbf89ad6 | ||
|
|
631bfea3da | ||
|
|
9d3298ea25 | ||
|
|
d83fd91d3f | ||
|
|
89ff76ac8a | ||
|
|
9a22e816f0 | ||
|
|
5dc328ebc2 | ||
|
|
b1adefe8f3 | ||
|
|
ff8032f26a | ||
|
|
fa1d86ae7e | ||
|
|
c621a56f67 | ||
|
|
5b4fb85db6 | ||
|
|
0113c8272e | ||
|
|
2a2d311ac1 | ||
|
|
a7de7a7315 | ||
|
|
551125bb50 | ||
|
|
abc1da7095 | ||
|
|
37c9415c2a | ||
|
|
42cf719de9 | ||
|
|
7b07b7954a | ||
|
|
074950ebf6 | ||
|
|
7e505285c6 | ||
|
|
d341b4cfbd | ||
|
|
551589e461 | ||
|
|
5144491e81 | ||
|
|
bd8e4d6c86 | ||
|
|
c4529d0890 | ||
|
|
005d9e863e | ||
|
|
5c03cea8c4 | ||
|
|
d73b1a3f43 | ||
|
|
883a84412b | ||
|
|
3a3d58e8a0 | ||
|
|
1e72bac223 | ||
|
|
d771bed2db | ||
|
|
f64a76a128 | ||
|
|
b1f12e55a1 | ||
|
|
a8956df057 | ||
|
|
eb3dac0821 | ||
|
|
f63f0420e2 | ||
|
|
4dd5483f35 | ||
|
|
f72fe35e03 | ||
|
|
e35b91f142 | ||
|
|
43b366b467 | ||
|
|
b6fb136098 | ||
|
|
639841cf20 | ||
|
|
93a00d1b48 | ||
|
|
00b1b78cb3 | ||
|
|
feab41ac5c | ||
|
|
35ef646402 | ||
|
|
cc3ee9495c | ||
|
|
1c990f3b9b | ||
|
|
0e911ec860 | ||
|
|
ec44e4a29e | ||
|
|
7a7e90dd7d | ||
|
|
3fb22a9b1e | ||
|
|
5b524e5a4f | ||
|
|
e055b49c10 | ||
|
|
dd91ca3c7a | ||
|
|
41b6bfd456 | ||
|
|
6e9e522731 | ||
|
|
509f03f2ef | ||
|
|
72f225f154 | ||
|
|
40fe46c1c6 | ||
|
|
6c5276aff2 | ||
|
|
95f1aa304e | ||
|
|
d9c315401c | ||
|
|
afaceac86e | ||
|
|
5180a2cbfb | ||
|
|
f38d68a35a | ||
|
|
3be619c329 | ||
|
|
b9ed37f3ba | ||
|
|
15b1d070bf | ||
|
|
1028cef704 | ||
|
|
f984a834fc | ||
|
|
02c992b12a | ||
|
|
482fffbdd0 | ||
|
|
95bbedd698 | ||
|
|
81f9bbf6ea | ||
|
|
74adac6f9d | ||
|
|
c425203618 | ||
|
|
d3d0db3941 | ||
|
|
a41f976949 | ||
|
|
aeb1bca94d | ||
|
|
06e41790ca | ||
|
|
d3722c1171 | ||
|
|
c35454807d | ||
|
|
cf27a24380 | ||
|
|
1273dc7c7a | ||
|
|
1cb60dd0e8 | ||
|
|
312294edb8 | ||
|
|
6b1205e160 | ||
|
|
2cbf5aea8b | ||
|
|
4cf97a2e79 | ||
|
|
1098333247 | ||
|
|
49832092b4 | ||
|
|
f2007d56a9 | ||
|
|
4e4b771e41 | ||
|
|
2bf1631809 | ||
|
|
ba119de89b | ||
|
|
33140938c9 | ||
|
|
2c5c3885d1 | ||
|
|
96ddd3e030 | ||
|
|
809d5492e8 | ||
|
|
77cf50066a | ||
|
|
2606f664bc | ||
|
|
97b51e1bcf | ||
|
|
ecee8b06e7 | ||
|
|
d6ba1e9068 | ||
|
|
f352b40232 | ||
|
|
74508a9ed1 | ||
|
|
0d3b82aee3 | ||
|
|
8a3b0bb190 | ||
|
|
55a4f9fdb4 | ||
|
|
9a3a57a819 | ||
|
|
53eacd4717 | ||
|
|
877e5a711e | ||
|
|
bd8dae128c | ||
|
|
0d85638464 | ||
|
|
38141bc5db | ||
|
|
ebd128c710 | ||
|
|
18dc61f552 | ||
|
|
3418378139 | ||
|
|
03093f77a7 | ||
|
|
1b248d744e | ||
|
|
fe6d88fa43 | ||
|
|
43cf52cd02 | ||
|
|
18cae1de98 | ||
|
|
e7119cf032 | ||
|
|
34570cd013 | ||
|
|
c09c3ac646 | ||
|
|
16e83955f3 | ||
|
|
cda3a61d2a | ||
|
|
9a4d07900c | ||
|
|
26f7867320 | ||
|
|
f7bd45420b | ||
|
|
c4f6890dd0 | ||
|
|
f7c9047457 | ||
|
|
c9b41838be | ||
|
|
46bc6030fe | ||
|
|
6adb694077 | ||
|
|
0fdc0de27d | ||
|
|
bd9be10e02 | ||
|
|
441fe67890 | ||
|
|
a7d49c7253 | ||
|
|
65795cbe79 | ||
|
|
81be27561d | ||
|
|
150772e252 | ||
|
|
33299b0779 | ||
|
|
46175908b1 | ||
|
|
56da8583b0 | ||
|
|
4fb19ae5a6 | ||
|
|
627e480d07 | ||
|
|
6f17b428bc | ||
|
|
3bc4ce471f | ||
|
|
3d6144cfcd | ||
|
|
8fde83c049 | ||
|
|
328d3c4d3a | ||
|
|
e374601402 | ||
|
|
deb6dcc056 | ||
|
|
980545a07e | ||
|
|
30f343a7de | ||
|
|
d1aef1f67d | ||
|
|
4887699892 | ||
|
|
f973b774a2 | ||
|
|
52a4798377 | ||
|
|
3d963a2ad6 | ||
|
|
3443198edb | ||
|
|
a691a729cf | ||
|
|
5e89a05b26 | ||
|
|
74c7b99bc5 | ||
|
|
35ead001b0 | ||
|
|
a754ae70c4 | ||
|
|
78942d2e78 | ||
|
|
e8269899b0 | ||
|
|
d82fce6f2f | ||
|
|
2cf794552f | ||
|
|
9459360948 | ||
|
|
e8d4a37fdc | ||
|
|
ca42c383d1 | ||
|
|
7813d242e8 | ||
|
|
7424f45ae3 | ||
|
|
7557a13544 | ||
|
|
c8cd318f2d | ||
|
|
99ce9bacda | ||
|
|
9095d11f41 | ||
|
|
60a7f1b996 | ||
|
|
066f4f8049 | ||
|
|
74b625b287 | ||
|
|
6c84ab14b7 | ||
|
|
301603ed68 | ||
|
|
8faa5b9cc5 | ||
|
|
42bc95786b | ||
|
|
01a6d34c97 | ||
|
|
4f6910c806 | ||
|
|
835c57faaa | ||
|
|
81fc637047 | ||
|
|
a002bbbdb0 | ||
|
|
ae51634be4 | ||
|
|
4254d123bf | ||
|
|
8ec28be2b6 | ||
|
|
d0dae7dfe2 | ||
|
|
28ba7d73ab | ||
|
|
0ef3f7284f | ||
|
|
4035423590 | ||
|
|
16c510c79f | ||
|
|
f39bc5c36e | ||
|
|
fcc30e3314 | ||
|
|
807d368df4 | ||
|
|
9fe58dee87 | ||
|
|
d580bad0eb | ||
|
|
875e0fdceb | ||
|
|
d79dfcc509 | ||
|
|
57862163f1 | ||
|
|
de63163e77 |
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ZioPao
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Logs**
|
||||||
|
Please upload your game logs too. Server logs are useful too.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
33
.github/workflows/build_mod.yml
vendored
@@ -1,33 +0,0 @@
|
|||||||
name: Build Mod
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
mod_name:
|
|
||||||
description: 'Mod name'
|
|
||||||
default: 'TheOnlyCure'
|
|
||||||
required: true
|
|
||||||
version:
|
|
||||||
description: 'Version'
|
|
||||||
default: '1.0'
|
|
||||||
required: true
|
|
||||||
jobs:
|
|
||||||
main_job:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: mkdir -p root/${{ inputs.mod_name }}/Contents/mods/${{ inputs.mod_name }}
|
|
||||||
- run: cp workshop.txt root/${{ inputs.mod_name }}/workshop.txt
|
|
||||||
- run: cp preview.png root/${{ inputs.mod_name}}/preview.png
|
|
||||||
- run: cp mod.info root/${{ inputs.mod_name }}/Contents/mods/${{ inputs.mod_name }}/mod.info
|
|
||||||
- run: cp icon.png root/${{ inputs.mod_name }}/Contents/mods/${{ inputs.mod_name }}/icon.png
|
|
||||||
- run: cp generic.png root/${{ inputs.mod_name }}/Contents/mods/${{ inputs.mod_name }}/generic.png
|
|
||||||
- run: cp -r media root/${{ inputs.mod_name }}/Contents/mods/${{ inputs.mod_name }}/media
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.mod_name }}-${{ inputs.version }}
|
|
||||||
path: |
|
|
||||||
root
|
|
||||||
root/${{ inputs.mod_name }}
|
|
||||||
root/${{ inputs.mod_name }}/Contents/
|
|
||||||
root/${{ inputs.mod_name }}/Contents/mods
|
|
||||||
root/${{ inputs.mod_name }}/Contents/mods/${{ inputs.mod_name }}/*
|
|
||||||
1
.gitignore
vendored
@@ -0,0 +1 @@
|
|||||||
|
.vscode
|
||||||
3
.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
11
.idea/The-Only-Cure-But-Better.iml
generated
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="zdoc-lua" level="project" />
|
|
||||||
<orderEntry type="library" name="zomboid-sources" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
7
.idea/discord.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DiscordProjectSettings">
|
|
||||||
<option name="show" value="PROJECT" />
|
|
||||||
<option name="description" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
9
.idea/libraries/zdoc_lua.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="zdoc-lua">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$USER_HOME$/IdeaProjects/decompilation-zomboid/lib/zdoc-lua.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
11
.idea/libraries/zomboid_sources.xml
generated
@@ -1,11 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="zomboid-sources">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$USER_HOME$/IdeaProjects/decompilation-zomboid/lib/zomboid.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$USER_HOME$/IdeaProjects/decompilation-zomboid/lib/zomboid-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
6
.idea/misc.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" project-jdk-name="Python 3.11" project-jdk-type="Python SDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/The-Only-Cure-But-Better.iml" filepath="$PROJECT_DIR$/.idea/The-Only-Cure-But-Better.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
17
.idea/runConfigurations/Run_Zomboid.xml
generated
@@ -1,17 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Run Zomboid" type="ShConfigurationType">
|
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="false" />
|
|
||||||
<option name="SCRIPT_PATH" value="E:/Steam/steamapps/common/ProjectZomboid/ProjectZomboid64 - nosteam-debug.bat" />
|
|
||||||
<option name="SCRIPT_OPTIONS" value="" />
|
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
|
||||||
<option name="INTERPRETER_PATH" value="" />
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
|
||||||
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
|
||||||
<envs />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
70
.vscode/settings.json
vendored
@@ -1,64 +1,16 @@
|
|||||||
{
|
{
|
||||||
"todo-tree.tree.scanMode": "workspace",
|
"todo-tree.tree.scanMode": "workspace",
|
||||||
|
"mod_id": "3236152598",
|
||||||
|
"zomboid_user_folder": "C:/Users/picch/Zomboid",
|
||||||
|
"zomboid_folder": "E:\\Steam\\steamapps\\common\\ProjectZomboid",
|
||||||
|
"zomboid_server_folder": "E:\\Steam\\steamapps\\common\\Project Zomboid Dedicated Server",
|
||||||
"Lua.diagnostics.globals": [
|
"Lua.diagnostics.globals": [
|
||||||
"ZombRand",
|
|
||||||
"getPlayer",
|
|
||||||
"BodyPartType",
|
|
||||||
"ProceduralDistributions",
|
|
||||||
"Events",
|
|
||||||
"getText",
|
|
||||||
"Perks",
|
|
||||||
"getPlayerByOnlineID",
|
|
||||||
"getTexture",
|
|
||||||
"ISTimedActionQueue",
|
|
||||||
"sendClientCommand",
|
|
||||||
"ISBaseTimedAction",
|
|
||||||
"instanceof",
|
|
||||||
"getPlayerInventory",
|
|
||||||
"sendServerCommand",
|
|
||||||
"TraitFactory",
|
|
||||||
"ISWorldObjectContextMenu",
|
|
||||||
"getCell",
|
|
||||||
"getSpecificPlayer",
|
|
||||||
"_",
|
|
||||||
"NewUI",
|
|
||||||
"getTextManager",
|
|
||||||
"isClient",
|
|
||||||
"ISHealthPanel",
|
|
||||||
"ModOptions",
|
"ModOptions",
|
||||||
"ISNewHealthPanel",
|
"zombie",
|
||||||
"ISButton",
|
"_"
|
||||||
"getCore",
|
],
|
||||||
"ProfessionFactory",
|
"Lua.format.defaultConfig": {
|
||||||
"BaseGameCharacterDetails",
|
"indent_style": "space",
|
||||||
"MoodleType",
|
"indent_size": "2"
|
||||||
"ISEquipWeaponAction",
|
}
|
||||||
"triggerEvent",
|
|
||||||
"forceDropHeavyItems",
|
|
||||||
"getPlayerHotbar",
|
|
||||||
"isServer",
|
|
||||||
"BodyLocations",
|
|
||||||
"ISUnequipAction",
|
|
||||||
"ISInventoryPaneContextMenu",
|
|
||||||
"ISDropItemAction",
|
|
||||||
"BloodBodyPartType",
|
|
||||||
"ISInventoryPane",
|
|
||||||
"ModData",
|
|
||||||
"isDebugEnabled",
|
|
||||||
"getActivatedMods",
|
|
||||||
"ISHotbar",
|
|
||||||
"isForceDropHeavyItem",
|
|
||||||
"isFHModKeyDown",
|
|
||||||
"getPlayerData",
|
|
||||||
"FHSwapHandsAction",
|
|
||||||
"getClassFieldVal",
|
|
||||||
"SandboxVars",
|
|
||||||
"getClassField",
|
|
||||||
"ISWearClothing",
|
|
||||||
"SyncXp",
|
|
||||||
"ISClothingExtraAction",
|
|
||||||
"SwapItConfig",
|
|
||||||
"getTimestamp",
|
|
||||||
"addSound"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
55
.vscode/tasks.json
vendored
@@ -3,29 +3,74 @@
|
|||||||
// for the documentation about the tasks.json format
|
// for the documentation about the tasks.json format
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Create Workshop folder",
|
||||||
|
"type": "shell",
|
||||||
|
"options": {"statusbar": {"label": "$(combine) Assemble Mod"}},
|
||||||
|
"command": "python ${config:zomboid_user_folder}/PaosCrap/make_workshop_pack.py picch ${workspaceFolderBasename}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Bump Mod Version",
|
||||||
|
"type": "shell",
|
||||||
|
"options": {"statusbar": {"label": "$(arrow-up) Bump Mod Version"}},
|
||||||
|
"command": "python ${config:zomboid_user_folder}/PaosCrap/bump_version.py media/lua/client/TOC/Main.lua",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Run Zomboid Debug No Steam",
|
"label": "Run Zomboid Debug No Steam",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "\"E:\\Steam\\steamapps\\common\\ProjectZomboid\\ProjectZomboid64 - nosteam-debug.bat\"",
|
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"group": "groupZomboid"
|
"group": "groupZomboid"
|
||||||
},
|
},
|
||||||
|
"command": "\"${config:zomboid_folder}\\ProjectZomboid64 - nosteam-debug.bat\"",
|
||||||
|
"options": {"statusbar": {"label": "$(run) Zomboid client"}},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$eslint-stylish"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Zomboid Debug No Steam 2",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "\"${config:zomboid_folder}\\ProjectZomboid64 - nosteam-debug.bat\"",
|
||||||
|
"options": {"statusbar": {"hide": true}},
|
||||||
|
|
||||||
"problemMatcher": [
|
"problemMatcher": [
|
||||||
"$eslint-stylish"
|
"$eslint-stylish"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Run two instances of Zomboid Debug No Steam",
|
"label": "Run two instances of Zomboid Debug No Steam",
|
||||||
|
"options": {"statusbar": {"label": "$(run-all) Two Zomboid Clients"}},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "new"
|
||||||
|
},
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"Run Zomboid Debug No Steam",
|
"Run Zomboid Debug No Steam", "Run Zomboid Debug No Steam 2"],
|
||||||
"Run Zomboid Debug No Steam"
|
|
||||||
],
|
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Run Zomboid Test Server",
|
"label": "Run Zomboid Test Server",
|
||||||
|
"options": {"statusbar": {"label": "$(run) Zomboid Server (TOC)"}},
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "\"E:\\Steam\\steamapps\\common\\Project Zomboid Dedicated Server\\StartServer64_nosteam.bat\"",
|
"command":"\"${config:zomboid_server_folder}\\StartServer64_nosteam_custom.bat\" TOC",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$eslint-stylish"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Zomboid Test Server 2",
|
||||||
|
"options": {"statusbar": {"label": "$(run) Zomboid Server (TOC+FH+BH)"}},
|
||||||
|
"type": "shell",
|
||||||
|
"command":"\"${config:zomboid_server_folder}\\StartServer64_nosteam_custom.bat\" TOC_FH_BH",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$eslint-stylish"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Zomboid Test Server 3",
|
||||||
|
"options": {"statusbar": {"label": "$(run) Zomboid Server (TOC+FH+BH+iMedsFixed)"}},
|
||||||
|
"type": "shell",
|
||||||
|
"command":"\"${config:zomboid_server_folder}\\StartServer64_nosteam_custom.bat\" TOC_FH_BH_imeds",
|
||||||
"problemMatcher": [
|
"problemMatcher": [
|
||||||
"$eslint-stylish"
|
"$eslint-stylish"
|
||||||
]
|
]
|
||||||
|
|||||||
674
LICENSE
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
65
README.md
@@ -1,4 +1,61 @@
|
|||||||
# Dev Version
|
<p align='center'>
|
||||||
Version: 1.0
|
<img src="/dev_stuff/logos/title.png" width=50% height=50%>
|
||||||
Workshop ID: 2915572347
|
</p>
|
||||||
Mod ID: Amputation2
|
|
||||||
|
<p align='center'>
|
||||||
|
<a href='https://steamcommunity.com/sharedfiles/filedetails/?id=3236152598'>
|
||||||
|
<img src='https://img.shields.io/badge/Steam-000000?style=for-the-badge&logo=steam&logoColor=white' />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
You're bitten. You have two choices.
|
||||||
|
Wait until you succumb to the virus or take matters into your hands. Cut off that infected part and live to die another day.
|
||||||
|
|
||||||
|
This version of **The Only Cure** has been rebuilt from scratch to support future additions and to feel as close as possible as a vanilla mechanic.
|
||||||
|
|
||||||
|
Supports **Single Player** and **Multiplayer**!
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
Use it with the following mods for the intended experience:
|
||||||
|
- [Fancy Handwork](https://steamcommunity.com/sharedfiles/filedetails/?id=2904920097)
|
||||||
|
- [Brutal Handwork](https://steamcommunity.com/sharedfiles/filedetails/?id=2934621024)
|
||||||
|
|
||||||
|
|
||||||
|
# Quick guide
|
||||||
|
|
||||||
|
## Amputation
|
||||||
|
Get a _Saw_ or a _Garden Saw_, right click on it, and choose which limb to amputate. You can also drag n' drop your Saw item directly into the afflicted area to start cutting it off.
|
||||||
|
|
||||||
|
If you have some _bandages_ and\or _stitches_ in your inventory you will automatically use them, multiplying the chances of your survival.
|
||||||
|
If you have a _tourniquet_, place it on the correct side to dampen the amount of damage you will take after you're done amputating the limb.
|
||||||
|
|
||||||
|
Keep in mind that if you amputate your **upper arm**, you won't be able to equip any prosthesis.
|
||||||
|
|
||||||
|
After you've amputated a limb, you will gain skill points for the amputated side, making timed actions faster in due time.
|
||||||
|
|
||||||
|
## Cicatrization
|
||||||
|
You can check the cicatrization status of an amputated limb from your **Health Panel**.
|
||||||
|
From time to time, you should clean your wounds with a bandage to help the cicatrization process.
|
||||||
|
If your limb isn't completely cicatrized, you can still equip prosthetic limbs, but that can trigger random bleedings from that area.
|
||||||
|
|
||||||
|
## Prosthesis
|
||||||
|
If you're missing a hand, you won't be able to do a lot of things, such as equipping two-handed weapons. With prosthetics limbs, you can fix that.
|
||||||
|
There are two prosthesis type that can be crafted\found.
|
||||||
|
- Hook Prosthesis
|
||||||
|
- Arm Prosthesis
|
||||||
|
|
||||||
|
The main difference between the twos is that your actions will take longer with the Hook Prosthesis.
|
||||||
|
|
||||||
|
When you equip a prosthetic limb, you will slowly gain familiarity with it, making actions more speedy in due time.
|
||||||
|
|
||||||
|
## Admin tools
|
||||||
|
If something strange happened, an admin can reset TOC mechanics on any player by right clicking on them and select _"Reset Amputations"_. They could also do the opposite by clicking on _"Force Amputation"_ for each amputable limb.
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
| | |
|
||||||
|
| ------------- | ------------- |
|
||||||
|
| Pao | Developer |
|
||||||
|
| Mr. Bounty | Original developer |
|
||||||
|
| Chuckleberry Finn | Logo and Icon |
|
||||||
|
| dhert | Compatibility API |
|
||||||
|
| The Zomboid community as a whole | A lot of little things |
|
||||||
|
|
||||||
|
|||||||
8
The-Only-Cure.code-workspace
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
0.9.15
|
|
||||||
- Hotfix to sound not stopping when performing an amputation on another player
|
|
||||||
|
|
||||||
0.9.14
|
|
||||||
- Optimizations
|
|
||||||
- New icon for the mod
|
|
||||||
- Added a dirtyness malus for cicatrization, you'll have to keep your wound clean while it's healing (wash it you animal)
|
|
||||||
- When trying to equip a prosthesis from the inventory you'll get a message to let you know that you're doing it wrong
|
|
||||||
- Added explicit support to Left Is Right, making it work a lot better when you've got an amputated right limb
|
|
||||||
|
|
||||||
|
|
||||||
0.9.13
|
|
||||||
- Some little optimizations
|
|
||||||
- Fixed a bug that made Fancy Handwork compat not work as intended
|
|
||||||
|
|
||||||
0.9.12
|
|
||||||
- Fixed traits icons
|
|
||||||
- Some cleaning to the code
|
|
||||||
|
|
||||||
0.9.11
|
|
||||||
- Hotfix to cicatrization visuals
|
|
||||||
|
|
||||||
0.9.10
|
|
||||||
- Modified textures once again
|
|
||||||
|
|
||||||
|
|
||||||
0.9.9
|
|
||||||
- Modified textures for amputations
|
|
||||||
- Fixed a bug that caused some problems when amputating an already amputated limb
|
|
||||||
|
|
||||||
0.9.8
|
|
||||||
- New textures for amputations
|
|
||||||
- When cicatrized, an amputation will not be bloody anymore (visual thing only)
|
|
||||||
|
|
||||||
0.9.7
|
|
||||||
- Now amputations should spawn in every case, damn hairs. Thanks Dev for the tip!
|
|
||||||
|
|
||||||
|
|
||||||
0.9.6
|
|
||||||
- Fixed a bug when handling zombie hitting amputated limbs
|
|
||||||
- Fixed sound looping incessantly after amputating a limb
|
|
||||||
- Changed how phantom pain occurs
|
|
||||||
- Fixes to new hook models
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
0.9.5
|
|
||||||
- No more Right Click menu. You'll have to use the TOC Menu from the Medical Check, except for Cheats
|
|
||||||
- Fixes to how amputations are handled
|
|
||||||
before and after
|
|
||||||
- Compatibility fixes with older versions
|
|
||||||
- Various fixes to Traits
|
|
||||||
- New heavily WIP models for metal and wooden hooks
|
|
||||||
- Readded sounds during amputations
|
|
||||||
- Fixed banages not getting applied after an amputation when they were in the player's inventory
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
1) Can cut every limb in SP
|
|
||||||
2) Does cutting a limb cure infection
|
|
||||||
3) If I get bit in the hand, will cutting the forearm cure the infection?
|
|
||||||
4) Both forearm bit, cut everyone, infection cured?
|
|
||||||
5) Can I operate myself?
|
|
||||||
6) Can I equip a prost?
|
|
||||||
7) Can i unequip a prost?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MP TEST
|
|
||||||
1) Everything up there but in mp env
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------
|
|
||||||
- traits are kinda broken, cant reset them
|
|
||||||
124
dev_stuff/Untitled Diagram.drawio
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<mxfile host="app.diagrams.net" modified="2023-11-06T08:39:21.951Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0" version="22.0.8" etag="ddG-F5xvL5OceRP-7Ajf" type="github">
|
||||||
|
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
||||||
|
<mxGraphModel dx="1223" dy="871" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||||
|
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--0" value="Person" style="swimlane;fontStyle=2;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||||
|
<mxGeometry x="220" y="120" width="160" height="138" as="geometry">
|
||||||
|
<mxRectangle x="230" y="140" width="160" height="26" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--1" value="Name" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||||
|
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--2" value="Phone Number" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||||
|
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--3" value="Email Address" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||||
|
<mxGeometry y="78" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--4" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||||
|
<mxGeometry y="104" width="160" height="8" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--5" value="Purchase Parking Pass" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||||
|
<mxGeometry y="112" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--6" value="Student" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||||
|
<mxGeometry x="120" y="360" width="160" height="138" as="geometry">
|
||||||
|
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--7" value="Student Number" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
|
||||||
|
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--8" value="Average Mark" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
|
||||||
|
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--9" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
|
||||||
|
<mxGeometry y="78" width="160" height="8" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--10" value="Is Eligible To Enroll" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontStyle=4" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
|
||||||
|
<mxGeometry y="86" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--11" value="Get Seminars Taken" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
|
||||||
|
<mxGeometry y="112" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--12" value="" style="endArrow=block;endSize=10;endFill=0;shadow=0;strokeWidth=1;rounded=0;edgeStyle=elbowEdgeStyle;elbow=vertical;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="zkfFHV4jXpPFQw0GAbJ--0" edge="1">
|
||||||
|
<mxGeometry width="160" relative="1" as="geometry">
|
||||||
|
<mxPoint x="200" y="203" as="sourcePoint" />
|
||||||
|
<mxPoint x="200" y="203" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--13" value="Professor" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||||
|
<mxGeometry x="330" y="360" width="160" height="70" as="geometry">
|
||||||
|
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--14" value="Salary" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--13" vertex="1">
|
||||||
|
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--15" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--13" vertex="1">
|
||||||
|
<mxGeometry y="52" width="160" height="8" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--16" value="" style="endArrow=block;endSize=10;endFill=0;shadow=0;strokeWidth=1;rounded=0;edgeStyle=elbowEdgeStyle;elbow=vertical;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--13" target="zkfFHV4jXpPFQw0GAbJ--0" edge="1">
|
||||||
|
<mxGeometry width="160" relative="1" as="geometry">
|
||||||
|
<mxPoint x="210" y="373" as="sourcePoint" />
|
||||||
|
<mxPoint x="310" y="271" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--17" value="Address" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||||
|
<mxGeometry x="508" y="120" width="160" height="216" as="geometry">
|
||||||
|
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--18" value="Street" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--19" value="City" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--20" value="State" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="78" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--21" value="Postal Code" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="104" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--22" value="Country" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="130" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--23" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="156" width="160" height="8" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--24" value="Validate" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="164" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--25" value="Output As Label" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||||
|
<mxGeometry y="190" width="160" height="26" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--26" value="" style="endArrow=open;shadow=0;strokeWidth=1;rounded=0;endFill=1;edgeStyle=elbowEdgeStyle;elbow=vertical;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--0" target="zkfFHV4jXpPFQw0GAbJ--17" edge="1">
|
||||||
|
<mxGeometry x="0.5" y="41" relative="1" as="geometry">
|
||||||
|
<mxPoint x="380" y="192" as="sourcePoint" />
|
||||||
|
<mxPoint x="540" y="192" as="targetPoint" />
|
||||||
|
<mxPoint x="-40" y="32" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--27" value="0..1" style="resizable=0;align=left;verticalAlign=bottom;labelBackgroundColor=none;fontSize=12;" parent="zkfFHV4jXpPFQw0GAbJ--26" connectable="0" vertex="1">
|
||||||
|
<mxGeometry x="-1" relative="1" as="geometry">
|
||||||
|
<mxPoint y="4" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--28" value="1" style="resizable=0;align=right;verticalAlign=bottom;labelBackgroundColor=none;fontSize=12;" parent="zkfFHV4jXpPFQw0GAbJ--26" connectable="0" vertex="1">
|
||||||
|
<mxGeometry x="1" relative="1" as="geometry">
|
||||||
|
<mxPoint x="-7" y="4" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="zkfFHV4jXpPFQw0GAbJ--29" value="lives at" style="text;html=1;resizable=0;points=[];;align=center;verticalAlign=middle;labelBackgroundColor=none;rounded=0;shadow=0;strokeWidth=1;fontSize=12;" parent="zkfFHV4jXpPFQw0GAbJ--26" vertex="1" connectable="0">
|
||||||
|
<mxGeometry x="0.5" y="49" relative="1" as="geometry">
|
||||||
|
<mxPoint x="-38" y="40" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
BIN
dev_stuff/black_white_from_blood.blw
Normal file
32
dev_stuff/ci/bump_minor_version.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Open the Main.lua file in read mode
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# Check if the current line contains _version
|
||||||
|
if [[ $line == *_version* ]]; then
|
||||||
|
# Get the current version number from the line
|
||||||
|
current_version=$(echo $line | cut -d '"' -f 2)
|
||||||
|
|
||||||
|
# Increment the version number by 1
|
||||||
|
new_version=$((current_version + 1))
|
||||||
|
|
||||||
|
# Replace the old version number with the new one in the file
|
||||||
|
echo "$line" | sed "s/$current_version/$new_version/g" > media/lua/client/Main.lua
|
||||||
|
fi
|
||||||
|
done < media/lua/client/Main.lua
|
||||||
|
|
||||||
|
|
||||||
|
# Open the mod.info file in read mode
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# Check if the current line contains modversion
|
||||||
|
if [[ $line == *modversion* ]]; then
|
||||||
|
# Get the current version number from the line
|
||||||
|
current_version=$(echo $line | cut -d '"' -f 2)
|
||||||
|
|
||||||
|
# Increment the version number by 1
|
||||||
|
new_version=$((current_version + 1))
|
||||||
|
|
||||||
|
# Replace the old version number with the new one in the file
|
||||||
|
echo "$line" | sed "s/$current_version/$new_version/g" > mod.info
|
||||||
|
fi
|
||||||
|
done < mod.info
|
||||||
BIN
dev_stuff/healthPanelHide.psd
Normal file
BIN
dev_stuff/healthPanelHideMale.psd
Normal file
BIN
dev_stuff/healthpanelPatternTest.psd
Normal file
BIN
dev_stuff/logos/TOC_LOGOv2 by Chuck.psd
Normal file
BIN
dev_stuff/logos/TOC_LOGOv2_ByChuck_169.png
Normal file
|
After Width: | Height: | Size: 534 KiB |
BIN
dev_stuff/logos/TOC_LOGOv2_ByChuck_169.psd
Normal file
BIN
dev_stuff/logos/TOC_LOGOv2_ByChuck_169_with_title.png
Normal file
|
After Width: | Height: | Size: 540 KiB |
BIN
dev_stuff/logos/test.png
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
dev_stuff/logos/title.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
dev_stuff/logos/workshop_img.psd
Normal file
54
dev_stuff/old_workshop_page.txt
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
https://steamcommunity.com/sharedfiles/filedetails/?id=3236152598
|
||||||
|
|
||||||
|
|
||||||
|
[img]https://i.imgur.com/PctsskC.png[/img]
|
||||||
|
|
||||||
|
[h1]Supports B41+. Compatible with SP and MP[/h1]
|
||||||
|
[h2]Made by [b]Mr. Bounty[/b] and maintained by [b]Pao[/b][/h2]
|
||||||
|
[img]https://i.imgur.com/RNxXaZ8.gif[/img]
|
||||||
|
|
||||||
|
|
||||||
|
[img]https://i.imgur.com/C6FcUgm.png[/img]
|
||||||
|
[h1] An update will come "soon". The work in progress version is available on GitHub [url=https://github.com/ZioPao/The-Only-Cure]here[/url].[/h1]
|
||||||
|
|
||||||
|
|
||||||
|
[img]https://i.imgur.com/koMbiql.png[/img]
|
||||||
|
[list]
|
||||||
|
[*]Amputate different parts of your arm to prevent an infection
|
||||||
|
[*]Cicatrization process and surgery after amputation
|
||||||
|
[*]Prosthesis for cut limbs up to the forearm
|
||||||
|
[*]Debug cheats (Multiplayer compatible)
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
|
||||||
|
[img]https://i.imgur.com/BOj0YGn.png[/img]
|
||||||
|
You can find a concise tutorial about the mod [url=https://github.com/ZioPao/The-Only-Cure/wiki]here[/url]. The wiki will be updated whenever we add some new feature that needs to be explained.
|
||||||
|
|
||||||
|
|
||||||
|
[img]https://i.imgur.com/RGF3ZTF.png[/img]
|
||||||
|
[h2]Required mods[/h2]
|
||||||
|
[list]
|
||||||
|
[*][url=https://steamcommunity.com/workshop/filedetails/?id=2760035814]Simple UI library[/url]
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2]Recommended mods[/h2]
|
||||||
|
[list]
|
||||||
|
[*][url=https://steamcommunity.com/sharedfiles/filedetails/?id=2904920097]Fancy Handwork[/url]
|
||||||
|
[*][url=https://steamcommunity.com/sharedfiles/filedetails/?id=2934621024]Brutal Handwork[/url]
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2]Compatible mods[/h2]
|
||||||
|
[list]
|
||||||
|
[*][url=https://steamcommunity.com/sharedfiles/filedetails/?id=2366717227]Swap It[/url]
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2]Incompatible mods[/h2]
|
||||||
|
[list]
|
||||||
|
[*][url=https://steamcommunity.com/workshop/filedetails/?id=2629286881]Military Ponchos[/url] (Amputation sometimes won't show)
|
||||||
|
[*][url=https://steamcommunity.com/sharedfiles/filedetails/?id=2915572347]zRe Bandaged Status[/url] (TOC button in the health panel menu won't shown)
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[hr]
|
||||||
|
|
||||||
|
Workshop ID: 2703664356
|
||||||
|
Mod ID: Amputation
|
||||||
@@ -5,6 +5,11 @@ import openpyxl
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### ITEMS FORMAT SHOULD BE
|
||||||
|
|
||||||
|
# Prost_Something_HookArm_L
|
||||||
|
|
||||||
os.chdir(os.getcwd() + "\\dev_stuff\\python_helpers\\")
|
os.chdir(os.getcwd() + "\\dev_stuff\\python_helpers\\")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,3 +97,102 @@ item LeatherBase_MetalHand
|
|||||||
CanHaveHoles = false,
|
CanHaveHoles = false,
|
||||||
WorldStaticModel = TOC.MetalHook,
|
WorldStaticModel = TOC.MetalHook,
|
||||||
}
|
}
|
||||||
|
item WoodenBase_WoodenHook
|
||||||
|
{
|
||||||
|
Weight = 0.90,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Wooden Base and Wooden Hook,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item WoodenBase_MetalHook
|
||||||
|
{
|
||||||
|
Weight = 1.20,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Wooden Base and Metal Hook,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item WoodenBase_MetalHand
|
||||||
|
{
|
||||||
|
Weight = 1.40,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Wooden Base and Metal Hand,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item MetalBase_WoodenHook
|
||||||
|
{
|
||||||
|
Weight = 1.40,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Metal Base and Wooden Hook,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item MetalBase_MetalHook
|
||||||
|
{
|
||||||
|
Weight = 1.70,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Metal Base and Metal Hook,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item MetalBase_MetalHand
|
||||||
|
{
|
||||||
|
Weight = 1.90,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Metal Base and Metal Hand,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item LeatherBase_WoodenHook
|
||||||
|
{
|
||||||
|
Weight = 1.20,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Leather Base and Wooden Hook,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item LeatherBase_MetalHook
|
||||||
|
{
|
||||||
|
Weight = 1.50,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Leather Base and Metal Hook,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
item LeatherBase_MetalHand
|
||||||
|
{
|
||||||
|
Weight = 1.70,
|
||||||
|
Type = Normal,
|
||||||
|
DisplayCategory = Prosthesis,
|
||||||
|
DisplayName = Prosthesis - Leather Base and Metal Hand,
|
||||||
|
Icon = metalLeg,
|
||||||
|
Tooltip = TempTooltip,
|
||||||
|
CanHaveHoles = false,
|
||||||
|
WorldStaticModel = TOC.MetalHook,
|
||||||
|
}
|
||||||
|
|||||||
90
dev_stuff/steam_desc.txt
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
[img]https://raw.githubusercontent.com/ZioPao/The-Only-Cure/551125bb50cb65608ad89ca81ef0daccb3b02c4c/dev_stuff/logos/title.png[/img]
|
||||||
|
|
||||||
|
|
||||||
|
[h1]You're bitten. You have two choices.[/h1]
|
||||||
|
Wait until you succumb to the virus or take matters into your hands. Cut off that infected part and live to die another day.
|
||||||
|
|
||||||
|
This version of [b]The Only Cure[/b] has been rebuilt from scratch to support future additions and to feel as close as possible as a vanilla mechanic.
|
||||||
|
|
||||||
|
[b]If you're using an older version of The Only Cure and want to switch with this, you're gonna need to create a new character\save to prevent issues.[/b]
|
||||||
|
[b]The older version will be delisted shortly and it will not be supported anymore.[/b]
|
||||||
|
[h1]Supports [b]Single Player[/b] and [b]Multiplayer[/b]. Host Mode is currently [b]UNSUPPORTED![/b][/h1]
|
||||||
|
|
||||||
|
[h1]Setup[/h1]
|
||||||
|
Use it with the following mods for the intended experience:
|
||||||
|
[list]
|
||||||
|
[*] [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2904920097]Fancy Handwork[/url]
|
||||||
|
[*] [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2934621024]Brutal Handwork[/url]
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
Place them [b]BEFORE[/b] The Only Cure in your mod list!
|
||||||
|
|
||||||
|
[hr][/hr]
|
||||||
|
|
||||||
|
[h1]Quick guide[/h1]
|
||||||
|
[h2]Amputation[/h2]
|
||||||
|
Get a [i]Saw[/i] or a [i]Garden Saw[/i], right click on it, and choose which limb to amputate. You can also drag n' drop your Saw item directly into the afflicted area to start cutting it off.
|
||||||
|
|
||||||
|
If you have some [i]bandages[/i] and\or [i]stitches[/i] in your inventory you will automatically use them, multiplying the chances of your survival.
|
||||||
|
If you have a [i]tourniquet[/i], place it on the correct side to dampen the amount of damage you will take after you're done amputating the limb.
|
||||||
|
|
||||||
|
Keep in mind that if you amputate your [b]upper arm[/b], you won't be able to equip any prosthesis.
|
||||||
|
|
||||||
|
After you've amputated a limb, you will gain [b]skill points[/b] for the amputated side, making timed actions faster in due time.
|
||||||
|
|
||||||
|
[h2]Cicatrization[/h2]
|
||||||
|
You can check the cicatrization status of an amputated limb from your [b]Health Panel[/b]
|
||||||
|
From time to time, you should clean your wounds with a bandage to help the cicatrization process.
|
||||||
|
If your limb isn't completely cicatrized, you can still equip prosthetic limbs, but that can trigger random bleedings from that area.
|
||||||
|
|
||||||
|
[h2]Prosthetics[/h2]
|
||||||
|
If you're missing a hand, you won't be able to do a lot of things, such as equipping two-handed weapons. With prosthetics limbs, you can fix that.
|
||||||
|
There are two prosthesis type that can be crafted\found in medical areas:
|
||||||
|
[list]
|
||||||
|
[*] Hook Prosthesis
|
||||||
|
[*] Arm Prosthesis
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
The main difference between the twos is that your actions will take longer with the Hook Prosthesis.
|
||||||
|
When you equip a prosthetic limb, you will slowly gain skill points in the [b]Prosthesis Familiarity[/b] perk, making actions more speedy in due time.
|
||||||
|
|
||||||
|
[h2]Admin tools[/h2]
|
||||||
|
If something strange happened, an admin can reset TOC mechanics on any player by right clicking on them and select [i]"Reset Amputations"[/i]. They could also do the opposite by clicking on [i]"Force Amputation"[/i] for each amputable limb.
|
||||||
|
|
||||||
|
[hr][/hr]
|
||||||
|
|
||||||
|
[h1]Issues and bugs?[/h1]
|
||||||
|
Got any issues or found some pesky bugs? Report them on GitHub!
|
||||||
|
|
||||||
|
[url=https://github.com/ZioPao/The-Only-Cure][img]https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white[/img][/url]
|
||||||
|
|
||||||
|
[h1]Credits[/h1]
|
||||||
|
[table]
|
||||||
|
[tr]
|
||||||
|
[th]Pao[/th]
|
||||||
|
[th]Developer[/th]
|
||||||
|
[/tr]
|
||||||
|
[tr]
|
||||||
|
[th]Mr. Bounty[/th]
|
||||||
|
[th]Original Developer[/th]
|
||||||
|
[/tr]
|
||||||
|
[tr]
|
||||||
|
[th]Chuckleberry Finn[/th]
|
||||||
|
[th]Logo and Icon[/th]
|
||||||
|
[/tr]
|
||||||
|
[tr]
|
||||||
|
[th]dhert[/th]
|
||||||
|
[th]Compatibility API[/th]
|
||||||
|
[/tr]
|
||||||
|
[tr]
|
||||||
|
[th]JCloudJalix[/th]
|
||||||
|
[th]German translation[/th]
|
||||||
|
[/tr]
|
||||||
|
[/table]
|
||||||
|
|
||||||
|
[hr][/hr]
|
||||||
|
|
||||||
|
[h1]Want to support me?[/h1]
|
||||||
|
[url=https://ko-fi.com/M4M7IERNW][img]https://storage.ko-fi.com/cdn/kofi3.png[/img][/url]
|
||||||
|
|
||||||
|
[hr][/hr]
|
||||||
BIN
generic.png
|
Before Width: | Height: | Size: 91 KiB |
BIN
icon.png
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 5.2 KiB |
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode>
|
|
||||||
<m_Name>aim_default</m_Name>
|
|
||||||
<m_AnimName>Bob_Sit_FishingIdle</m_AnimName>
|
|
||||||
<m_Priority>4</m_Priority>
|
|
||||||
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
|
|
||||||
<m_SyncTrackingEnabled>false</m_SyncTrackingEnabled>
|
|
||||||
<m_SpeedScale>IdleSpeed</m_SpeedScale>
|
|
||||||
<m_BlendTime>0.30</m_BlendTime>
|
|
||||||
<m_maxTorsoTwist>70.0</m_maxTorsoTwist>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Transitions>
|
|
||||||
<m_Target>Idle</m_Target>
|
|
||||||
<m_AnimName>Bob_Sit_FishingIdle</m_AnimName>
|
|
||||||
<m_blendInTime>0.3</m_blendInTime>
|
|
||||||
<m_blendOutTime>0.3</m_blendOutTime>
|
|
||||||
<m_speedScale>1.2</m_speedScale>
|
|
||||||
</m_Transitions>
|
|
||||||
<m_Transitions>
|
|
||||||
<m_Target>sneakIdle</m_Target>
|
|
||||||
<m_AnimName>Bob_Sit_FishingIdle</m_AnimName>
|
|
||||||
<m_blendInTime>0.3</m_blendInTime>
|
|
||||||
<m_blendOutTime>0.3</m_blendOutTime>
|
|
||||||
<m_speedScale>1.2</m_speedScale>
|
|
||||||
</m_Transitions>
|
|
||||||
<m_Transitions>
|
|
||||||
<m_Target>sneakIdleLow</m_Target>
|
|
||||||
<m_AnimName>Bob_Sit_FishingIdle</m_AnimName>
|
|
||||||
<m_blendInTime>0.3</m_blendInTime>
|
|
||||||
<m_blendOutTime>0.3</m_blendOutTime>
|
|
||||||
<m_speedScale>1.2</m_speedScale>
|
|
||||||
</m_Transitions>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode>
|
|
||||||
<m_Name>NoLegs_Idle</m_Name>
|
|
||||||
<m_AnimName>Bob_Sit_FishingIdle</m_AnimName>
|
|
||||||
<m_DeferredBoneName>Translation_Data</m_DeferredBoneName>
|
|
||||||
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
|
|
||||||
<m_Looped>true</m_Looped>
|
|
||||||
<m_SpeedScale>0.8</m_SpeedScale>
|
|
||||||
<m_BlendTime>0.20</m_BlendTime>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Transitions>
|
|
||||||
<m_Target>NoLegs_IdleSneak</m_Target>
|
|
||||||
<m_blendInTime>0.1</m_blendInTime>
|
|
||||||
</m_Transitions>
|
|
||||||
<m_Transitions>
|
|
||||||
<m_Target>NoLegs_Idle</m_Target>
|
|
||||||
<m_blendInTime>0.35</m_blendInTime>
|
|
||||||
<m_blendOutTime>0.35</m_blendOutTime>
|
|
||||||
</m_Transitions>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode>
|
|
||||||
<m_Name>NoLegs_IdleSneak</m_Name>
|
|
||||||
<m_AnimName>Bob_ScrambleFloorIdle</m_AnimName>
|
|
||||||
<m_Looped>true</m_Looped>
|
|
||||||
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
|
|
||||||
<m_SyncTrackingEnabled>false</m_SyncTrackingEnabled>
|
|
||||||
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
|
|
||||||
<m_SpeedScale>0.8</m_SpeedScale>
|
|
||||||
<m_BlendTime>0.20</m_BlendTime>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>sneaking</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode>
|
|
||||||
<m_Name>NoLegs_Walk</m_Name>
|
|
||||||
<m_AnimName>Bob_Crawl</m_AnimName>
|
|
||||||
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
|
|
||||||
<m_Looped>true</m_Looped>
|
|
||||||
<m_SpeedScale>1.5</m_SpeedScale>
|
|
||||||
<m_BlendTime>0.20</m_BlendTime>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Events>
|
|
||||||
<m_EventName>Footstep</m_EventName>
|
|
||||||
<m_TimePc>0.15</m_TimePc>
|
|
||||||
<m_ParameterValue>walk</m_ParameterValue>
|
|
||||||
</m_Events>
|
|
||||||
<m_Events>
|
|
||||||
<m_EventName>Footstep</m_EventName>
|
|
||||||
<m_TimePc>0.6</m_TimePc>
|
|
||||||
<m_ParameterValue>walk</m_ParameterValue>
|
|
||||||
</m_Events>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode>
|
|
||||||
<m_Name>NoLegs_WalkSneak</m_Name>
|
|
||||||
<m_AnimName>Zombie_CrawlUnder</m_AnimName>
|
|
||||||
<m_DeferredBoneName>Translation_Data</m_DeferredBoneName>
|
|
||||||
<m_Looped>true</m_Looped>
|
|
||||||
<m_SpeedScale>1.5</m_SpeedScale>
|
|
||||||
<m_BlendTime>0.20</m_BlendTime>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>sneaking</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>inTrees</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>false</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Events>
|
|
||||||
<m_EventName>Footstep</m_EventName>
|
|
||||||
<m_TimePc>0.15</m_TimePc>
|
|
||||||
<m_ParameterValue>sneak_walk</m_ParameterValue>
|
|
||||||
</m_Events>
|
|
||||||
<m_Events>
|
|
||||||
<m_EventName>Footstep</m_EventName>
|
|
||||||
<m_TimePc>0.6</m_TimePc>
|
|
||||||
<m_ParameterValue>sneak_walk</m_ParameterValue>
|
|
||||||
</m_Events>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode>
|
|
||||||
<m_Name>NoLegs_Turn</m_Name>
|
|
||||||
<m_DeferredBoneName>Bip01</m_DeferredBoneName>
|
|
||||||
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
|
|
||||||
<m_useDeferedRotation>true</m_useDeferedRotation>
|
|
||||||
<m_SpeedScale>0.80</m_SpeedScale>
|
|
||||||
<m_BlendTime>0.10</m_BlendTime>
|
|
||||||
<m_BlendOutTime>0.20</m_BlendOutTime>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
|
|
||||||
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>isTurning</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_Pelvis</boneName>
|
|
||||||
<includeDescendants>false</includeDescendants>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_Spine</boneName>
|
|
||||||
<includeDescendants>false</includeDescendants>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_BackPack</boneName>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_DressFront</boneName>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_DressBack</boneName>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_L_Thigh</boneName>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_R_Thigh</boneName>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01</boneName>
|
|
||||||
<includeDescendants>false</includeDescendants>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Translation_Data</boneName>
|
|
||||||
<includeDescendants>false</includeDescendants>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_Prop1</boneName>
|
|
||||||
<weight>0.00</weight>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<boneName>Bip01_Prop2</boneName>
|
|
||||||
<weight>0.00</weight>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode x_extends="NoLegs_Turn.xml">
|
|
||||||
<m_Name>NoLegs_TurnIdle</m_Name>
|
|
||||||
<m_Looped>false</m_Looped>
|
|
||||||
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
|
|
||||||
<m_BlendOutTime>0.10</m_BlendOutTime>
|
|
||||||
<m_Conditions />
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>isMoving</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>false</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
|
|
||||||
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>Aim</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>false</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Transitions>
|
|
||||||
<m_Target>Idle</m_Target>
|
|
||||||
<m_blendInTime>0.1</m_blendInTime>
|
|
||||||
</m_Transitions>
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<weight>0.25</weight>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<weight>0.20</weight>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
</animNode>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode x_extends="NoLegs_TurnIdle.xml">
|
|
||||||
<m_Name>NoLegs_TurnIdle180</m_Name>
|
|
||||||
<m_Conditions />
|
|
||||||
<m_Conditions />
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>isTurningAround</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights>
|
|
||||||
<weight>0.00</weight>
|
|
||||||
</m_SubStateBoneWeights>
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
<m_SubStateBoneWeights />
|
|
||||||
</animNode>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode x_extends="NoLegs_TurnIdle180.xml">
|
|
||||||
<m_Name>NoLegs_turnIdle180L</m_Name>
|
|
||||||
<m_AnimName>Bob_Crawl</m_AnimName>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>twist</m_Name>
|
|
||||||
<m_Type>LESS</m_Type>
|
|
||||||
<m_FloatValue>0</m_FloatValue>
|
|
||||||
</m_Conditions>
|
|
||||||
</animNode>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<animNode x_extends="NoLegs_TurnIdle180.xml">
|
|
||||||
<m_Name>NoLegs_TurnIdle180R</m_Name>
|
|
||||||
<m_AnimName>Bob_EmoteWaveBye</m_AnimName>
|
|
||||||
<m_Conditions />
|
|
||||||
<m_Conditions />
|
|
||||||
<m_Conditions />
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>IsCrawling</m_Name>
|
|
||||||
<m_Type>BOOL</m_Type>
|
|
||||||
<m_BoolValue>true</m_BoolValue>
|
|
||||||
</m_Conditions>
|
|
||||||
<m_Conditions>
|
|
||||||
<m_Name>twist</m_Name>
|
|
||||||
<m_Type>GTR</m_Type>
|
|
||||||
<m_FloatValue>0</m_FloatValue>
|
|
||||||
</m_Conditions>
|
|
||||||
</animNode>
|
|
||||||
61
media/clothing/clothingItems/Amputation_ForeArm_L.xml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Amputation\Amputation_Left_LowerArm_Male</m_MaleModel>
|
||||||
|
<m_FemaleModel>Amputation\Amputation_Left_LowerArm_Female</m_FemaleModel>
|
||||||
|
<m_GUID>d3816fe0-48e1-4cf5-a8e4-48c72595edb4</m_GUID>
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
|
||||||
|
<m_Masks>3</m_Masks>
|
||||||
|
<m_Masks>4</m_Masks>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- HUMAN -->
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_b</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_hairy_b</textureChoices>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- HUMAN AFTER CICATRIZATION -->
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05a</textureChoices>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ZOMBIE -->
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin01_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin01_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin01_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin02_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin02_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin02_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin03_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin03_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin03_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin04_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin04_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin04_l3</textureChoices>
|
||||||
|
|
||||||
|
</clothingItem>
|
||||||
58
media/clothing/clothingItems/Amputation_ForeArm_R.xml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Amputation\Amputation_Right_LowerArm_Male</m_MaleModel>
|
||||||
|
<m_FemaleModel>Amputation\Amputation_Right_LowerArm_Female</m_FemaleModel>
|
||||||
|
<m_GUID>e6f80efd-22e5-49e0-8b24-537519d42b37</m_GUID>
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
|
||||||
|
<m_Masks>5</m_Masks>
|
||||||
|
<m_Masks>6</m_Masks>
|
||||||
|
|
||||||
|
<!-- HUMAN -->
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_b</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_hairy_b</textureChoices>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- HUMAN AFTER CICATRIZATION -->
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05a</textureChoices>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ZOMBIE -->
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin01_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin01_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin01_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin02_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin02_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin02_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin03_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin03_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin03_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin04_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin04_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Forearm\z_skin04_l3</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
24
media/clothing/clothingItems/Amputation_Hand_L.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Amputation\Amputation_Left_Hand_Male</m_MaleModel>
|
||||||
|
<m_FemaleModel>Amputation\Amputation_Left_Hand_Female</m_FemaleModel>
|
||||||
|
<m_GUID>2de93af2-b7a8-4c04-84d1-28d92cce8a0f</m_GUID>
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<m_Masks>4</m_Masks>
|
||||||
|
<m_MasksFolder>none</m_MasksFolder>
|
||||||
|
|
||||||
|
<!-- HUMAN -->
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_b</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_hairy_b</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
23
media/clothing/clothingItems/Amputation_Hand_R.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Amputation\Amputation_Right_Hand_Male</m_MaleModel>
|
||||||
|
<m_FemaleModel>Amputation\Amputation_Right_Hand_Female</m_FemaleModel>
|
||||||
|
<m_GUID>f114e53a-b92e-4639-8d8c-2b43ab981885</m_GUID>
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<m_Masks>6</m_Masks>
|
||||||
|
<m_MasksFolder>none</m_MasksFolder>
|
||||||
|
|
||||||
|
<!-- HUMAN -->
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_b</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin01_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin02_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin03_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin04_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Forearm\skin05_hairy_b</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation\Amputation_GenericModel</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation\Amputation_GenericModel</m_FemaleModel>
|
|
||||||
<m_GUID>506c0fc0-b50c-4667-bafa-ae22e3c2c0dc</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>8</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation_Left_Hand_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation_Left_Hand_Female</m_FemaleModel>
|
|
||||||
<m_GUID>2de93af2-b7a8-4c04-84d1-28d92cce8a0f</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>4</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation_Left_LowerArm_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation_Left_LowerArm_Female</m_FemaleModel>
|
|
||||||
<m_GUID>d3816fe0-48e1-4cf5-a8e4-48c72595edb4</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>3</m_Masks>
|
|
||||||
<m_Masks>4</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation_Left_UpperArm_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation_Left_UpperArm_Female</m_FemaleModel>
|
|
||||||
<m_GUID>646cafa5-3fa1-41af-9ca0-aa57cca3b36d</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>3</m_Masks>
|
|
||||||
<m_Masks>4</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Upperarm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Upperarm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation\Amputation_GenericModel</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation\Amputation_GenericModel</m_FemaleModel>
|
|
||||||
<m_GUID>2600c2ab-bfeb-49c3-b0b5-e21c6d83d5c2</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>10</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation_Right_Hand_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation_Right_Hand_Female</m_FemaleModel>
|
|
||||||
<m_GUID>f114e53a-b92e-4639-8d8c-2b43ab981885</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>6</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation_Right_LowerArm_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation_Right_LowerArm_Female</m_FemaleModel>
|
|
||||||
<m_GUID>e6f80efd-22e5-49e0-8b24-537519d42b37</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>5</m_Masks>
|
|
||||||
<m_Masks>6</m_Masks>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Forearm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Forearm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Amputation_Right_UpperArm_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Amputation_Right_UpperArm_Female</m_FemaleModel>
|
|
||||||
<m_GUID>db8ccad2-b76f-44bd-93ab-1eefa25beade</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<m_Masks>5</m_Masks>
|
|
||||||
<m_Masks>6</m_Masks>
|
|
||||||
<m_MasksFolder>none</m_MasksFolder>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Upperarm\skin01_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin02_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin03_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin04_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin05_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Amputations\Upperarm\skin01_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin02_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin03_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin04_hairy_b</textureChoices>
|
|
||||||
<textureChoices>Amputations\Upperarm\skin05_hairy_b</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05</textureChoices>
|
|
||||||
|
|
||||||
<textureChoices>Body\MaleBody01a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody02a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody03a</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody04</textureChoices>
|
|
||||||
<textureChoices>Body\MaleBody05a</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
56
media/clothing/clothingItems/Amputation_UpperArm_L.xml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Amputation\Amputation_Left_UpperArm_Male</m_MaleModel>
|
||||||
|
<m_FemaleModel>Amputation\Amputation_Left_UpperArm_Female</m_FemaleModel>
|
||||||
|
<m_GUID>646cafa5-3fa1-41af-9ca0-aa57cca3b36d</m_GUID>
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<m_Masks>3</m_Masks>
|
||||||
|
<m_Masks>4</m_Masks>
|
||||||
|
|
||||||
|
<!-- HUMAN -->
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin01_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin02_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin03_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin04_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin05_b</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin01_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin02_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin03_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin04_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin05_hairy_b</textureChoices>
|
||||||
|
|
||||||
|
<!-- HUMAN AFTER CICATRIZATION -->
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05a</textureChoices>
|
||||||
|
|
||||||
|
<!-- ZOMBIE -->
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin01_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin01_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin01_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin02_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin02_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin02_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin03_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin03_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin03_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin04_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin04_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin04_l3</textureChoices>
|
||||||
|
|
||||||
|
</clothingItem>
|
||||||
57
media/clothing/clothingItems/Amputation_UpperArm_R.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Amputation\Amputation_Right_UpperArm_Male</m_MaleModel>
|
||||||
|
<m_FemaleModel>Amputation\Amputation_Right_UpperArm_Female</m_FemaleModel>
|
||||||
|
<m_GUID>db8ccad2-b76f-44bd-93ab-1eefa25beade</m_GUID>
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<m_Masks>5</m_Masks>
|
||||||
|
<m_Masks>6</m_Masks>
|
||||||
|
|
||||||
|
<!-- HUMAN -->
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin01_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin02_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin03_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin04_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm\skin05_b</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Human\Upperarm1\skin01_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm1\skin02_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm1\skin03_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm1\skin04_hairy_b</textureChoices>
|
||||||
|
<textureChoices>Amputations\Human\Upperarm1\skin05_hairy_b</textureChoices>
|
||||||
|
|
||||||
|
<!-- HUMAN AFTER CICATRIZATION -->
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Body\MaleBody01a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody02a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody03a</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody04</textureChoices>
|
||||||
|
<textureChoices>Body\MaleBody05a</textureChoices>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ZOMBIE -->
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin01_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin01_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin01_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin02_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin02_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin02_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin03_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin03_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin03_l3</textureChoices>
|
||||||
|
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin04_l1</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin04_l2</textureChoices>
|
||||||
|
<textureChoices>Amputations\Zombie\Upperarm\z_skin04_l3</textureChoices>
|
||||||
|
|
||||||
|
</clothingItem>
|
||||||
10
media/clothing/clothingItems/Prost_HookArm_L.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Prosthesis\hookArm_L_F</m_MaleModel>
|
||||||
|
<m_FemaleModel>Prosthesis\hookArm_L_F</m_FemaleModel>
|
||||||
|
<m_GUID>05338f5e-e984-49c2-be79-81af9ae8e818</m_GUID>
|
||||||
|
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<textureChoices>Prosthesis\hookArm</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
10
media/clothing/clothingItems/Prost_HookArm_R.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Prosthesis\hookArm_R_F</m_MaleModel>
|
||||||
|
<m_FemaleModel>Prosthesis\hookArm_R_F</m_FemaleModel>
|
||||||
|
<m_GUID>8ee7e1bc-2c21-428e-a15d-760d98df973d</m_GUID>
|
||||||
|
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<textureChoices>Prosthesis\hookArm</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Prost_Left_LowerArm_Base_Hook_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Prost_Left_LowerArm_Base_Hook_Female</m_FemaleModel>
|
|
||||||
<m_GUID>129ee688-d4bb-4297-8eb2-f88974001217</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<textureChoices>Prosthesis\metal_hook_male</textureChoices>
|
|
||||||
<textureChoices>Prosthesis\metal_hook_female</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
10
media/clothing/clothingItems/Prost_NormalArm_L.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Prosthesis\normalArm_L_M</m_MaleModel>
|
||||||
|
<m_FemaleModel>Prosthesis\normalArm_L_F</m_FemaleModel>
|
||||||
|
<m_GUID>689318c7-5045-4876-a7e1-360de4aedf89</m_GUID>
|
||||||
|
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<textureChoices>Prosthesis\normalArm</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
10
media/clothing/clothingItems/Prost_NormalArm_R.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<clothingItem>
|
||||||
|
<m_MaleModel>Prosthesis\normalArm_R_M</m_MaleModel>
|
||||||
|
<m_FemaleModel>Prosthesis\normalArm_R_F</m_FemaleModel>
|
||||||
|
<m_GUID>0e24eb76-4745-46af-9147-ba21e0ebbb2e</m_GUID>
|
||||||
|
|
||||||
|
<m_Static>false</m_Static>
|
||||||
|
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||||
|
<textureChoices>Prosthesis\normalArm</textureChoices>
|
||||||
|
</clothingItem>
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<clothingItem>
|
|
||||||
<m_MaleModel>Prost_Right_LowerArm_Base_Hook_Male</m_MaleModel>
|
|
||||||
<m_FemaleModel>Prost_Right_LowerArm_Base_Hook_Female</m_FemaleModel>
|
|
||||||
<m_GUID>1eb56768-d7ef-46e4-ac07-91d0e43d15fb</m_GUID>
|
|
||||||
<m_Static>false</m_Static>
|
|
||||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
|
||||||
<textureChoices>Prosthesis\metal_hook_male</textureChoices>
|
|
||||||
<textureChoices>Prosthesis\metal_hook_female</textureChoices>
|
|
||||||
</clothingItem>
|
|
||||||
@@ -1,100 +1,61 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<fileGuidTable>
|
<fileGuidTable>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Amputation_Right_Hand.xml</path>
|
<path>media/clothing/clothingItems/Amputation_Hand_R.xml</path>
|
||||||
<guid>f114e53a-b92e-4639-8d8c-2b43ab981885</guid>
|
<guid>f114e53a-b92e-4639-8d8c-2b43ab981885</guid>
|
||||||
</files>
|
</files>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Amputation_Right_LowerArm.xml</path>
|
<path>media/clothing/clothingItems/Amputation_ForeArm_R.xml</path>
|
||||||
<guid>e6f80efd-22e5-49e0-8b24-537519d42b37</guid>
|
<guid>e6f80efd-22e5-49e0-8b24-537519d42b37</guid>
|
||||||
</files>
|
</files>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Amputation_Right_UpperArm.xml</path>
|
<path>media/clothing/clothingItems/Amputation_UpperArm_R.xml</path>
|
||||||
<guid>db8ccad2-b76f-44bd-93ab-1eefa25beade</guid>
|
<guid>db8ccad2-b76f-44bd-93ab-1eefa25beade</guid>
|
||||||
</files>
|
</files>
|
||||||
|
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Amputation_Left_Hand.xml</path>
|
<path>media/clothing/clothingItems/Amputation_Hand_L.xml</path>
|
||||||
<guid>2de93af2-b7a8-4c04-84d1-28d92cce8a0f</guid>
|
<guid>2de93af2-b7a8-4c04-84d1-28d92cce8a0f</guid>
|
||||||
</files>
|
</files>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Amputation_Left_LowerArm.xml</path>
|
<path>media/clothing/clothingItems/Amputation_ForeArm_L.xml</path>
|
||||||
<guid>d3816fe0-48e1-4cf5-a8e4-48c72595edb4</guid>
|
<guid>d3816fe0-48e1-4cf5-a8e4-48c72595edb4</guid>
|
||||||
</files>
|
</files>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Amputation_Left_UpperArm.xml</path>
|
<path>media/clothing/clothingItems/Amputation_UpperArm_L.xml</path>
|
||||||
<guid>646cafa5-3fa1-41af-9ca0-aa57cca3b36d</guid>
|
<guid>646cafa5-3fa1-41af-9ca0-aa57cca3b36d</guid>
|
||||||
</files>
|
</files>
|
||||||
|
|
||||||
<!-- Prosthesis files -->
|
<!--Prosthetics -->
|
||||||
|
|
||||||
<!-- TODO RE DO ALL OF THIS!!! THIS IS OLD, MISSING STUFF, AND OLD OLD OLD-->
|
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Prost_Right_Hand_WoodenHook.xml</path>
|
<path>media/clothing/clothingItems/Prost_HookArm_L.xml</path>
|
||||||
<guid>1fcc7523-d577-4cb0-a019-f077ef281d3a</guid>
|
<guid>05338f5e-e984-49c2-be79-81af9ae8e818</guid>
|
||||||
</files>
|
</files>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Prost_Left_Hand_WoodenHook.xml</path>
|
<path>media/clothing/clothingItems/Prost_HookArm_R.xml</path>
|
||||||
<guid>0def629e-fe4f-4485-bdae-2d6032e150be</guid>
|
<guid>8ee7e1bc-2c21-428e-a15d-760d98df973d</guid>
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Right_Hand_MetalHook.xml</path>
|
|
||||||
<guid>dd7b749b-7e81-4547-91b0-81b1a1e9f7b8</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Left_Hand_MetalHook.xml</path>
|
|
||||||
<guid>6b4f4e13-d51f-48ab-80b0-6e0923650fc4</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Right_Hand_MetalHook.xml</path>
|
|
||||||
<guid>731c280a-9682-4e2e-84cf-470bf00dd02f</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Left_Hand_MetalHand.xml</path>
|
|
||||||
<guid>2101af26-54b9-455b-abc0-7533ce37f84b</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Right_LowerArm_WoodenHook.xml</path>
|
|
||||||
<guid>714b78a7-8895-4f48-a29d-b6f12909db0e</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Right_LowerArm_LeatherBase_MetalHook.xml</path>
|
|
||||||
<guid>1eb56768-d7ef-46e4-ac07-91d0e43d15fb</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Right_LowerArm_MetalHand.xml</path>
|
|
||||||
<guid>27758f1e-6298-42eb-b027-b9be31465c11</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Left_LowerArm_WoodenHook.xml</path>
|
|
||||||
<guid>aea8e02a-cba0-48d0-9eb0-7087651306b0</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Left_LowerArm_LeatherBase_MetalHook.xml</path>
|
|
||||||
<guid>129ee688-d4bb-4297-8eb2-f88974001217</guid>
|
|
||||||
</files>
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Prost_Left_LowerArm_MetalHand.xml</path>
|
|
||||||
<guid>0405a4c0-f71b-45a8-9edc-489fc81dca39</guid>
|
|
||||||
</files>
|
</files>
|
||||||
|
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Surgery_Left_Tourniquet.xml</path>
|
<path>media/clothing/clothingItems/Prost_NormalArm_L.xml</path>
|
||||||
|
<guid>689318c7-5045-4876-a7e1-360de4aedf89</guid>
|
||||||
|
</files>
|
||||||
|
<files>
|
||||||
|
<path>media/clothing/clothingItems/Prost_NormalArm_R.xml</path>
|
||||||
|
<guid>0e24eb76-4745-46af-9147-ba21e0ebbb2e</guid>
|
||||||
|
</files>
|
||||||
|
|
||||||
|
<!--Surgery -->
|
||||||
|
|
||||||
|
<files>
|
||||||
|
<path>media/clothing/clothingItems/Surg_Arm_Tourniquet_L.xml</path>
|
||||||
<guid>afbab35d-8bd4-4d61-87c7-054651ead1bd</guid>
|
<guid>afbab35d-8bd4-4d61-87c7-054651ead1bd</guid>
|
||||||
</files>
|
</files>
|
||||||
<files>
|
<files>
|
||||||
<path>media/clothing/clothingItems/Surgery_Right_Tourniquet.xml</path>
|
<path>media/clothing/clothingItems/Surg_Arm_Tourniquet_R.xml</path>
|
||||||
<guid>9a5fe063-63c7-4e6f-81ca-ee77c6678e0d</guid>
|
<guid>9a5fe063-63c7-4e6f-81ca-ee77c6678e0d</guid>
|
||||||
</files>
|
</files>
|
||||||
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Amputation_Left_Foot.xml</path>
|
|
||||||
<guid>506c0fc0-b50c-4667-bafa-ae22e3c2c0dc</guid>
|
|
||||||
</files>
|
|
||||||
|
|
||||||
<files>
|
|
||||||
<path>media/clothing/clothingItems/Amputation_Right_Foot.xml</path>
|
|
||||||
<guid>2600c2ab-bfeb-49c3-b0b5-e21c6d83d5c2</guid>
|
|
||||||
</files>
|
|
||||||
|
|
||||||
</fileGuidTable>
|
</fileGuidTable>
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
------------------------------------------
|
|
||||||
-------------- THE ONLY CURE -------------
|
|
||||||
------------------------------------------
|
|
||||||
---------- COMPATIBILITY FUNCS -----------
|
|
||||||
|
|
||||||
|
|
||||||
if TOC_Compat == nil then
|
|
||||||
TOC_Compat = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Gets the old status and turns it into the new.
|
|
||||||
TOC_Compat.CheckCompatibilityWithOlderVersions = function(modData)
|
|
||||||
|
|
||||||
if modData.TOC ~= nil then
|
|
||||||
print("TOC: found old data from TOC")
|
|
||||||
if modData.TOC.Limbs ~= nil then
|
|
||||||
TOC_Compat.MapOldDataToNew(modData)
|
|
||||||
modData.TOC = nil -- Deletes the old mod data stuff
|
|
||||||
else
|
|
||||||
print("TOC: something is wrong, couldn't find Limbs table in old TOC modData")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print("TOC: couldn't find old TOC data")
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
TOC_Compat.MapOldDataToNew = function(modData)
|
|
||||||
|
|
||||||
local oldNamesTable = { "RightHand", "RightForearm", "RightArm", "LeftHand", "LeftForearm", "LeftArm" }
|
|
||||||
local newNamesTable = { "Right_Hand", "Right_LowerArm", "Right_UpperArm", "Left_Hand", "Left_LowerArm", "Left_UpperArm" }
|
|
||||||
|
|
||||||
print("TOC: Trying to backup old data from TOC")
|
|
||||||
|
|
||||||
if modData == nil then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
print("TOC: found old data from TOC")
|
|
||||||
|
|
||||||
|
|
||||||
TOC_Cheat.ResetEverything()
|
|
||||||
|
|
||||||
-- Another check just in case the user is using Mr Bounty og version. I really don't wanna map that out so let's just reset everything directly
|
|
||||||
|
|
||||||
local compatEnum = nil
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Player has the og version of the mod
|
|
||||||
if modData.TOC.Limbs.RightHand.IsCut ~= nil then
|
|
||||||
print("TOC: Found TOC Beta data")
|
|
||||||
compatEnum = 1
|
|
||||||
elseif modData.TOC.Limbs.Right_Hand.is_cut ~= nil then
|
|
||||||
print("TOC: Found TOCBB data")
|
|
||||||
compatEnum = 2
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if compatEnum == nil then
|
|
||||||
print("TOC: Couldn't find any compatible data that could be retrieved")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Key setup
|
|
||||||
local isCutOldKey = nil
|
|
||||||
local isInfectedOldKey = nil
|
|
||||||
local isOperatedOldKey = nil
|
|
||||||
local isCicatrizedOldKey = nil
|
|
||||||
local isCauterizedOldKey = nil
|
|
||||||
local isAmputationShownOldKey = nil
|
|
||||||
local cicatrizationTimeOldKey = nil
|
|
||||||
local isOtherBodypartInfectedOldKey = nil
|
|
||||||
|
|
||||||
if compatEnum == 1 then
|
|
||||||
isCutOldKey = "IsCut"
|
|
||||||
isInfectedOldKey = "IsInfected"
|
|
||||||
isOperatedOldKey = "IsOperated"
|
|
||||||
isCicatrizedOldKey = "IsCicatrized"
|
|
||||||
isCauterizedOldKey = "ISBurn"
|
|
||||||
isAmputationShownOldKey = "ToDisplay"
|
|
||||||
cicatrizationTimeOldKey = "CicaTimeLeft"
|
|
||||||
isOtherBodypartInfectedOldKey = "OtherBody_IsInfected"
|
|
||||||
elseif compatEnum == 2 then
|
|
||||||
isCutOldKey = "is_cut"
|
|
||||||
isInfectedOldKey = "is_infected"
|
|
||||||
isOperatedOldKey = "is_operated"
|
|
||||||
isCicatrizedOldKey = "is_cicatrized"
|
|
||||||
isCauterizedOldKey = "is_cauterized"
|
|
||||||
isAmputationShownOldKey = "is_amputation_shown"
|
|
||||||
cicatrizationTimeOldKey = "cicatrization_time"
|
|
||||||
isOtherBodypartInfectedOldKey = "is_other_bodypart_infected"
|
|
||||||
|
|
||||||
elseif compatEnum == 3 then
|
|
||||||
isCutOldKey = "isCut"
|
|
||||||
isInfectedOldKey = "isInfected"
|
|
||||||
isOperatedOldKey = "isOperated"
|
|
||||||
isCicatrizedOldKey = "isCicatrized"
|
|
||||||
isCauterizedOldKey = "isCauterized"
|
|
||||||
isAmputationShownOldKey = "isAmputationShwon"
|
|
||||||
cicatrizationTimeOldKey = "cicatrizationTime"
|
|
||||||
isOtherBodypartInfectedOldKey = "isOtherBodypartInfected"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Starts reapplying stuff
|
|
||||||
modData.TOC.limbs.isOtherBodypartInfected = modData.TOC.Limbs[isOtherBodypartInfectedOldKey]
|
|
||||||
|
|
||||||
for i = 1, #newNamesTable do
|
|
||||||
|
|
||||||
local oldName = oldNamesTable[i]
|
|
||||||
local newName = newNamesTable[i]
|
|
||||||
print("TOC: isCut: " .. oldName .. " " .. tostring(modData.TOC.Limbs[oldName][isCutOldKey]))
|
|
||||||
print("TOC: isOperated: " .. oldName .. " " .. tostring(modData.TOC.Limbs[oldName][isOperatedOldKey]))
|
|
||||||
print("TOC: isCicatrized: " .. oldName .. " " .. tostring(modData.TOC.Limbs[oldName][isCicatrizedOldKey]))
|
|
||||||
print("TOC: isAmputationShown: " .. oldName .. " " .. tostring(modData.TOC.Limbs[oldName][isAmputationShownOldKey]))
|
|
||||||
print("TOC: cicatrizationTime: " .. oldName .. " " .. tostring(modData.TOC.Limbs[oldName][cicatrizationTimeOldKey]))
|
|
||||||
|
|
||||||
|
|
||||||
modData.TOC.limbs[newName].isCut = modData.TOC.Limbs[oldName][isCutOldKey]
|
|
||||||
|
|
||||||
if modData.TOC.limbs[newName].isCut then
|
|
||||||
print("TOC: Found old cut limb, reapplying model")
|
|
||||||
local cloth = getPlayer():getInventory():AddItem(TOC_Common.FindAmputatedClothingName(newName))
|
|
||||||
getPlayer():setWornItem(cloth:getBodyLocation(), cloth)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
modData.TOC.limbs[newName].isInfected = modData.TOC.Limbs[oldName][isInfectedOldKey]
|
|
||||||
modData.TOC.limbs[newName].isOperated = modData.TOC.Limbs[oldName][isOperatedOldKey]
|
|
||||||
modData.TOC.limbs[newName].isCicatrized = modData.TOC.Limbs[oldName][isCicatrizedOldKey]
|
|
||||||
modData.TOC.limbs[newName].isCauterized = modData.TOC.Limbs[oldName][isCauterizedOldKey]
|
|
||||||
modData.TOC.limbs[newName].isAmputationShown = modData.TOC.Limbs[oldName][isAmputationShownOldKey]
|
|
||||||
modData.TOC.limbs[newName].cicatrizationTime = modData.TOC.Limbs[oldName][cicatrizationTimeOldKey]
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
------------------------------------------
|
|
||||||
-------------- THE ONLY CURE -------------
|
|
||||||
------------------------------------------
|
|
||||||
----------- CUT LIMB FUNCTIONS -----------
|
|
||||||
|
|
||||||
-- Seems to be the first file loaded, so let's add this
|
|
||||||
if TOC == nil then
|
|
||||||
TOC = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local function CheckIfStillInfected(limbsData)
|
|
||||||
if limbsData == nil then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- Check ALL body part types to check if the player is still gonna die
|
|
||||||
local check = false
|
|
||||||
|
|
||||||
|
|
||||||
for _, v in pairs(TOC_Common.GetPartNames()) do
|
|
||||||
if limbsData[v].isInfected then
|
|
||||||
check = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if limbsData.isOtherBodypartInfected then
|
|
||||||
check = true
|
|
||||||
end
|
|
||||||
|
|
||||||
return check
|
|
||||||
end
|
|
||||||
|
|
||||||
local function CureInfection(bodyDamage, partName)
|
|
||||||
|
|
||||||
local bodyPartType = bodyDamage:getBodyPart(TOC_Common.GetBodyPartFromPartName(partName))
|
|
||||||
|
|
||||||
bodyDamage:setInfected(false)
|
|
||||||
bodyPartType:SetInfected(false)
|
|
||||||
bodyDamage:setInfectionMortalityDuration(-1)
|
|
||||||
bodyDamage:setInfectionTime(-1)
|
|
||||||
bodyDamage:setInfectionLevel(0)
|
|
||||||
local bodypartTypesTable = bodyDamage:getBodyParts()
|
|
||||||
|
|
||||||
-- TODO I think this is enough... we should just cycle if with everything instead of that crap up there
|
|
||||||
for i = bodypartTypesTable:size() - 1, 0, -1 do
|
|
||||||
local bodyPart = bodypartTypesTable:get(i)
|
|
||||||
bodyPart:SetInfected(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
if bodyPartType:scratched() then bodyPartType:setScratched(false, false) end
|
|
||||||
if bodyPartType:haveGlass() then bodyPartType:setHaveGlass(false) end
|
|
||||||
if bodyPartType:haveBullet() then bodyPartType:setHaveBullet(false, 0) end
|
|
||||||
if bodyPartType:isInfectedWound() then bodyPartType:setInfectedWound(false) end
|
|
||||||
if bodyPartType:isBurnt() then bodyPartType:setBurnTime(0) end
|
|
||||||
if bodyPartType:isCut() then bodyPartType:setCut(false, false) end --Lacerations
|
|
||||||
if bodyPartType:getFractureTime() > 0 then bodyPartType:setFractureTime(0) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function DeleteOtherAmputatedLimbs(side)
|
|
||||||
-- if left hand is cut and we cut left lowerarm, then delete hand
|
|
||||||
for _, limb in pairs(TOC.limbNames) do
|
|
||||||
local partName = "TOC.Amputation_" .. TOC_Common.ConcatPartName(side, limb)
|
|
||||||
local amputatedLimbItem = getPlayer():getInventory():FindAndReturn(partName)
|
|
||||||
if amputatedLimbItem then
|
|
||||||
getPlayer():getInventory():Remove(amputatedLimbItem)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param player any
|
|
||||||
---@param perk any The perk to scale down
|
|
||||||
local function LosePerkLevel(player, perk)
|
|
||||||
player:LoseLevel(perk)
|
|
||||||
local actualLevel = player:getPerkLevel(perk)
|
|
||||||
local perkXp = player:getXp()
|
|
||||||
perkXp:setXPToLevel(perk, actualLevel)
|
|
||||||
SyncXp(player)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param isHealingBite boolean
|
|
||||||
local function SetParametersForMissingLimb(bodyPart, isHealingBite)
|
|
||||||
bodyPart:setBleeding(false)
|
|
||||||
bodyPart:setBleedingTime(0)
|
|
||||||
bodyPart:setDeepWounded(false)
|
|
||||||
bodyPart:setDeepWoundTime(0)
|
|
||||||
bodyPart:setScratched(false, false) -- why the fuck are there 2 booleans TIS?
|
|
||||||
bodyPart:setScratchTime(0)
|
|
||||||
bodyPart:setCut(false)
|
|
||||||
bodyPart:setCutTime(0)
|
|
||||||
|
|
||||||
if isHealingBite then
|
|
||||||
bodyPart:SetBitten(false)
|
|
||||||
bodyPart:setBiteTime(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function TOC.DamagePlayerDuringAmputation(patient, partName)
|
|
||||||
|
|
||||||
-- Since we're cutting that specific part, it only makes sense that the bleeding starts from there.
|
|
||||||
-- Then, we just delete the bleeding somewhere else before applying the other damage to to upper part of the limb
|
|
||||||
local bodyPartType = TOC_Common.GetBodyPartFromPartName(partName)
|
|
||||||
local bodyDamage = patient:getBodyDamage()
|
|
||||||
local bodyDamagePart = bodyDamage:getBodyPart(bodyPartType)
|
|
||||||
|
|
||||||
|
|
||||||
bodyDamagePart:setBleeding(true)
|
|
||||||
bodyDamagePart:setCut(true)
|
|
||||||
bodyDamagePart:setBleedingTime(ZombRand(10, 20))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function FindTourniquetInWornItems(patient, side)
|
|
||||||
|
|
||||||
local checkString = "Surgery_" .. side .. "_Tourniquet"
|
|
||||||
local item = TOC_Common.FindItemInWornItems(patient, checkString)
|
|
||||||
return item
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function FindWristWatchInWornItems(patient, side)
|
|
||||||
local checkString = "Watch_" .. side
|
|
||||||
local item = TOC_Common.FindItemInWornItems(patient, checkString)
|
|
||||||
return item
|
|
||||||
|
|
||||||
end
|
|
||||||
----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Main function for cutting a limb
|
|
||||||
---@param partName string the part name to amputate
|
|
||||||
---@param surgeonFactor any the surgeon factor, which will determine some stats for the inflicted wound
|
|
||||||
---@param bandageTable any bandages info
|
|
||||||
---@param painkillerTable any painkillers info, not used
|
|
||||||
TOC.CutLimb = function(partName, surgeonFactor, bandageTable, painkillerTable)
|
|
||||||
|
|
||||||
-- TODO Separate Cut Limb in side and limb instead of single part_name
|
|
||||||
|
|
||||||
-- Items get unequipped in ISCutLimb.Start
|
|
||||||
local player = getPlayer()
|
|
||||||
|
|
||||||
local TOCModData = player:getModData().TOC
|
|
||||||
local limbParameters = TOC.limbParameters
|
|
||||||
local limbsData = TOCModData.limbs
|
|
||||||
|
|
||||||
|
|
||||||
-- Cut Hand -> Damage in forearm
|
|
||||||
-- Cut Forearm -> Damage in Upperarm
|
|
||||||
-- Cut UpperArm -> Damage to torso
|
|
||||||
local bodyDamage = player:getBodyDamage()
|
|
||||||
local bodyPart = bodyDamage:getBodyPart(TOC_Common.GetBodyPartFromPartName(partName))
|
|
||||||
local adjacentBodyPart = player:getBodyDamage():getBodyPart(TOC_Common.GetAdjacentBodyPartFromPartName(partName))
|
|
||||||
|
|
||||||
local stats = player:getStats()
|
|
||||||
local side = TOC_Common.GetSideFromPartName(partName)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Reset the status of the first body part, since we just cut it off it shouldn't be bleeding anymore
|
|
||||||
-- The bit will be checked later since we're not sure if the player is not infected from another wound
|
|
||||||
SetParametersForMissingLimb(bodyPart, false)
|
|
||||||
|
|
||||||
-- Use a tourniquet if available
|
|
||||||
local tourniquetItem = FindTourniquetInWornItems(player, side)
|
|
||||||
|
|
||||||
local baseDamageValue = 100
|
|
||||||
|
|
||||||
if tourniquetItem ~= nil then
|
|
||||||
baseDamageValue = 50 -- TODO Decrease mostly blood and damage, add pain, not everything else
|
|
||||||
|
|
||||||
if partName == TOC_Common.ConcatPartName(side, "UpperArm") then
|
|
||||||
player:removeWornItem(tourniquetItem)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Removes wrist watches in case they're amputating the same side where they equipped it
|
|
||||||
local wristWatchItem = FindWristWatchInWornItems(player, side)
|
|
||||||
|
|
||||||
if wristWatchItem ~= nil then
|
|
||||||
if partName == side .. "_LowerArm" or partName == side .. "_UpperArm" then
|
|
||||||
player:removeWornItem(wristWatchItem)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Set damage, stress, and low endurance after amputation
|
|
||||||
adjacentBodyPart:AddDamage(baseDamageValue - surgeonFactor)
|
|
||||||
adjacentBodyPart:setAdditionalPain(baseDamageValue - surgeonFactor)
|
|
||||||
adjacentBodyPart:setBleeding(true)
|
|
||||||
adjacentBodyPart:setBleedingTime(baseDamageValue - surgeonFactor)
|
|
||||||
adjacentBodyPart:setDeepWounded(true)
|
|
||||||
adjacentBodyPart:setDeepWoundTime(baseDamageValue - surgeonFactor)
|
|
||||||
stats:setEndurance(surgeonFactor)
|
|
||||||
stats:setStress(baseDamageValue - surgeonFactor)
|
|
||||||
|
|
||||||
|
|
||||||
-- Set malus for strength and fitness
|
|
||||||
-- TODO Make it more "random" with just some XP scaling down instead of a whole level, depending on the limb that we're cutting
|
|
||||||
LosePerkLevel(player, Perks.Fitness)
|
|
||||||
LosePerkLevel(player, Perks.Strength)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- If bandages are available, use them
|
|
||||||
adjacentBodyPart:setBandaged(bandageTable.useBandage, 10, bandageTable.isBandageSterilized,
|
|
||||||
bandageTable.bandageType)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- If painkillers are available, use them
|
|
||||||
-- TODO add painkiller support
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- A check for isCut shouldn't be necessary here since if we've got here we've already checked it out enough
|
|
||||||
|
|
||||||
if limbsData[partName].isCut == false then
|
|
||||||
limbsData[partName].isCut = true
|
|
||||||
limbsData[partName].isAmputationShown = true
|
|
||||||
limbsData[partName].cicatrizationTime = limbParameters[partName].cicatrizationBaseTime - surgeonFactor * 50
|
|
||||||
|
|
||||||
for _, depended_v in pairs(limbParameters[partName].dependsOn) do
|
|
||||||
limbsData[depended_v].isCut = true
|
|
||||||
limbsData[depended_v].isAmputationShown = false
|
|
||||||
limbsData[depended_v].cicatrizationTime = limbParameters[partName].cicatrizationBaseTime -
|
|
||||||
surgeonFactor * 50
|
|
||||||
|
|
||||||
local canHealDependedV = limbsData[depended_v].isInfected and
|
|
||||||
bodyDamage:getInfectionLevel() < 20
|
|
||||||
local depended_body_part = bodyDamage:getBodyPart(TOC_Common.GetBodyPartFromPartName(depended_v))
|
|
||||||
SetParametersForMissingLimb(depended_body_part, canHealDependedV)
|
|
||||||
|
|
||||||
if canHealDependedV then
|
|
||||||
limbsData[depended_v].isInfected = false
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Heal the infection here
|
|
||||||
local body_damage = player:getBodyDamage()
|
|
||||||
if limbsData[partName].isInfected and body_damage:getInfectionLevel() < 20 then
|
|
||||||
limbsData[partName].isInfected = false
|
|
||||||
|
|
||||||
-- NOT THE ADIACENT ONE!!!
|
|
||||||
bodyPart:SetBitten(false)
|
|
||||||
bodyPart:setBiteTime(0)
|
|
||||||
|
|
||||||
-- Second check, let's see if there is any other infected limb.
|
|
||||||
if CheckIfStillInfected(limbsData) == false then
|
|
||||||
CureInfection(body_damage, partName)
|
|
||||||
getPlayer():Say("I'm gonna be fine...") -- TODO Make it visible to other players, check True Actions as reference
|
|
||||||
else
|
|
||||||
getPlayer():Say("I'm still gonna die...")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Check for older amputation models and deletes them from player's inventory
|
|
||||||
local side = string.match(partName, '(%w+)_')
|
|
||||||
DeleteOtherAmputatedLimbs(side)
|
|
||||||
|
|
||||||
--Equip new model for amputation
|
|
||||||
local amputation_clothing_item_name = TOC_Common.FindAmputatedClothingName(partName)
|
|
||||||
print(amputation_clothing_item_name)
|
|
||||||
|
|
||||||
local amputation_clothing_item = player:getInventory():AddItem(amputation_clothing_item_name)
|
|
||||||
TOC_Visuals.SetTextureForAmputation(amputation_clothing_item, player, false)
|
|
||||||
player:setWornItem(amputation_clothing_item:getBodyLocation(), amputation_clothing_item)
|
|
||||||
|
|
||||||
|
|
||||||
-- Set blood on the amputated limb
|
|
||||||
TOC_Visuals.SetBloodOnAmputation(getPlayer(), adjacentBodyPart)
|
|
||||||
|
|
||||||
if partName == "Left_Foot" or partName == "Right_Foot" then
|
|
||||||
TOC_Anims.SetMissingFootAnimation(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
------------------------------------------
|
|
||||||
-------------- THE ONLY CURE -------------
|
|
||||||
------------------------------------------
|
|
||||||
------------- LOCAL ACTIONS --------------
|
|
||||||
|
|
||||||
--Used to handle SP scenarios
|
|
||||||
|
|
||||||
|
|
||||||
if TOC_LocalActions == nil then
|
|
||||||
TOC_LocalActions = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function TOC_LocalActions.Cut(_, player, partName)
|
|
||||||
if TOC_Common.GetSawInInventory(player) ~= nil then
|
|
||||||
ISTimedActionQueue.add(TOC_CutLimbAction:new(player, player, partName))
|
|
||||||
else
|
|
||||||
player:Say("I don't have a saw on me")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TOC_LocalActions.Operate(_, player, partName, useOven)
|
|
||||||
if useOven then
|
|
||||||
ISTimedActionQueue.add(TOC_OperateLimbAction:new(player, player, _, partName, useOven));
|
|
||||||
else
|
|
||||||
local kit = TOC_Common.GetKitInInventory(player)
|
|
||||||
if kit ~= nil then
|
|
||||||
ISTimedActionQueue.add(TOC_OperateLimbAction:new(player, player, kit, partName, false))
|
|
||||||
else
|
|
||||||
player:Say("I don't have a kit on me")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TOC_LocalActions.EquipProsthesis(_, player, partName)
|
|
||||||
local surgeonInv = player:getInventory()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO Find a better way to filter objects. Disabled for now and only gets LeatherBase
|
|
||||||
local prosthesisToEquip = surgeonInv:getItemFromType('TOC.LeatherBase_MetalHook')
|
|
||||||
if prosthesisToEquip then
|
|
||||||
ISTimedActionQueue.add(TOC_InstallProsthesisAction:new(player, player, prosthesisToEquip, partName))
|
|
||||||
else
|
|
||||||
player:Say("I need a prosthesis")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TOC_LocalActions.UnequipProsthesis(_, player, partName)
|
|
||||||
ISTimedActionQueue.add(TOC_UninstallProsthesisAction:new(player, player, partName))
|
|
||||||
end
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
------------------------------------------
|
|
||||||
-------- THE ONLY CURE --------
|
|
||||||
------------------------------------------
|
|
||||||
--------- OPERATE LIMB FUNCTIONS ---------
|
|
||||||
|
|
||||||
local function FixSingleBodyPartType(bodyPartType, useOven)
|
|
||||||
bodyPartType:setDeepWounded(false) --Basically like stitching
|
|
||||||
bodyPartType:setDeepWoundTime(0)
|
|
||||||
if useOven then
|
|
||||||
bodyPartType:AddDamage(100)
|
|
||||||
bodyPartType:setAdditionalPain(100);
|
|
||||||
bodyPartType:setBleeding(false)
|
|
||||||
bodyPartType:setBleedingTime(0) -- no bleeding since it's been cauterized
|
|
||||||
else
|
|
||||||
-- TODO Think a little better about this, do we want to trigger bleeding or not?
|
|
||||||
bodyPartType:setBleeding(false)
|
|
||||||
|
|
||||||
--body_part_type:setBleedingTime(ZombRand(1, 5)) -- Reset the bleeding, maybe make it random
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function SetBodyPartsStatusAfterOperation(player, limbParameters, partName, useOven)
|
|
||||||
|
|
||||||
|
|
||||||
local bodyPartType = player:getBodyDamage():getBodyPart(TOC_Common.GetAdjacentBodyPartFromPartName(partName))
|
|
||||||
FixSingleBodyPartType(bodyPartType, useOven)
|
|
||||||
|
|
||||||
for _, v in pairs(limbParameters[partName].dependsOn) do
|
|
||||||
local dependedBodyPartType = player:getBodyDamage():getBodyPart(TOC_Common.GetAdjacentBodyPartFromPartName(v))
|
|
||||||
FixSingleBodyPartType(dependedBodyPartType, useOven)
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
---Main function to operate a limb after amputation
|
|
||||||
---@param partName any
|
|
||||||
---@param surgeonFactor any
|
|
||||||
---@param useOven boolean wheter using oven instead of a kit or not
|
|
||||||
function TOC.OperateLimb(partName, surgeonFactor, useOven)
|
|
||||||
|
|
||||||
local player = getPlayer()
|
|
||||||
|
|
||||||
|
|
||||||
local TOCModData = player:getModData().TOC
|
|
||||||
|
|
||||||
local limbParameters = TOC.limbParameters
|
|
||||||
local limbsData = TOCModData.limbs
|
|
||||||
|
|
||||||
if useOven then
|
|
||||||
local stats = player:getStats()
|
|
||||||
stats:setEndurance(100)
|
|
||||||
stats:setStress(100)
|
|
||||||
end
|
|
||||||
|
|
||||||
if limbsData[partName].isOperated == false and limbsData[partName].isCut == true then
|
|
||||||
limbsData[partName].isOperated = true
|
|
||||||
limbsData[partName].cicatrizationTime = limbsData[partName].cicatrizationTime - (surgeonFactor * 200)
|
|
||||||
if useOven then limbsData[partName].isCauterized = true end
|
|
||||||
for _, dependedPart in pairs(limbParameters[partName].dependsOn) do
|
|
||||||
limbsData[dependedPart].isOperated = true
|
|
||||||
-- TODO We should not have cicatrization time for depended parts.
|
|
||||||
-- limbsData[dependedPart].cicatrizationTime = limbsData[dependedPart].cicatrizationTime -
|
|
||||||
-- (surgeonFactor * 200)
|
|
||||||
if useOven then limbsData[dependedPart].isCauterized = true end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
SetBodyPartsStatusAfterOperation(player, limbParameters, partName, useOven)
|
|
||||||
end
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
------------------------------------------
|
|
||||||
------------- THE ONLY CURE --------------
|
|
||||||
------------------------------------------
|
|
||||||
---------- PROSTHESIS FUNCTIONS ----------
|
|
||||||
|
|
||||||
|
|
||||||
---Equip a prosthesis transforming a normal item into a clothing item
|
|
||||||
---@param partName string
|
|
||||||
---@param prosthesisItem any the prosthesis item
|
|
||||||
---@param prosthesisBaseName string I don't really remember
|
|
||||||
function TOC.EquipProsthesis(partName, prosthesisItem, prosthesisBaseName)
|
|
||||||
|
|
||||||
-- TODO probably will have to move this from the TOC menu to classic equip to have dynamic durability
|
|
||||||
-- TODO We need to pass the original item so we can get its data!
|
|
||||||
|
|
||||||
local player = getPlayer()
|
|
||||||
local TOCModData = player:getModData().TOC
|
|
||||||
|
|
||||||
local equippedProsthesis = GenerateEquippedProsthesis(prosthesisItem, player:getInventory(), partName)
|
|
||||||
|
|
||||||
|
|
||||||
--print("TOC: Test durability new item " .. added_prosthesis_mod_data.TOC.durability)
|
|
||||||
|
|
||||||
-- TODO equippedProsthesis must have something like the ProsthesisFactor from before!!!
|
|
||||||
|
|
||||||
if partName ~= nil then
|
|
||||||
|
|
||||||
if equippedProsthesis ~= nil then
|
|
||||||
TOCModData.limbs[partName].isProsthesisEquipped = true
|
|
||||||
|
|
||||||
|
|
||||||
-- Fill equippedProsthesis with the correct stuff
|
|
||||||
-- TODO For prosthetics we should fetch the data from a modData INSIDE them!
|
|
||||||
|
|
||||||
-- TODO Change the value passed, it's wrong
|
|
||||||
--TOCModData.limbs[partName].equippedProsthesis = TOCModData.Prosthesis[prosthesisBaseName][partName]
|
|
||||||
|
|
||||||
if player:isFemale() then
|
|
||||||
equippedProsthesis:getVisual():setTextureChoice(1)
|
|
||||||
else
|
|
||||||
equippedProsthesis:getVisual():setTextureChoice(0)
|
|
||||||
end
|
|
||||||
player:setWornItem(equippedProsthesis:getBodyLocation(), equippedProsthesis)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
---Unequip a prosthesis clothing item and returns it to the inventory as a normal item
|
|
||||||
---@param partName string
|
|
||||||
function TOC.UnequipProsthesis(patient, partName, equippedProsthesis)
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO Pass the parameters generated from EquipProsthesis to the re-generated normal item
|
|
||||||
|
|
||||||
local TOCModData = patient:getModData().TOC
|
|
||||||
TOCModData.limbs[partName].isProsthesisEquipped = false
|
|
||||||
|
|
||||||
|
|
||||||
local equippedProstFullType = equippedProsthesis:getFullType()
|
|
||||||
|
|
||||||
|
|
||||||
for _, prostValue in ipairs(GetProsthesisList()) do
|
|
||||||
local prostName = string.match(equippedProstFullType, prostValue)
|
|
||||||
if prostName then
|
|
||||||
-- Get mod data from equipped prosthesis so we can get its parameters
|
|
||||||
local equippedProstModData = equippedProsthesis:getModData()
|
|
||||||
|
|
||||||
|
|
||||||
local baseProstItem = patient:getInventory():AddItem("TOC." .. prostName)
|
|
||||||
local baseProstItemModData = baseProstItem.getModData()
|
|
||||||
baseProstItemModData.TOC = {
|
|
||||||
durability = equippedProstModData.TOC.durability,
|
|
||||||
speed = equippedProstModData.TOC.speed
|
|
||||||
}
|
|
||||||
|
|
||||||
patient:setWornItem(equippedProsthesis:getBodyLocation(), nil)
|
|
||||||
patient:getInventory():Remove(equippedProsthesis)
|
|
||||||
TOCModData.limbs[partName].equippedProsthesis = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
-- TODO this should be moved
|
|
||||||
|
|
||||||
local function TryToToResetEverythingOtherPlayer(_, patient, surgeon)
|
|
||||||
sendClientCommand(surgeon, "TOC", "AskToResetEverything", { patient:getOnlineID() })
|
|
||||||
end
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------------
|
|
||||||
if TOC_ContextMenu == nil then
|
|
||||||
TOC_ContextMenu = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
TOC_ContextMenu.CreateCheatsMenu = function(playerId, context, worldObjects, _)
|
|
||||||
local clickedPlayers = {}
|
|
||||||
local currentClickedPlayer = nil
|
|
||||||
|
|
||||||
local localPlayer = getSpecificPlayer(playerId)
|
|
||||||
--local players = getOnlinePlayers()
|
|
||||||
|
|
||||||
for _, v in pairs(worldObjects) do
|
|
||||||
-- help detecting a player by checking nearby squares
|
|
||||||
for x = v:getSquare():getX() - 1, v:getSquare():getX() + 1 do
|
|
||||||
for y = v:getSquare():getY() - 1, v:getSquare():getY() + 1 do
|
|
||||||
local sq = getCell():getGridSquare(x, y, v:getSquare():getZ())
|
|
||||||
if sq then
|
|
||||||
for i = 0, sq:getMovingObjects():size() - 1 do
|
|
||||||
local o = sq:getMovingObjects():get(i)
|
|
||||||
if instanceof(o, "IsoPlayer") then
|
|
||||||
currentClickedPlayer = o
|
|
||||||
|
|
||||||
if clickedPlayers[currentClickedPlayer:getUsername()] == nil then
|
|
||||||
|
|
||||||
-- FIXME this is to prevent context menu spamming. Find a better way
|
|
||||||
clickedPlayers[currentClickedPlayer:getUsername()] = true
|
|
||||||
|
|
||||||
if localPlayer:getAccessLevel() == "Admin" or isDebugEnabled() then
|
|
||||||
local rootOption = context:addOption("TOC - Cheats on " .. currentClickedPlayer:getUsername())
|
|
||||||
local rootMenu = context:getNew(context)
|
|
||||||
|
|
||||||
if currentClickedPlayer == localPlayer then
|
|
||||||
rootMenu:addOption("Reset TOC for me", _, TOC_Cheat.ResetEverything)
|
|
||||||
|
|
||||||
else
|
|
||||||
rootMenu:addOption("Reset TOC for " .. currentClickedPlayer:getUsername(), _, TryToToResetEverythingOtherPlayer,
|
|
||||||
currentClickedPlayer, localPlayer)
|
|
||||||
|
|
||||||
end
|
|
||||||
context:addSubMenu(rootOption, rootMenu)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- TocContextMenus.FillCutAndOperateMenus(local_player, clicked_player, worldObjects,
|
|
||||||
-- cut_menu, operate_menu)
|
|
||||||
--TocContextMenus.FillCheatMenu(context, cheat_menu)
|
|
||||||
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
TOC_ContextMenu.CreateOperateWithOvenMenu = function(playerId, context, worldObjects, test)
|
|
||||||
local player = getSpecificPlayer(playerId)
|
|
||||||
-- TODO Let the player move towards the oven
|
|
||||||
|
|
||||||
local partData = player:getModData().TOC.limbs
|
|
||||||
local isMainMenuAlreadyCreated = false
|
|
||||||
|
|
||||||
for _, currentObject in pairs(worldObjects) do
|
|
||||||
if instanceof(currentObject, "IsoStove") and (player:HasTrait("Brave") or player:getPerkLevel(Perks.Strength) >= 6) then
|
|
||||||
|
|
||||||
-- Check temperature
|
|
||||||
if currentObject:getCurrentTemperature() > 250 then
|
|
||||||
|
|
||||||
for _, partName in ipairs(TOC_Common.GetPartNames()) do
|
|
||||||
if partData[partName].isCut and partData[partName].isAmputationShown and
|
|
||||||
not partData[partName].isOperated then
|
|
||||||
local subMenu = context:getNew(context);
|
|
||||||
|
|
||||||
if isMainMenuAlreadyCreated == false then
|
|
||||||
local rootMenu = context:addOption(getText('UI_ContextMenu_OperateOven'), worldObjects, nil);
|
|
||||||
context:addSubMenu(rootMenu, subMenu)
|
|
||||||
isMainMenuAlreadyCreated = true
|
|
||||||
end
|
|
||||||
subMenu:addOption(getText('UI_ContextMenu_' .. partName), worldObjects, TOC_LocalActions.Operate,
|
|
||||||
getSpecificPlayer(playerId), partName,true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
break -- stop searching for stoves
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
TOC_ContextMenu.CreateNewMenu = function(name, context, rootMenu)
|
|
||||||
|
|
||||||
local new_option = rootMenu:addOption(name)
|
|
||||||
local new_menu = context:getNew(context)
|
|
||||||
context:addSubMenu(new_option, new_menu)
|
|
||||||
|
|
||||||
return new_menu
|
|
||||||
end
|
|
||||||
|
|
||||||
TOC_ContextMenu.FillCheatMenus = function(context, cheat_menu)
|
|
||||||
|
|
||||||
if cheat_menu then
|
|
||||||
local cheat_cut_and_fix_menu = TOC_ContextMenu.CreateNewMenu("Cut and Fix", context, cheat_menu)
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
Events.OnFillWorldObjectContextMenu.Add(TOC_ContextMenu.CreateOperateWithOvenMenu) -- this is probably too much
|
|
||||||
Events.OnFillWorldObjectContextMenu.Add(TOC_ContextMenu.CreateCheatsMenu) -- TODO Add check only when admin is active
|
|
||||||
@@ -1,700 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
if TOC_UI == nil then
|
|
||||||
TOC_UI = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local mainUI, descUI, confirmUI, confirmUIMP
|
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
|
||||||
-- MP stuff
|
|
||||||
|
|
||||||
-- TODO Strip out all this crap and redo it
|
|
||||||
local function PrerenderFuncMP()
|
|
||||||
local toSee = confirmUIMP
|
|
||||||
if confirmUIMP.responseReceive then
|
|
||||||
if not confirmUIMP.responseCan then
|
|
||||||
getPlayer():Say("I can't do that !")
|
|
||||||
confirmUIMP.responseReceive = false
|
|
||||||
confirmUIMP:close()
|
|
||||||
return false;
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Prerender basically hooks onto SendCommandToConfirmUI, dunno how but it does
|
|
||||||
SendCommandToConfirmUIMP(confirmUIMP.responseAction, confirmUIMP.responseIsBitten,
|
|
||||||
confirmUIMP.responseUserName, confirmUIMP.responsePartName);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
-- Getters
|
|
||||||
function GetConfirmUIMP()
|
|
||||||
return confirmUIMP;
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------
|
|
||||||
-- UI Visible stuff functions
|
|
||||||
local function GetImageName(partName, limbsData)
|
|
||||||
local name = ""
|
|
||||||
|
|
||||||
local partData = limbsData[partName]
|
|
||||||
|
|
||||||
if partData.isCut and partData.isCicatrized and partData.isProsthesisEquipped then -- Cut and equip
|
|
||||||
if partName == "Right_Hand" or partName == "Left_Hand" then
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Hook.png"
|
|
||||||
else
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Prothesis.png"
|
|
||||||
end
|
|
||||||
elseif partData.isCut and partData.isCicatrized and not partData.isProsthesisEquipped and
|
|
||||||
partData.isAmputationShown then -- Cut and heal
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Cut.png"
|
|
||||||
elseif partData.isCut and not partData.isCicatrized and partData.isAmputationShown and
|
|
||||||
not partData.isOperated then -- Cut but not healead
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Bleed.png"
|
|
||||||
elseif partData.isCut and not partData.isCicatrized and partData.isAmputationShown and partData.isOperated then -- Cut but not healed and operated
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Operate.png"
|
|
||||||
elseif partData.isCut and not partData.isAmputationShown then -- Empty (like hand if forearm cut)
|
|
||||||
name = "media/ui/TOC/Empty.png"
|
|
||||||
elseif not partData.isCut and
|
|
||||||
-- FIXME This doesn't work in MP on another player since we're trying to retrieve bodyDamage from another player
|
|
||||||
getPlayer():getBodyDamage():getBodyPart(TOC_Common.GetBodyPartFromPartName(partName)):bitten() then -- Not cut but bitten
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Bite.png"
|
|
||||||
else -- Not cut
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Base.png"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If foreaerm equip, change hand
|
|
||||||
if partName == "Right_Hand" and limbsData["Right_LowerArm"].isProsthesisEquipped then
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Hook.png"
|
|
||||||
elseif partName == "Left_Hand" and limbsData["Left_LowerArm"].isProsthesisEquipped then
|
|
||||||
name = "media/ui/TOC/" .. partName .. "/Hook.png"
|
|
||||||
end
|
|
||||||
return name
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------------------------------
|
|
||||||
-- Check functions
|
|
||||||
|
|
||||||
local function IsProsthesisInstalled(partData)
|
|
||||||
return partData.isCut and partData.isCicatrized and partData.isProsthesisEquipped
|
|
||||||
end
|
|
||||||
|
|
||||||
local function CanProsthesisBeEquipped(partData)
|
|
||||||
|
|
||||||
return partData.isCut and partData.isCicatrized and not partData.isProsthesisEquipped and
|
|
||||||
partData.isAmputationShown
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function IsAmputatedLimbHealed(partData)
|
|
||||||
return partData.isCut and not partData.isCicatrized and partData.isAmputationShown
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function IsAmputatedLimbToBeVisible(partData)
|
|
||||||
return partData.isCut and not partData.isAmputationShown
|
|
||||||
end
|
|
||||||
|
|
||||||
local function IsPartBitten(partData, partName)
|
|
||||||
return not partData.isCut and
|
|
||||||
getPlayer():getBodyDamage():getBodyPart(TOC_Common.GetBodyPartFromPartName(partName)):bitten()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function FindMinMax(lv)
|
|
||||||
local min, max
|
|
||||||
if lv == 1 then
|
|
||||||
min = 0;
|
|
||||||
max = 75;
|
|
||||||
elseif lv == 2 then
|
|
||||||
min = 75;
|
|
||||||
max = 150 + 75;
|
|
||||||
elseif lv == 3 then
|
|
||||||
min = 150;
|
|
||||||
max = 300 + 75 + 150;
|
|
||||||
elseif lv == 4 then
|
|
||||||
min = 300;
|
|
||||||
max = 750 + 75 + 150 + 300;
|
|
||||||
elseif lv == 5 then
|
|
||||||
min = 750;
|
|
||||||
max = 1500 + 75 + 150 + 300 + 750;
|
|
||||||
elseif lv == 6 then
|
|
||||||
min = 1500;
|
|
||||||
max = 3000 + 75 + 150 + 300 + 750 + 1500;
|
|
||||||
elseif lv == 7 then
|
|
||||||
min = 3000;
|
|
||||||
max = 4500 + 75 + 150 + 300 + 750 + 1500 + 3000;
|
|
||||||
elseif lv == 8 then
|
|
||||||
min = 4500;
|
|
||||||
max = 6000 + 75 + 150 + 300 + 750 + 1500 + 3000 + 4500;
|
|
||||||
elseif lv == 9 then
|
|
||||||
min = 6000;
|
|
||||||
max = 7500 + 75 + 150 + 300 + 750 + 1500 + 3000 + 4500 + 6000;
|
|
||||||
elseif lv == 10 then
|
|
||||||
min = 7500;
|
|
||||||
max = 9000 + 75 + 150 + 300 + 750 + 1500 + 3000 + 4500 + 6000 + 7500;
|
|
||||||
end
|
|
||||||
return min, max;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------
|
|
||||||
-- Setup stuff with variables and shit
|
|
||||||
|
|
||||||
TOC_UI.SetupMainUI = function(surgeon, patient, limbsData)
|
|
||||||
mainUI.surgeon = surgeon -- we shouldn't need an arg for this
|
|
||||||
mainUI.patient = patient
|
|
||||||
|
|
||||||
if limbsData then
|
|
||||||
|
|
||||||
mainUI.limbsData = limbsData
|
|
||||||
|
|
||||||
mainUI["b11"]:setPath(GetImageName("Right_UpperArm", limbsData))
|
|
||||||
mainUI["b12"]:setPath(GetImageName("Left_UpperArm", limbsData))
|
|
||||||
|
|
||||||
mainUI["b21"]:setPath(GetImageName("Right_LowerArm", limbsData))
|
|
||||||
mainUI["b22"]:setPath(GetImageName("Left_LowerArm", limbsData))
|
|
||||||
|
|
||||||
mainUI["b31"]:setPath(GetImageName("Right_Hand", limbsData))
|
|
||||||
mainUI["b32"]:setPath(GetImageName("Left_Hand", limbsData))
|
|
||||||
|
|
||||||
mainUI["b41"]:setPath(GetImageName("Right_Foot", limbsData))
|
|
||||||
mainUI["b42"]:setPath(GetImageName("Left_Foot", limbsData))
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
TOC_UI.SetupDescUI = function(surgeon, patient, limbsData, partName)
|
|
||||||
descUI["textTitle"]:setText(getText("UI_ContextMenu_" .. partName))
|
|
||||||
descUI.partName = partName
|
|
||||||
descUI.surgeon = surgeon
|
|
||||||
descUI.patient = patient
|
|
||||||
|
|
||||||
local partData = limbsData[partName]
|
|
||||||
|
|
||||||
if IsProsthesisInstalled(partData) then
|
|
||||||
-- Limb cut with prosthesis
|
|
||||||
descUI["status"]:setText("Prosthesis equipped")
|
|
||||||
descUI["status"]:setColor(1, 0, 1, 0)
|
|
||||||
descUI["b1"]:setText("Unequip")
|
|
||||||
descUI["b1"]:addArg("option", "Unequip")
|
|
||||||
descUI["b1"]:setVisible(true)
|
|
||||||
elseif CanProsthesisBeEquipped(partData) then
|
|
||||||
-- Limb cut but no prosthesis
|
|
||||||
descUI["status"]:setText("Amputated and healed")
|
|
||||||
descUI["status"]:setColor(1, 0, 1, 0)
|
|
||||||
|
|
||||||
-- Another check for UpperArm
|
|
||||||
if partName == "Right_UpperArm" or partName == "Left_UpperArm" then
|
|
||||||
descUI["b1"]:setVisible(false)
|
|
||||||
else
|
|
||||||
descUI["b1"]:setText("Equip")
|
|
||||||
descUI["b1"]:addArg("option", "Equip")
|
|
||||||
descUI["b1"]:setVisible(true)
|
|
||||||
end
|
|
||||||
-- Limb cut but still healing
|
|
||||||
elseif IsAmputatedLimbHealed(partData) then
|
|
||||||
-- Limb cut and healed, no prosthesis equipped
|
|
||||||
if partData.isOperated then
|
|
||||||
|
|
||||||
descUI["b1"]:setVisible(false) -- no operate prompt
|
|
||||||
|
|
||||||
if partData.cicatrizationTime > 1000 then
|
|
||||||
descUI["status"]:setText("Still a long way to go")
|
|
||||||
descUI["status"]:setColor(1, 0.8, 1, 0.2);
|
|
||||||
elseif partData.cicatrizationTime > 500 then
|
|
||||||
descUI["status"]:setText("Starting to get better")
|
|
||||||
descUI["status"]:setColor(1, 0.8, 1, 0.2)
|
|
||||||
|
|
||||||
elseif partData.cicatrizationTime > 100 then
|
|
||||||
descUI["status"]:setText("Almost cicatrized")
|
|
||||||
descUI["status"]:setColor(1, 0.8, 1, 0.2)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Set the operate button
|
|
||||||
descUI["b1"]:setText("Operate")
|
|
||||||
descUI["b1"]:addArg("option", "Operate")
|
|
||||||
descUI["b1"]:setVisible(true)
|
|
||||||
|
|
||||||
if partData.cicatrizationTime > 1000 then
|
|
||||||
descUI["status"]:setText("It hurts so much...")
|
|
||||||
descUI["status"]:setColor(1, 1, 0, 0)
|
|
||||||
elseif partData.cicatrizationTime > 500 then
|
|
||||||
descUI["status"]:setText("It still hurts a lot")
|
|
||||||
descUI["status"]:setColor(1, 0.8, 1, 0.2)
|
|
||||||
elseif partData.cicatrizationTime > 500 then
|
|
||||||
descUI["status"]:setText("I think it's almost over...")
|
|
||||||
descUI["status"]:setColor(1, 0.8, 1, 0.2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
elseif IsAmputatedLimbToBeVisible(partData) then
|
|
||||||
-- Limb cut and not visible (ex: hand after having amputated forearm)
|
|
||||||
descUI["status"]:setText("Nothing here")
|
|
||||||
descUI["status"]:setColor(1, 1, 1, 1)
|
|
||||||
descUI["b1"]:setVisible(false)
|
|
||||||
elseif TOC_Common.CheckIfCanBeCut(partName, limbsData) then
|
|
||||||
-- Everything else
|
|
||||||
-- TODO add check for cuts and scratches
|
|
||||||
descUI["status"]:setText("Not cut")
|
|
||||||
descUI["status"]:setColor(1, 1, 1, 1)
|
|
||||||
if TOC_Common.GetSawInInventory(surgeon) and not TOC_Common.CheckIfProsthesisAlreadyInstalled(limbsData, partName) then
|
|
||||||
descUI["b1"]:setVisible(true)
|
|
||||||
descUI["b1"]:setText("Cut")
|
|
||||||
descUI["b1"]:addArg("option", "Cut")
|
|
||||||
elseif TOC_Common.GetSawInInventory(surgeon) and TOC_Common.CheckIfProsthesisAlreadyInstalled(limbsData, partName) then
|
|
||||||
descUI["b1"]:setVisible(true)
|
|
||||||
descUI["b1"]:setText("Remove prosthesis before")
|
|
||||||
descUI["b1"]:addArg("option", "Nothing")
|
|
||||||
|
|
||||||
else
|
|
||||||
descUI["b1"]:setVisible(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
descUI["status"]:setText("Not cut")
|
|
||||||
descUI["status"]:setColor(1, 1, 1, 1)
|
|
||||||
descUI["b1"]:setVisible(true)
|
|
||||||
descUI["b1"]:setText("Remove prosthesis before")
|
|
||||||
descUI["b1"]:addArg("option", "Nothing")
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Prosthesis Level
|
|
||||||
if string.find(partName, "Right") then
|
|
||||||
local lv = patient:getPerkLevel(Perks.Right_Hand) + 1
|
|
||||||
descUI["textLV2"]:setText("Level: " .. lv .. " / 10")
|
|
||||||
|
|
||||||
local xp = patient:getXp():getXP(Perks.Right_Hand)
|
|
||||||
local min, max = FindMinMax(lv)
|
|
||||||
descUI["pbarNLV"]:setMinMax(min, max)
|
|
||||||
descUI["pbarNLV"]:setValue(xp)
|
|
||||||
else
|
|
||||||
local lv = patient:getPerkLevel(Perks.Left_Hand) + 1
|
|
||||||
descUI["textLV2"]:setText("Level: " .. lv .. " / 10")
|
|
||||||
|
|
||||||
local xp = patient:getXp():getXP(Perks.Left_Hand)
|
|
||||||
local min, max = FindMinMax(lv)
|
|
||||||
descUI["pbarNLV"]:setMinMax(min, max)
|
|
||||||
descUI["pbarNLV"]:setValue(xp)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
-- On Click Functions
|
|
||||||
local function OnClickMainUI(button, args)
|
|
||||||
|
|
||||||
descUI:open()
|
|
||||||
descUI:setPositionPixel(mainUI:getRight(), mainUI:getY())
|
|
||||||
TOC_UI.SetupDescUI(mainUI.surgeon, mainUI.patient, mainUI.limbsData, args.partName) -- surgeon is generic.
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Generic TOC action, used in OnClickDescUI
|
|
||||||
local function TryTOCAction(_, partName, action, surgeon, patient)
|
|
||||||
-- TODO at this point surgeon doesnt do anything. We'll fix this later
|
|
||||||
|
|
||||||
-- Check if SinglePlayer
|
|
||||||
if not isServer() and not isClient() then
|
|
||||||
|
|
||||||
if action == "Cut" then
|
|
||||||
TOC_LocalActions.Cut(_, surgeon, partName)
|
|
||||||
elseif action == "Operate" then
|
|
||||||
TOC_LocalActions.Operate(_, surgeon, partName, false)
|
|
||||||
elseif action == "Equip" then
|
|
||||||
TOC_LocalActions.EquipProsthesis(_, surgeon, partName)
|
|
||||||
elseif action == "Unequip" then
|
|
||||||
TOC_LocalActions.UnequipProsthesis(_, surgeon, partName)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local ui = GetConfirmUIMP()
|
|
||||||
if not ui then
|
|
||||||
CreateConfirmUIMP()
|
|
||||||
ui = GetConfirmUIMP()
|
|
||||||
end
|
|
||||||
|
|
||||||
if patient == nil then
|
|
||||||
patient = surgeon
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if action == "Cut" then
|
|
||||||
AskCanCutLimb(patient, partName)
|
|
||||||
elseif action == "Operate" then
|
|
||||||
AskCanOperateLimb(patient, partName)
|
|
||||||
elseif action == "Equip" then
|
|
||||||
AskCanEquipProsthesis(patient, partName)
|
|
||||||
elseif action == "Unequip" then
|
|
||||||
AskCanUnequipProsthesis(patient, partName)
|
|
||||||
end
|
|
||||||
|
|
||||||
ui.actionAct = action
|
|
||||||
ui.partNameAct = partName
|
|
||||||
ui.patient = patient
|
|
||||||
|
|
||||||
SendCommandToConfirmUIMP("Wait server")
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function OnClickDescUI(button, args)
|
|
||||||
|
|
||||||
-- Gets every arg from main
|
|
||||||
local patient = descUI.patient
|
|
||||||
local surgeon = descUI.surgeon
|
|
||||||
|
|
||||||
if args.option ~= "Nothing" then
|
|
||||||
TryTOCAction(_, descUI.partName, args.option, surgeon, patient)
|
|
||||||
end
|
|
||||||
mainUI:close()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function OnClickConfirmUIMP(button, args)
|
|
||||||
local player = getPlayer()
|
|
||||||
if confirmUIMP.actionAct == "Cut" and args.option == "yes" then
|
|
||||||
ISTimedActionQueue.add(TOC_CutLimbAction:new(confirmUIMP.patient, player, confirmUIMP.partNameAct))
|
|
||||||
elseif confirmUIMP.actionAct == "Operate" and args.option == "yes" then
|
|
||||||
local kit = TOC_Common.GetKitInInventory(player)
|
|
||||||
if kit then
|
|
||||||
ISTimedActionQueue.add(TOC_OperateLimbAction:new(confirmUIMP.patient, player, kit, confirmUIMP.partNameAct,
|
|
||||||
false))
|
|
||||||
else
|
|
||||||
player:Say("I need a kit")
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif confirmUIMP.actionAct == "Equip" and args.option == "yes" then
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO Gonna be broken soon!
|
|
||||||
local surgeon_inventory = player:getInventory()
|
|
||||||
|
|
||||||
local prosthesis_to_equip = surgeon_inventory:getItemFromType('TOC.MetalHand') or
|
|
||||||
surgeon_inventory:getItemFromType('TOC.MetalHook') or
|
|
||||||
surgeon_inventory:getItemFromType('TOC.WoodenHook')
|
|
||||||
|
|
||||||
if prosthesis_to_equip then
|
|
||||||
ISTimedActionQueue.add(TOC_InstallProsthesisAction:new(player, confirmUIMP.patient, prosthesis_to_equip,
|
|
||||||
confirmUIMP.partNameAct))
|
|
||||||
else
|
|
||||||
player:Say("I don't have a prosthesis right now")
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif confirmUIMP.actionAct == "Unequip" and args.option == "yes" then
|
|
||||||
|
|
||||||
-- We can't check if the player has a prosthesis right now, we need to do it later
|
|
||||||
|
|
||||||
-- TODO should check if player has a prosthesis equipped before doing it
|
|
||||||
-- TODO Player is surgeon, but we don't have a confirm_ui_mp.surgeon... awful awful awful
|
|
||||||
-- TODO Workaround for now, we'd need to send data from patient before doing it since we can't access his inventory from the surgeon
|
|
||||||
if confirmUIMP.patient == player then
|
|
||||||
ISTimedActionQueue.add(TOC_UninstallProsthesisAction:new(player, confirmUIMP.patient, confirmUIMP.partNameAct))
|
|
||||||
|
|
||||||
else
|
|
||||||
player:Say("I can't do that, they need to do it themselves")
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
confirmUIMP:close()
|
|
||||||
confirmUIMP.responseReceive = false
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
-- CREATE UI SECTION
|
|
||||||
local function CreateMainUI()
|
|
||||||
mainUI = NewUI()
|
|
||||||
mainUI:setTitle("The Only Cure Menu")
|
|
||||||
mainUI:setWidthPercent(0.1)
|
|
||||||
|
|
||||||
mainUI:addImageButton("b11", "", OnClickMainUI)
|
|
||||||
mainUI["b11"]:addArg("partName", "Right_UpperArm")
|
|
||||||
|
|
||||||
|
|
||||||
mainUI:addImageButton("b12", "", OnClickMainUI)
|
|
||||||
mainUI["b12"]:addArg("partName", "Left_UpperArm")
|
|
||||||
|
|
||||||
mainUI:nextLine()
|
|
||||||
|
|
||||||
mainUI:addImageButton("b21", "", OnClickMainUI)
|
|
||||||
mainUI["b21"]:addArg("partName", "Right_LowerArm")
|
|
||||||
|
|
||||||
|
|
||||||
mainUI:addImageButton("b22", "", OnClickMainUI)
|
|
||||||
mainUI["b22"]:addArg("partName", "Left_LowerArm")
|
|
||||||
|
|
||||||
mainUI:nextLine()
|
|
||||||
|
|
||||||
mainUI:addImageButton("b31", "", OnClickMainUI)
|
|
||||||
mainUI["b31"]:addArg("partName", "Right_Hand")
|
|
||||||
|
|
||||||
mainUI:addImageButton("b32", "", OnClickMainUI)
|
|
||||||
mainUI["b32"]:addArg("partName", "Left_Hand")
|
|
||||||
|
|
||||||
|
|
||||||
mainUI:nextLine()
|
|
||||||
|
|
||||||
mainUI:addImageButton("b41", "", OnClickMainUI)
|
|
||||||
mainUI["b41"]:addArg("partName", "Right_Foot")
|
|
||||||
|
|
||||||
mainUI:addImageButton("b42", "", OnClickMainUI)
|
|
||||||
mainUI["b42"]:addArg("partName", "Left_Foot")
|
|
||||||
|
|
||||||
mainUI:saveLayout()
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create a temporary desc UI with fake data (for now)
|
|
||||||
local function CreateDescUI()
|
|
||||||
descUI = NewUI()
|
|
||||||
descUI:setTitle("The only cure description");
|
|
||||||
descUI:isSubUIOf(mainUI)
|
|
||||||
descUI:setWidthPixel(250)
|
|
||||||
descUI:setColumnWidthPixel(1, 100)
|
|
||||||
|
|
||||||
descUI:addText("textTitle", "Right arm", "Large", "Center")
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addText("textLV2", "Level 3/10", _, "Center")
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addText("textLV", "Next LV:", _, "Right")
|
|
||||||
descUI:addProgressBar("pbarNLV", 39, 0, 100)
|
|
||||||
descUI["pbarNLV"]:setMarginPixel(10, 6)
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addEmpty("border1")
|
|
||||||
descUI:setLineHeightPixel(1)
|
|
||||||
descUI["border1"]:setBorder(true)
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addEmpty()
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addText("status", "Temporary", "Medium", "Center")
|
|
||||||
descUI["status"]:setColor(1, 1, 0, 0)
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addEmpty()
|
|
||||||
descUI:nextLine()
|
|
||||||
|
|
||||||
descUI:addButton("b1", "Operate", OnClickDescUI)
|
|
||||||
|
|
||||||
descUI:saveLayout()
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreateConfirmUIMP()
|
|
||||||
confirmUIMP = NewUI()
|
|
||||||
confirmUIMP.responseReceive = false
|
|
||||||
|
|
||||||
confirmUIMP:addText("text1", "Are you sure?", "Title", "Center");
|
|
||||||
confirmUIMP:setLineHeightPixel(getTextManager():getFontHeight(confirmUIMP.text1.font) + 10)
|
|
||||||
confirmUIMP:nextLine();
|
|
||||||
|
|
||||||
confirmUIMP:addText("text4", "", "Medium", "Center");
|
|
||||||
confirmUIMP:setLineHeightPixel(getTextManager():getFontHeight(confirmUIMP.text4.font) + 10)
|
|
||||||
confirmUIMP:nextLine();
|
|
||||||
|
|
||||||
confirmUIMP:addText("text2", "", _, "Center");
|
|
||||||
confirmUIMP:nextLine();
|
|
||||||
|
|
||||||
confirmUIMP:addText("text3", "", _, "Center");
|
|
||||||
confirmUIMP:nextLine();
|
|
||||||
|
|
||||||
confirmUIMP:addEmpty();
|
|
||||||
confirmUIMP:nextLine();
|
|
||||||
|
|
||||||
confirmUIMP:addEmpty();
|
|
||||||
confirmUIMP:addButton("b1", "Yes", OnClickConfirmUIMP);
|
|
||||||
confirmUIMP.b1:addArg("option", "yes");
|
|
||||||
confirmUIMP:addEmpty();
|
|
||||||
confirmUIMP:addButton("b2", "No", OnClickConfirmUIMP);
|
|
||||||
confirmUIMP:addEmpty();
|
|
||||||
|
|
||||||
confirmUIMP:nextLine();
|
|
||||||
confirmUIMP:addEmpty();
|
|
||||||
|
|
||||||
confirmUIMP:saveLayout();
|
|
||||||
confirmUIMP:addPrerenderFunction(PrerenderFuncMP);
|
|
||||||
confirmUIMP:close();
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- We create everything from here
|
|
||||||
|
|
||||||
TOC_UI.OnCreate = function()
|
|
||||||
CreateMainUI()
|
|
||||||
CreateDescUI()
|
|
||||||
CreateConfirmUIMP()
|
|
||||||
|
|
||||||
if isClient() then CreateConfirmUIMP() end
|
|
||||||
mainUI:close()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------
|
|
||||||
-- MP Confirm (I should add it to client too but hey not sure how it works tbh)
|
|
||||||
|
|
||||||
function SendCommandToConfirmUIMP(action, isBitten, userName, partName)
|
|
||||||
confirmUIMP:setInCenterOfScreen()
|
|
||||||
confirmUIMP:bringToTop()
|
|
||||||
confirmUIMP:open()
|
|
||||||
|
|
||||||
|
|
||||||
if action ~= "Wait server" then
|
|
||||||
confirmUIMP["text4"]:setText("You're gonna " ..
|
|
||||||
action .. " the " .. getText("UI_ContextMenu_" .. partName) .. " of " .. userName)
|
|
||||||
|
|
||||||
confirmUIMP["text2"]:setText("Are you sure?")
|
|
||||||
confirmUIMP["text2"]:setColor(1, 0, 0, 0)
|
|
||||||
confirmUIMP["b1"]:setVisible(true)
|
|
||||||
confirmUIMP["b2"]:setVisible(true)
|
|
||||||
else
|
|
||||||
|
|
||||||
confirmUIMP["text4"]:setText(action)
|
|
||||||
confirmUIMP["text3"]:setText("")
|
|
||||||
confirmUIMP["text2"]:setText("")
|
|
||||||
confirmUIMP["b1"]:setVisible(false)
|
|
||||||
confirmUIMP["b2"]:setVisible(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--------------------------------------------
|
|
||||||
-- Add TOC element to Health Panel
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TOC_UI.onlineTempTable = {patient = nil, surgeon = nil}
|
|
||||||
|
|
||||||
TOC.RefreshClientMenu = function(_)
|
|
||||||
if mainUI:getIsVisible() == false then
|
|
||||||
Events.OnTick.Remove(TOC.RefreshClientMenu)
|
|
||||||
TOC_UI.onlineTempTable.patient = nil
|
|
||||||
TOC_UI.onlineTempTable.surgeon = nil
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
local limbs_data = TOC_UI.onlineTempTable.patient:getModData().TOC.limbs
|
|
||||||
TOC_UI.SetupMainUI(TOC_UI.onlineTempTable.patient, TOC_UI.onlineTempTable.patient, limbs_data)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
TOC.RefreshOtherPlayerMenu = function(_)
|
|
||||||
|
|
||||||
if mainUI:getIsVisible() == false then
|
|
||||||
|
|
||||||
Events.OnTick.Remove(TOC.RefreshOtherPlayerMenu)
|
|
||||||
TOC_UI.onlineTempTable.patient = nil
|
|
||||||
TOC_UI.onlineTempTable.surgeon = nil
|
|
||||||
|
|
||||||
else
|
|
||||||
if ModData.get("TOC_PLAYER_DATA")[TOC_UI.onlineTempTable.patient:getUsername()] ~= nil then
|
|
||||||
local otherPlayerPartData = ModData.get("TOC_PLAYER_DATA")[TOC_UI.onlineTempTable.patient:getUsername()]
|
|
||||||
|
|
||||||
TOC_UI.SetupMainUI(TOC_UI.onlineTempTable.surgeon, TOC_UI.onlineTempTable.patient, otherPlayerPartData[1])
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local ISHealthPanel_createChildren = ISHealthPanel.createChildren
|
|
||||||
local ISHealthPanel_render = ISHealthPanel.render
|
|
||||||
-- Add button to health panel
|
|
||||||
function ISNewHealthPanel.onClickTOC(button)
|
|
||||||
|
|
||||||
local surgeon = button.otherPlayer
|
|
||||||
local patient = button.character
|
|
||||||
|
|
||||||
TOC_UI.onlineTempTable.patient = patient
|
|
||||||
TOC_UI.onlineTempTable.surgeon = surgeon
|
|
||||||
|
|
||||||
-- MP Handling
|
|
||||||
if surgeon then
|
|
||||||
|
|
||||||
|
|
||||||
if surgeon == patient then
|
|
||||||
Events.OnTick.Add(TOC.RefreshClientMenu)
|
|
||||||
|
|
||||||
else
|
|
||||||
Events.OnTick.Add(TOC.RefreshOtherPlayerMenu) -- MP stuff, try to get the other player data and display it on the surgeon display
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- SP Handling
|
|
||||||
Events.OnTick.Add(TOC.RefreshClientMenu)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Set the correct main title
|
|
||||||
-- TODO sizes of the menu are strange in MP, they're not consistent with SP
|
|
||||||
local separatedUsername = {}
|
|
||||||
|
|
||||||
for v in string.gmatch(patient:getUsername(), "%u%l+") do
|
|
||||||
table.insert(separatedUsername, v)
|
|
||||||
end
|
|
||||||
|
|
||||||
local main_title
|
|
||||||
if separatedUsername[1] == nil then
|
|
||||||
main_title = patient:getUsername() .. " - TOC"
|
|
||||||
else
|
|
||||||
main_title = separatedUsername[1] .. " " .. separatedUsername[2] .. " - TOC"
|
|
||||||
end
|
|
||||||
|
|
||||||
mainUI:setTitle(main_title)
|
|
||||||
|
|
||||||
mainUI:toggle()
|
|
||||||
mainUI:setInCenterOfScreen()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function ISHealthPanel:createChildren()
|
|
||||||
ISHealthPanel_createChildren(self)
|
|
||||||
|
|
||||||
self.fitness:setWidth(self.fitness:getWidth() / 1.4)
|
|
||||||
|
|
||||||
self.TOCButton = ISButton:new(self.fitness:getRight() + 10, self.healthPanel.y, 60, 20, "", self,
|
|
||||||
ISNewHealthPanel.onClickTOC)
|
|
||||||
self.TOCButton:setImage(getTexture("media/ui/TOC/iconForMenu.png"))
|
|
||||||
self.TOCButton.anchorTop = false
|
|
||||||
self.TOCButton.anchorBottom = true
|
|
||||||
self.TOCButton:initialise()
|
|
||||||
self.TOCButton:instantiate()
|
|
||||||
self:addChild(self.TOCButton)
|
|
||||||
if getCore():getGameMode() == "Tutorial" then
|
|
||||||
self.TOCButton:setVisible(false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ISHealthPanel:render()
|
|
||||||
ISHealthPanel_render(self);
|
|
||||||
self.TOCButton:setY(self.fitness:getY());
|
|
||||||
end
|
|
||||||
|
|
||||||
-- EVENTS
|
|
||||||
Events.OnCreateUI.Add(TOC_UI.OnCreate)
|
|
||||||
50
media/lua/client/TOC/API.lua
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
------------------------------------------
|
||||||
|
-- Compatibility Handler by Dhert
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
|
||||||
|
|
||||||
|
local TOC_Compat = {}
|
||||||
|
|
||||||
|
-- Raw access, must pass valid part
|
||||||
|
--- @param player IsoPlayer
|
||||||
|
--- @param part string
|
||||||
|
--- @return boolean
|
||||||
|
function TOC_Compat.hasPart(player, part)
|
||||||
|
if not player or not part then return false end
|
||||||
|
local dc = DataController.GetInstance(player:getUsername())
|
||||||
|
if not dc then return false end
|
||||||
|
return (dc:getIsCut(part) and dc:getIsProstEquipped(part)) or not dc:getIsCut(part)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if hand is available
|
||||||
|
---@param player IsoPlayer
|
||||||
|
---@param left boolean Optional
|
||||||
|
---@return boolean
|
||||||
|
function TOC_Compat.hasHand(player, left)
|
||||||
|
return TOC_Compat.hasPart(player, ((left and StaticData.LIMBS_IND_STR.Hand_L) or StaticData.LIMBS_IND_STR.Hand_R))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if both hands are available
|
||||||
|
---@param player IsoPlayer
|
||||||
|
---@return boolean
|
||||||
|
function TOC_Compat.hasBothHands(player)
|
||||||
|
return TOC_Compat.hasHand(player, false) and TOC_Compat.hasHand(player, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- This returns a number for the hands that you have
|
||||||
|
----- 11 == both hands
|
||||||
|
----- 10 == left hand
|
||||||
|
----- 01 (1) == right hand
|
||||||
|
----- 00 (0) == no hands
|
||||||
|
---@param player any
|
||||||
|
---@return integer
|
||||||
|
function TOC_Compat.getHands(player)
|
||||||
|
return ((TOC_Compat.hasHand(player, false) and 1) or 0) + ((TOC_Compat.hasHand(player, true) and 10) or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return TOC_Compat
|
||||||
114
media/lua/client/TOC/Admin.lua
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
local CommandsData = require("TOC/CommandsData")
|
||||||
|
local ClientRelayCommands = require("TOC/ClientRelayCommands")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
---@param playerNum number
|
||||||
|
---@param context ISContextMenu
|
||||||
|
---@param worldobjects table
|
||||||
|
local function AddAdminTocOptions(playerNum, context, worldobjects)
|
||||||
|
|
||||||
|
if (isClient() and not isDebugEnabled()) or isAdmin() then return end
|
||||||
|
|
||||||
|
local players = {}
|
||||||
|
for _, v in ipairs(worldobjects) do
|
||||||
|
for x = v:getSquare():getX() - 1, v:getSquare():getX() + 1 do
|
||||||
|
for y = v:getSquare():getY() - 1, v:getSquare():getY() + 1 do
|
||||||
|
local sq = getCell():getGridSquare(x, y, v:getSquare():getZ());
|
||||||
|
if sq then
|
||||||
|
for z = 0, sq:getMovingObjects():size() - 1 do
|
||||||
|
local o = sq:getMovingObjects():get(z)
|
||||||
|
if instanceof(o, "IsoPlayer") then
|
||||||
|
---@cast o IsoPlayer
|
||||||
|
|
||||||
|
local oId = o:getOnlineID()
|
||||||
|
players[oId] = o
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
for _, pl in pairs(players) do
|
||||||
|
---@cast pl IsoPlayer
|
||||||
|
|
||||||
|
local clickedPlayerNum = pl:getOnlineID()
|
||||||
|
|
||||||
|
local option = context:addOption(getText("ContextMenu_Admin_TOC") .. " - " .. pl:getUsername(), nil, nil)
|
||||||
|
local subMenu = ISContextMenu:getNew(context)
|
||||||
|
context:addSubMenu(option, subMenu)
|
||||||
|
|
||||||
|
subMenu:addOption(getText("ContextMenu_Admin_ResetTOC"), nil, function()
|
||||||
|
if isClient() then
|
||||||
|
sendClientCommand(CommandsData.modules.TOC_RELAY, CommandsData.server.Relay.RelayExecuteInitialization,
|
||||||
|
{ patientNum = clickedPlayerNum })
|
||||||
|
else
|
||||||
|
-- TODO ugly
|
||||||
|
ClientRelayCommands.ReceiveExecuteInitialization()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Force amputation
|
||||||
|
local forceAmpOption = subMenu:addOption(getText("ContextMenu_Admin_ForceAmputation"), nil, nil)
|
||||||
|
local forceAmpSubMenu = ISContextMenu:getNew(subMenu)
|
||||||
|
context:addSubMenu(forceAmpOption, forceAmpSubMenu)
|
||||||
|
|
||||||
|
for i = 1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
local limbTranslatedName = getText("ContextMenu_Limb_" .. limbName)
|
||||||
|
|
||||||
|
forceAmpSubMenu:addOption(limbTranslatedName, nil, function()
|
||||||
|
if isClient() then
|
||||||
|
sendClientCommand(CommandsData.modules.TOC_RELAY, CommandsData.server.Relay.RelayForcedAmputation,
|
||||||
|
{ patientNum = clickedPlayerNum, limbName = limbName })
|
||||||
|
else
|
||||||
|
ClientRelayCommands.ReceiveExecuteAmputationAction({surgeonNum=clickedPlayerNum, limbName=limbName, damagePlayer=false})
|
||||||
|
-- todo ugly
|
||||||
|
end
|
||||||
|
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Events.OnFillWorldObjectContextMenu.Add(AddAdminTocOptions)
|
||||||
|
|
||||||
|
|
||||||
|
--* Override to cheats to fix stuff
|
||||||
|
|
||||||
|
local og_ISHealthPanel_onCheatCurrentPlayer = ISHealthPanel.onCheatCurrentPlayer
|
||||||
|
|
||||||
|
---Override to onCheatCurrentPlayer to fix behaviour with TOC
|
||||||
|
---@param bodyPart BodyPart
|
||||||
|
---@param action any
|
||||||
|
---@param player IsoPlayer
|
||||||
|
function ISHealthPanel.onCheatCurrentPlayer(bodyPart, action, player)
|
||||||
|
og_ISHealthPanel_onCheatCurrentPlayer(bodyPart, action, player)
|
||||||
|
local bptString = BodyPartType.ToString(bodyPart:getType())
|
||||||
|
|
||||||
|
if action == "healthFullBody" then
|
||||||
|
-- loop all limbs and reset them if infected
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
|
||||||
|
for i = 1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
|
||||||
|
dcInst:setIsInfected(limbName, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
dcInst:setIsIgnoredPartInfected(false)
|
||||||
|
|
||||||
|
dcInst:apply()
|
||||||
|
end
|
||||||
|
|
||||||
|
if action == "healthFull" then
|
||||||
|
-- Get the limbName for that BodyPart and fix the values in TOC Data
|
||||||
|
local limbName = StaticData.BODYLOCS_TO_LIMBS_IND_STR[bptString]
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
|
||||||
|
dcInst:setIsInfected(limbName, false)
|
||||||
|
dcInst:apply()
|
||||||
|
end
|
||||||
|
end
|
||||||
77
media/lua/client/TOC/ClientRelayCommands.lua
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
local CommandsData = require("TOC/CommandsData")
|
||||||
|
local AmputationHandler = require("TOC/Handlers/AmputationHandler")
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
local ClientRelayCommands = {}
|
||||||
|
|
||||||
|
---Initialize Amputation Handler
|
||||||
|
---@param limbName any
|
||||||
|
---@param surgeonNum any
|
||||||
|
---@return AmputationHandler
|
||||||
|
local function InitAmputationHandler(limbName, surgeonNum)
|
||||||
|
|
||||||
|
-- TODO Pretty unclean
|
||||||
|
local surgeonPl = getSpecificPlayer(surgeonNum)
|
||||||
|
local handler = AmputationHandler:new(limbName, surgeonPl)
|
||||||
|
return handler
|
||||||
|
end
|
||||||
|
|
||||||
|
---Receive the damage from another player during the amputation
|
||||||
|
---@param args receiveDamageDuringAmputationParams
|
||||||
|
function ClientRelayCommands.ReceiveDamageDuringAmputation(args)
|
||||||
|
AmputationHandler.ApplyDamageDuringAmputation(getPlayer(), args.limbName)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Creates a new handler and execute the amputation function on this client
|
||||||
|
---@param args receiveExecuteAmputationActionParams
|
||||||
|
function ClientRelayCommands.ReceiveExecuteAmputationAction(args)
|
||||||
|
|
||||||
|
-- Check if player already doesn't have that limb or it's a dependant limb.
|
||||||
|
-- Mostly a check for admin forced amputations more than anything else, since this case is handled in the GUI already.
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
if dcInst:getIsCut(args.limbName) then return end
|
||||||
|
|
||||||
|
local handler = InitAmputationHandler(args.limbName, args.surgeonNum)
|
||||||
|
handler:execute(args.damagePlayer)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--* APPLY RELAY *--
|
||||||
|
|
||||||
|
function ClientRelayCommands.ReceiveApplyFromServer()
|
||||||
|
TOC_DEBUG.print("Received forced re-apply from server")
|
||||||
|
local key = CommandsData.GetKey(getPlayer():getUsername())
|
||||||
|
ModData.request(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--* TRIGGERED BY ADMINS *--
|
||||||
|
|
||||||
|
function ClientRelayCommands.ReceiveExecuteInitialization()
|
||||||
|
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
|
||||||
|
LocalPlayerController.InitializePlayer(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Creates a new handler and execute the amputation function on this client
|
||||||
|
---@param args receiveForcedCicatrizationParams
|
||||||
|
function ClientRelayCommands.ReceiveForcedCicatrization(args)
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
--dcInst:setCicatrizationTime(args.limbName, 1)
|
||||||
|
dcInst:setIsCicatrized(args.limbName, true)
|
||||||
|
dcInst:apply()
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
local function OnServerRelayCommand(module, command, args)
|
||||||
|
if module == CommandsData.modules.TOC_RELAY and ClientRelayCommands[command] then
|
||||||
|
TOC_DEBUG.print("Received Server Relay command - " .. tostring(command))
|
||||||
|
ClientRelayCommands[command](args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Events.OnServerCommand.Add(OnServerRelayCommand)
|
||||||
|
|
||||||
|
-- TODO temporary
|
||||||
|
return ClientRelayCommands
|
||||||
48
media/lua/client/TOC/CommonMethods.lua
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
local CommonMethods = {}
|
||||||
|
|
||||||
|
---@param val number
|
||||||
|
---@param min number
|
||||||
|
---@param max number
|
||||||
|
function CommonMethods.Normalize(val, min, max)
|
||||||
|
if (max - min) == 0 then return 1 end
|
||||||
|
return (val - min)/(max-min)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function CommonMethods.GetLimbNameFromBodyPart(bodyPart)
|
||||||
|
local bodyPartTypeStr = BodyPartType.ToString(bodyPart:getType())
|
||||||
|
return StaticData.LIMBS_IND_STR[bodyPartTypeStr]
|
||||||
|
end
|
||||||
|
|
||||||
|
---Returns the side for a certain limb or prosthesis
|
||||||
|
---@param name string
|
||||||
|
---@return string "L" or "R"
|
||||||
|
function CommonMethods.GetSide(name)
|
||||||
|
if string.find(name, "_L") then return "L" else return "R" end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Returns full name for the side, to be used with BodyLocations
|
||||||
|
---@param side string
|
||||||
|
---@return string?
|
||||||
|
function CommonMethods.GetSideFull(side)
|
||||||
|
if side == 'R' then
|
||||||
|
return "Right"
|
||||||
|
elseif side == 'L' then
|
||||||
|
return 'Left'
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---Stops and start an event, making sure that we don't stack them up
|
||||||
|
---@param event string
|
||||||
|
---@param method function
|
||||||
|
function CommonMethods.SafeStartEvent(event, method)
|
||||||
|
Events[event].Remove(method)
|
||||||
|
Events[event].Add(method)
|
||||||
|
end
|
||||||
|
|
||||||
|
return CommonMethods
|
||||||
75
media/lua/client/TOC/Compat.lua
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
---@class Compat
|
||||||
|
---@field handlers table<string, {fun : function, isActive : boolean}>
|
||||||
|
local Compat = {
|
||||||
|
handlers = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Brutal hands has a TOC_COMPAT but its check is wrong and uses an old API.
|
||||||
|
function Compat.BrutalHandwork()
|
||||||
|
BrutalHands = BrutalHands or {}
|
||||||
|
BrutalHands.TOC = require("TOC/API")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Was handled inside old TOC
|
||||||
|
function Compat.FancyHandwork()
|
||||||
|
require("TimedActions/FHSwapHandsAction")
|
||||||
|
local og_FHSwapHandsAction_isValid = FHSwapHandsAction.isValid
|
||||||
|
function FHSwapHandsAction:isValid()
|
||||||
|
local tocApi = require("TOC/API")
|
||||||
|
if tocApi.hasBothHands(self.character) then
|
||||||
|
return og_FHSwapHandsAction_isValid(self)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Compat.iMeds()
|
||||||
|
require("Component/Interface/Service/ContextMenu/Menu/HealthPanel/HealthPanelMenuInitializer")
|
||||||
|
-- placeholder, in case we need to do something more drastic with it.
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Compat.handlers = {
|
||||||
|
["BrutalHandwork"] = {
|
||||||
|
fun = Compat.BrutalHandwork,
|
||||||
|
isActive = false},
|
||||||
|
["FancyHandwork"] = {
|
||||||
|
fun = Compat.FancyHandwork,
|
||||||
|
isActive = false},
|
||||||
|
|
||||||
|
-- either or
|
||||||
|
['iMeds'] = {
|
||||||
|
fun = Compat.iMeds,
|
||||||
|
isActive = false},
|
||||||
|
['iMedsFixed'] = {
|
||||||
|
fun = Compat.iMeds,
|
||||||
|
isActive = false}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function Compat.RunModCompatibility()
|
||||||
|
local activatedMods = getActivatedMods()
|
||||||
|
TOC_DEBUG.print("Checking for mods compatibility")
|
||||||
|
|
||||||
|
for k, modCompatHandler in pairs(Compat.handlers) do
|
||||||
|
if activatedMods:contains(k) then
|
||||||
|
TOC_DEBUG.print("Found " .. k .. ", running compatibility handler")
|
||||||
|
modCompatHandler.fun()
|
||||||
|
modCompatHandler.isActive = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Events.OnGameStart.Add(Compat.RunModCompatibility)
|
||||||
|
|
||||||
|
return Compat
|
||||||
491
media/lua/client/TOC/Controllers/DataController.lua
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
if isServer() then return end
|
||||||
|
|
||||||
|
local CommandsData = require("TOC/CommandsData")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
----------------
|
||||||
|
|
||||||
|
--- An instance will be abbreviated with dcInst
|
||||||
|
|
||||||
|
|
||||||
|
--- Handle all TOC mod data related stuff
|
||||||
|
---@class DataController
|
||||||
|
---@field username string
|
||||||
|
---@field tocData tocModDataType
|
||||||
|
---@field isDataReady boolean
|
||||||
|
---@field isResetForced boolean
|
||||||
|
local DataController = {}
|
||||||
|
DataController.instances = {}
|
||||||
|
|
||||||
|
---Setup a new Mod Data Handler
|
||||||
|
---@param username string
|
||||||
|
---@param isResetForced boolean?
|
||||||
|
---@return DataController
|
||||||
|
function DataController:new(username, isResetForced)
|
||||||
|
TOC_DEBUG.print("Creating new DataController instance for " .. username)
|
||||||
|
---@type DataController
|
||||||
|
---@diagnostic disable-next-line: missing-fields
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
|
||||||
|
o.username = username
|
||||||
|
o.isResetForced = isResetForced or false
|
||||||
|
o.isDataReady = false
|
||||||
|
|
||||||
|
-- We're gonna set it already from here, to prevent it from looping in SP (in case we need to fetch this instance)
|
||||||
|
DataController.instances[username] = o
|
||||||
|
|
||||||
|
local key = CommandsData.GetKey(username)
|
||||||
|
|
||||||
|
if isClient() then
|
||||||
|
-- In MP, we request the data from the server to trigger DataController.ReceiveData
|
||||||
|
ModData.request(key)
|
||||||
|
else
|
||||||
|
-- In SP, we handle it with another function which will reference the saved instance in DataController.instances
|
||||||
|
o:initSinglePlayer(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Setup a new toc mod data data class
|
||||||
|
---@param key string
|
||||||
|
function DataController:setup(key)
|
||||||
|
TOC_DEBUG.print("Running setup")
|
||||||
|
|
||||||
|
---@type tocModDataType
|
||||||
|
self.tocData = {
|
||||||
|
-- Generic stuff that does not belong anywhere else
|
||||||
|
isInitializing = true,
|
||||||
|
isIgnoredPartInfected = false,
|
||||||
|
isAnyLimbCut = false,
|
||||||
|
limbs = {},
|
||||||
|
prostheses = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
---@type partDataType
|
||||||
|
local defaultParams = {
|
||||||
|
isCut = false, isInfected = false, isOperated = false, isCicatrized = false, isCauterized = false,
|
||||||
|
woundDirtyness = -1, cicatrizationTime = -1,
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Initialize limbs
|
||||||
|
for i=1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
self.tocData.limbs[limbName] = {}
|
||||||
|
self:setLimbParams(StaticData.LIMBS_STR[i], defaultParams, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize prostheses stuff
|
||||||
|
for i=1, #StaticData.AMP_GROUPS_STR do
|
||||||
|
local group = StaticData.AMP_GROUPS_STR[i]
|
||||||
|
self.tocData.prostheses[group] = {
|
||||||
|
isProstEquipped = false,
|
||||||
|
prostFactor = 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add it to client global mod data
|
||||||
|
ModData.add(key, self.tocData)
|
||||||
|
|
||||||
|
-- Sync with the server
|
||||||
|
self:apply()
|
||||||
|
|
||||||
|
-- -- Disable lock
|
||||||
|
-- self.tocData.isInitializing = false
|
||||||
|
-- ModData.add(key, self.tocData)
|
||||||
|
|
||||||
|
triggerEvent("OnSetupTocData")
|
||||||
|
end
|
||||||
|
|
||||||
|
---In case of desync between the table on ModData and the table here
|
||||||
|
---@param tocData tocModDataType
|
||||||
|
function DataController:applyOnlineData(tocData)
|
||||||
|
local key = CommandsData.GetKey(self.username)
|
||||||
|
ModData.add(key, tocData)
|
||||||
|
self.tocData = ModData.get(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param key string
|
||||||
|
function DataController:tryLoadLocalData(key)
|
||||||
|
self.tocData = ModData.get(key)
|
||||||
|
|
||||||
|
--TOC_DEBUG.printTable(self.tocData)
|
||||||
|
|
||||||
|
if self.tocData and self.tocData.limbs then
|
||||||
|
TOC_DEBUG.print("Found and loaded local data")
|
||||||
|
else
|
||||||
|
TOC_DEBUG.print("Local data failed to load! Running setup")
|
||||||
|
self:setup(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-----------------
|
||||||
|
--* Setters *--
|
||||||
|
|
||||||
|
---@param isDataReady boolean
|
||||||
|
function DataController:setIsDataReady(isDataReady)
|
||||||
|
self.isDataReady = isDataReady
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param isResetForced boolean
|
||||||
|
function DataController:setIsResetForced(isResetForced)
|
||||||
|
self.isResetForced = isResetForced
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set a generic boolean that toggles varies function of the mod
|
||||||
|
---@param isAnyLimbCut boolean
|
||||||
|
function DataController:setIsAnyLimbCut(isAnyLimbCut)
|
||||||
|
self.tocData.isAnyLimbCut = isAnyLimbCut
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set isIgnoredPartInfected
|
||||||
|
---@param isIgnoredPartInfected boolean
|
||||||
|
function DataController:setIsIgnoredPartInfected(isIgnoredPartInfected)
|
||||||
|
self.tocData.isIgnoredPartInfected = isIgnoredPartInfected
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set isCut
|
||||||
|
---@param limbName string
|
||||||
|
---@param isCut boolean
|
||||||
|
function DataController:setIsCut(limbName, isCut)
|
||||||
|
self.tocData.limbs[limbName].isCut = isCut
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set isInfected
|
||||||
|
---@param limbName string
|
||||||
|
---@param isInfected boolean
|
||||||
|
function DataController:setIsInfected(limbName, isInfected)
|
||||||
|
self.tocData.limbs[limbName].isInfected = isInfected
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set isCicatrized
|
||||||
|
---@param limbName string
|
||||||
|
---@param isCicatrized boolean
|
||||||
|
function DataController:setIsCicatrized(limbName, isCicatrized)
|
||||||
|
self.tocData.limbs[limbName].isCicatrized = isCicatrized
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set isCauterized
|
||||||
|
---@param limbName string
|
||||||
|
---@param isCauterized boolean
|
||||||
|
function DataController:setIsCauterized(limbName, isCauterized)
|
||||||
|
self.tocData.limbs[limbName].isCauterized = isCauterized
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set woundDirtyness
|
||||||
|
---@param limbName string
|
||||||
|
---@param woundDirtyness number
|
||||||
|
function DataController:setWoundDirtyness(limbName, woundDirtyness)
|
||||||
|
self.tocData.limbs[limbName].woundDirtyness = woundDirtyness
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Set cicatrizationTime
|
||||||
|
---@param limbName string
|
||||||
|
---@param cicatrizationTime number
|
||||||
|
function DataController:setCicatrizationTime(limbName, cicatrizationTime)
|
||||||
|
self.tocData.limbs[limbName].cicatrizationTime = cicatrizationTime
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set isProstEquipped
|
||||||
|
---@param group string
|
||||||
|
---@param isProstEquipped boolean
|
||||||
|
function DataController:setIsProstEquipped(group, isProstEquipped)
|
||||||
|
self.tocData.prostheses[group].isProstEquipped = isProstEquipped
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set prostFactor
|
||||||
|
---@param group string
|
||||||
|
---@param prostFactor number
|
||||||
|
function DataController:setProstFactor(group, prostFactor)
|
||||||
|
self.tocData.prostheses[group].prostFactor = prostFactor
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
--* Getters *--
|
||||||
|
|
||||||
|
---comment
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsDataReady()
|
||||||
|
return self.isDataReady
|
||||||
|
end
|
||||||
|
---Set a generic boolean that toggles varies function of the mod
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsAnyLimbCut()
|
||||||
|
if not self.isDataReady then return false end
|
||||||
|
return self.tocData.isAnyLimbCut
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isIgnoredPartInfected
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsIgnoredPartInfected()
|
||||||
|
if not self.isDataReady then return false end
|
||||||
|
return self.tocData.isIgnoredPartInfected
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isCut
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsCut(limbName)
|
||||||
|
if not self.isDataReady then return false end
|
||||||
|
if self.tocData.limbs[limbName] then
|
||||||
|
return self.tocData.limbs[limbName].isCut
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isVisible
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsVisible(limbName)
|
||||||
|
if not self.isDataReady then return false end
|
||||||
|
return self.tocData.limbs[limbName].isVisible
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isCicatrized
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsCicatrized(limbName)
|
||||||
|
if not self.isDataReady then return false end
|
||||||
|
return self.tocData.limbs[limbName].isCicatrized
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isCauterized
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsCauterized(limbName)
|
||||||
|
if not self.isDataReady then return false end
|
||||||
|
return self.tocData.limbs[limbName].isCauterized
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isInfected
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsInfected(limbName)
|
||||||
|
return self.tocData.limbs[limbName].isInfected
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get woundDirtyness
|
||||||
|
---@param limbName string
|
||||||
|
---@return number
|
||||||
|
function DataController:getWoundDirtyness(limbName)
|
||||||
|
if not self.isDataReady then return -1 end
|
||||||
|
return self.tocData.limbs[limbName].woundDirtyness
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Get cicatrizationTime
|
||||||
|
---@param limbName string
|
||||||
|
---@return number
|
||||||
|
function DataController:getCicatrizationTime(limbName)
|
||||||
|
if not self.isDataReady then return -1 end
|
||||||
|
return self.tocData.limbs[limbName].cicatrizationTime
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get isProstEquipped
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function DataController:getIsProstEquipped(limbName)
|
||||||
|
local prostGroup = StaticData.LIMBS_TO_AMP_GROUPS_MATCH_IND_STR[limbName]
|
||||||
|
return self.tocData.prostheses[prostGroup].isProstEquipped
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get prostFactor
|
||||||
|
---@param group string
|
||||||
|
---@return number
|
||||||
|
function DataController:getProstFactor(group)
|
||||||
|
return self.tocData.prostheses[group].prostFactor
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Limbs data handling *--
|
||||||
|
|
||||||
|
---Set a limb and its dependend limbs as cut
|
||||||
|
---@param limbName string
|
||||||
|
---@param isOperated boolean
|
||||||
|
---@param isCicatrized boolean
|
||||||
|
---@param isCauterized boolean
|
||||||
|
---@param surgeonFactor number?
|
||||||
|
function DataController:setCutLimb(limbName, isOperated, isCicatrized, isCauterized, surgeonFactor)
|
||||||
|
local cicatrizationTime = 0
|
||||||
|
if isCicatrized == false or isCauterized == false then
|
||||||
|
cicatrizationTime = StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[limbName] - surgeonFactor
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type partDataType
|
||||||
|
local params = {isCut = true, isInfected = false, isOperated = isOperated, isCicatrized = isCicatrized, isCauterized = isCauterized, woundDirtyness = 0, isVisible = true}
|
||||||
|
self:setLimbParams(limbName, params, cicatrizationTime)
|
||||||
|
|
||||||
|
for i=1, #StaticData.LIMBS_DEPENDENCIES_IND_STR[limbName] do
|
||||||
|
local dependedLimbName = StaticData.LIMBS_DEPENDENCIES_IND_STR[limbName][i]
|
||||||
|
|
||||||
|
-- We don't care about isOperated, isCicatrized, isCauterized since this is depending on another limb
|
||||||
|
-- Same story for cicatrizationTime, which will be 0
|
||||||
|
-- isCicatrized is to true to prevent it from doing the cicatrization process
|
||||||
|
self:setLimbParams(dependedLimbName, {isCut = true, isInfected = false, isVisible = false, isCicatrized = true}, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set that a limb has been cut, to activate some functions without having to loop through the parts
|
||||||
|
self:setIsAnyLimbCut(true)
|
||||||
|
|
||||||
|
-- TODO In theory we should cache data from here, not AmputationHandler
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set a limb data
|
||||||
|
---@param limbName string
|
||||||
|
---@param ampStatus partDataType {isCut, isInfected, isOperated, isCicatrized, isCauterized, isVisible}
|
||||||
|
---@param cicatrizationTime integer?
|
||||||
|
function DataController:setLimbParams(limbName, ampStatus, cicatrizationTime)
|
||||||
|
local limbData = self.tocData.limbs[limbName]
|
||||||
|
if ampStatus.isCut ~= nil then limbData.isCut = ampStatus.isCut end
|
||||||
|
if ampStatus.isInfected ~= nil then limbData.isInfected = ampStatus.isInfected end
|
||||||
|
if ampStatus.isOperated ~= nil then limbData.isOperated = ampStatus.isOperated end
|
||||||
|
if ampStatus.isCicatrized ~= nil then limbData.isCicatrized = ampStatus.isCicatrized end
|
||||||
|
if ampStatus.isCauterized ~= nil then limbData.isCauterized = ampStatus.isCauterized end
|
||||||
|
if ampStatus.woundDirtyness ~= nil then limbData.woundDirtyness = ampStatus.woundDirtyness end
|
||||||
|
if ampStatus.isVisible ~= nil then limbData.isVisible = ampStatus.isVisible end
|
||||||
|
|
||||||
|
if cicatrizationTime ~= nil then limbData.cicatrizationTime = cicatrizationTime end
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Update statuses of a limb *--
|
||||||
|
|
||||||
|
---Decreases the cicatrization time
|
||||||
|
---@param limbName string
|
||||||
|
function DataController:decreaseCicatrizationTime(limbName)
|
||||||
|
self.tocData.limbs[limbName].cicatrizationTime = self.tocData.limbs[limbName].cicatrizationTime - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Global Mod Data Handling *--
|
||||||
|
|
||||||
|
function DataController:apply()
|
||||||
|
TOC_DEBUG.print("Applying data for " .. self.username)
|
||||||
|
ModData.transmit(CommandsData.GetKey(self.username))
|
||||||
|
|
||||||
|
-- if getPlayer():getUsername() ~= self.username then
|
||||||
|
-- sendClientCommand(CommandsData.modules.TOC_RELAY, CommandsData.server.Relay.RelayApplyFromOtherClient, {patientUsername = self.username} )
|
||||||
|
-- -- force request from the server for that other client...
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Online only, Global Mod Data doesn't trigger this in SP
|
||||||
|
---@param key string
|
||||||
|
---@param data tocModDataType
|
||||||
|
function DataController.ReceiveData(key, data)
|
||||||
|
-- During startup the game can return Bob as the player username, adding a useless ModData table
|
||||||
|
if key == "TOC_Bob" then return end
|
||||||
|
if not luautils.stringStarts(key, StaticData.MOD_NAME .. "_") then return end
|
||||||
|
|
||||||
|
|
||||||
|
TOC_DEBUG.print("ReceiveData for " .. key)
|
||||||
|
|
||||||
|
-- if data == nil or data.limbs == nil then
|
||||||
|
-- TOC_DEBUG.print("Data is nil, new character or something is wrong")
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- Get DataController instance if there was none for that user and reapply the correct ModData table as a reference
|
||||||
|
local username = key:sub(5)
|
||||||
|
local handler = DataController.GetInstance(username)
|
||||||
|
|
||||||
|
-- Bit of a workaround, but in a perfect world, I'd use the server to get the data and that would be it.
|
||||||
|
-- but Zomboid Mod Data handling is too finnicky at best to be that reliable, in case of an unwanted disconnection and what not,
|
||||||
|
-- so for now, I'm gonna assume that the local data (for the local client) is the
|
||||||
|
-- most recent (and correct) one instead of trying to fetch it from the server every single time
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO Add update from server scenario
|
||||||
|
|
||||||
|
if handler.isResetForced then
|
||||||
|
TOC_DEBUG.print("Forced reset")
|
||||||
|
handler:setup(key)
|
||||||
|
elseif data and data.limbs then
|
||||||
|
-- Let's validate that the data structure is actually valid to prevent issues
|
||||||
|
if data.isUpdateFromServer then
|
||||||
|
TOC_DEBUG.print("Update from the server")
|
||||||
|
end
|
||||||
|
handler:applyOnlineData(data)
|
||||||
|
elseif username == getPlayer():getUsername() then
|
||||||
|
TOC_DEBUG.print("Trying to load local data or no data is available")
|
||||||
|
handler:tryLoadLocalData(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
handler:setIsResetForced(false)
|
||||||
|
handler:setIsDataReady(true)
|
||||||
|
|
||||||
|
--TOC_DEBUG.print("Finished ReceiveData, triggering OnReceivedTocData")
|
||||||
|
triggerEvent("OnReceivedTocData", handler.username)
|
||||||
|
|
||||||
|
-- TODO We need an event to track if initialization has been finalized
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- if username == getPlayer():getUsername() and not handler.isResetForced then
|
||||||
|
-- handler:loadLocalData(key)
|
||||||
|
-- elseif handler.isResetForced or data == nil then
|
||||||
|
-- TOC_DEBUG.print("Data is nil or empty!?")
|
||||||
|
-- TOC_DEBUG.printTable(data)
|
||||||
|
-- handler:setup(key)
|
||||||
|
-- elseif data and data.limbs then
|
||||||
|
-- handler:applyOnlineData(data)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- handler:setIsResetForced(false)
|
||||||
|
-- handler:setIsDataReady(true)
|
||||||
|
|
||||||
|
-- -- Event, triggers caching
|
||||||
|
-- triggerEvent("OnReceivedTocData", handler.username)
|
||||||
|
|
||||||
|
-- Transmit it back to the server
|
||||||
|
--ModData.transmit(key)
|
||||||
|
--TOC_DEBUG.print("Transmitting data after receiving it for: " .. handler.username)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
Events.OnReceiveGlobalModData.Add(DataController.ReceiveData)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- SP Only initialization
|
||||||
|
---@param key string
|
||||||
|
function DataController:initSinglePlayer(key)
|
||||||
|
self:tryLoadLocalData(key)
|
||||||
|
if self.tocData == nil or self.isResetForced then
|
||||||
|
self:setup(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:setIsDataReady(true)
|
||||||
|
self:setIsResetForced(false)
|
||||||
|
|
||||||
|
-- Event, triggers caching
|
||||||
|
triggerEvent("OnReceivedTocData", self.username)
|
||||||
|
end
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
---@param username string?
|
||||||
|
---@return DataController
|
||||||
|
function DataController.GetInstance(username)
|
||||||
|
if username == nil or username == "Bob" then
|
||||||
|
username = getPlayer():getUsername()
|
||||||
|
end
|
||||||
|
|
||||||
|
if DataController.instances[username] == nil then
|
||||||
|
TOC_DEBUG.print("Creating NEW instance for " .. username)
|
||||||
|
return DataController:new(username)
|
||||||
|
else
|
||||||
|
return DataController.instances[username]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function DataController.DestroyInstance(username)
|
||||||
|
if DataController.instances[username] ~= nil then
|
||||||
|
DataController.instances[username] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return DataController
|
||||||
179
media/lua/client/TOC/Controllers/ItemsController.lua
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
--- Submodule to handle spawning the correct items after certain actions (ie: cutting a hand). LOCAL ONLY!
|
||||||
|
---@class ItemsController
|
||||||
|
local ItemsController = {}
|
||||||
|
|
||||||
|
|
||||||
|
--* Player Methods *--
|
||||||
|
---@class ItemsController.Player
|
||||||
|
ItemsController.Player = {}
|
||||||
|
|
||||||
|
---Returns the correct index for the textures of the amputation
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
---@param isCicatrized boolean
|
||||||
|
---@return number
|
||||||
|
---@private
|
||||||
|
function ItemsController.Player.GetAmputationTexturesIndex(playerObj, isCicatrized)
|
||||||
|
-- FIX Broken
|
||||||
|
local textureString = playerObj:getHumanVisual():getSkinTexture()
|
||||||
|
local isHairy = textureString:sub(-1) == "a"
|
||||||
|
|
||||||
|
local matchedIndex = tonumber(textureString:match("%d%d")) -- it must always be at least 1
|
||||||
|
TOC_DEBUG.print("Texture string: " .. tostring(textureString))
|
||||||
|
|
||||||
|
if isHairy then
|
||||||
|
matchedIndex = matchedIndex + 5
|
||||||
|
end
|
||||||
|
|
||||||
|
if isCicatrized then
|
||||||
|
matchedIndex = matchedIndex + (isHairy and 5 or 10) -- We add 5 is it's the texture, else 10
|
||||||
|
end
|
||||||
|
|
||||||
|
TOC_DEBUG.print("isCicatrized = " .. tostring(isCicatrized))
|
||||||
|
TOC_DEBUG.print("Amputation Texture Index: " .. tostring(matchedIndex))
|
||||||
|
return matchedIndex - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
---Main function to delete a clothing item
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
---@param clothingItem InventoryItem
|
||||||
|
---@return boolean
|
||||||
|
---@private
|
||||||
|
function ItemsController.Player.RemoveClothingItem(playerObj, clothingItem)
|
||||||
|
if clothingItem and instanceof(clothingItem, "InventoryItem") then
|
||||||
|
playerObj:removeWornItem(clothingItem)
|
||||||
|
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
|
playerObj:getInventory():Remove(clothingItem) -- Umbrella is wrong, can be an InventoryItem too
|
||||||
|
TOC_DEBUG.print("found and deleted" .. tostring(clothingItem))
|
||||||
|
|
||||||
|
-- Reset model
|
||||||
|
playerObj:resetModelNextFrame()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
---Search and deletes an old amputation clothing item on the same side
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
function ItemsController.Player.DeleteOldAmputationItem(playerObj, limbName)
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
for partName, _ in pairs(StaticData.PARTS_IND_STR) do
|
||||||
|
local othLimbName = partName .. "_" .. side
|
||||||
|
local othClothingItemName = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. othLimbName
|
||||||
|
|
||||||
|
local othClothingItem = playerObj:getInventory():FindAndReturn(othClothingItemName)
|
||||||
|
|
||||||
|
|
||||||
|
-- If we manage to find and remove an item, then we should stop this function.
|
||||||
|
---@cast othClothingItem InventoryItem
|
||||||
|
if ItemsController.Player.RemoveClothingItem(playerObj, othClothingItem) then return end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Deletes all the old amputation items, used for resets
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
function ItemsController.Player.DeleteAllOldAmputationItems(playerObj)
|
||||||
|
-- This part is a workaround for a pretty shitty implementation on the java side. Check ProsthesisHandler for more infos
|
||||||
|
local group = BodyLocations.getGroup("Human")
|
||||||
|
group:setMultiItem("TOC_Arm", false)
|
||||||
|
group:setMultiItem("TOC_ArmProst", false)
|
||||||
|
|
||||||
|
for i = 1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
local clothItemName = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName
|
||||||
|
local clothItem = playerObj:getInventory():FindAndReturn(clothItemName)
|
||||||
|
---@cast clothItem InventoryItem
|
||||||
|
ItemsController.Player.RemoveClothingItem(playerObj, clothItem)
|
||||||
|
end
|
||||||
|
-- Reset model just in case
|
||||||
|
playerObj:resetModel()
|
||||||
|
|
||||||
|
group:setMultiItem("TOC_Arm", true)
|
||||||
|
group:setMultiItem("TOC_ArmProst", true)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Spawns and equips the correct amputation item to the player.
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
function ItemsController.Player.SpawnAmputationItem(playerObj, limbName)
|
||||||
|
TOC_DEBUG.print("clothing name " .. StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName)
|
||||||
|
local clothingItem = playerObj:getInventory():AddItem(StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName)
|
||||||
|
local texId = ItemsController.Player.GetAmputationTexturesIndex(playerObj, false)
|
||||||
|
|
||||||
|
---@cast clothingItem InventoryItem
|
||||||
|
clothingItem:getVisual():setTextureChoice(texId) -- it counts from 0, so we have to subtract 1
|
||||||
|
playerObj:setWornItem(clothingItem:getBodyLocation(), clothingItem)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Search through worn items and modifies a specific amputation item
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
---@param isCicatrized boolean
|
||||||
|
function ItemsController.Player.OverrideAmputationItemVisuals(playerObj, limbName, isCicatrized)
|
||||||
|
local wornItems = playerObj:getWornItems()
|
||||||
|
local fullType = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName
|
||||||
|
|
||||||
|
for i = 1, wornItems:size() do
|
||||||
|
local it = wornItems:get(i - 1)
|
||||||
|
if it then
|
||||||
|
local wornItem = wornItems:get(i - 1):getItem()
|
||||||
|
TOC_DEBUG.print(wornItem:getFullType())
|
||||||
|
if wornItem:getFullType() == fullType then
|
||||||
|
TOC_DEBUG.print("Found amputation item for " .. limbName)
|
||||||
|
|
||||||
|
-- change it here
|
||||||
|
local texId = ItemsController.Player.GetAmputationTexturesIndex(playerObj, isCicatrized)
|
||||||
|
wornItem:getVisual():setTextureChoice(texId)
|
||||||
|
playerObj:resetModelNextFrame() -- necessary to update the model
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Zombie Methods *--
|
||||||
|
---@class ItemsController.Zombie
|
||||||
|
ItemsController.Zombie = {}
|
||||||
|
|
||||||
|
---Set an amputation to a zombie
|
||||||
|
---@param zombie IsoZombie
|
||||||
|
---@param amputationFullType string Full Type
|
||||||
|
function ItemsController.Zombie.SpawnAmputationItem(zombie, amputationFullType)
|
||||||
|
local texId = ItemsController.Zombie.GetAmputationTexturesIndex(zombie)
|
||||||
|
local zombieVisuals = zombie:getItemVisuals()
|
||||||
|
local itemVisual = ItemVisual:new()
|
||||||
|
itemVisual:setItemType(amputationFullType)
|
||||||
|
itemVisual:setTextureChoice(texId)
|
||||||
|
if zombieVisuals then zombieVisuals:add(itemVisual) end
|
||||||
|
zombie:resetModelNextFrame()
|
||||||
|
|
||||||
|
-- Spawn the item too in the inventory to keep track of stuff this way. It's gonna get deleted when we reload the game
|
||||||
|
local zombieInv = zombie:getInventory()
|
||||||
|
zombieInv:AddItem(amputationFullType)
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO Remove objects in that part of the body to prevent items floating in mid air
|
||||||
|
end
|
||||||
|
|
||||||
|
function ItemsController.Zombie.GetAmputationTexturesIndex(zombie)
|
||||||
|
local x = zombie:getHumanVisual():getSkinTexture()
|
||||||
|
|
||||||
|
-- Starting ID for zombies = 20
|
||||||
|
-- 3 levels
|
||||||
|
local matchedIndex = tonumber(x:match("ZedBody0(%d)")) - 1
|
||||||
|
matchedIndex = matchedIndex * 3
|
||||||
|
|
||||||
|
local level = tonumber(x:match("%d$")) - 1 -- it's from 1 to 3, but we're using it like 0 indexed arrays
|
||||||
|
|
||||||
|
local finalId = 20 + matchedIndex + level
|
||||||
|
--print("Zombie texture index: " .. tostring(finalId))
|
||||||
|
return finalId
|
||||||
|
end
|
||||||
|
|
||||||
|
return ItemsController
|
||||||
369
media/lua/client/TOC/Controllers/LimitActionsController.lua
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
|
||||||
|
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
|
||||||
|
--* TIMED ACTIONS *--
|
||||||
|
-- We want to be able to modify how long actions are gonna take,
|
||||||
|
-- depending on amputation status and kind of action. Also, when the
|
||||||
|
-- player has not completely cicatrized their own wounds, and try to do any action with
|
||||||
|
-- a prosthesis on, that can trigger random bleeds.
|
||||||
|
|
||||||
|
local function CheckHandFeasibility(limbName)
|
||||||
|
TOC_DEBUG.print("Checking hand feasibility: " .. limbName)
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
|
||||||
|
local isFeasible = not dcInst:getIsCut(limbName) or dcInst:getIsProstEquipped(limbName)
|
||||||
|
TOC_DEBUG.print("isFeasible: " .. tostring(isFeasible))
|
||||||
|
return isFeasible
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--* Time to perform actions overrides *--
|
||||||
|
local og_ISBaseTimedAction_adjustMaxTime = ISBaseTimedAction.adjustMaxTime
|
||||||
|
--- Adjust time
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
function ISBaseTimedAction:adjustMaxTime(maxTime)
|
||||||
|
local time = og_ISBaseTimedAction_adjustMaxTime(self, maxTime)
|
||||||
|
|
||||||
|
-- Exceptions handling, if we find that parameter then we just use the original time
|
||||||
|
local actionsQueue = ISTimedActionQueue.getTimedActionQueue(getPlayer())
|
||||||
|
|
||||||
|
if actionsQueue and actionsQueue.current and actionsQueue.skipTOC then
|
||||||
|
--TOC_DEBUG.print("Should skip TOC stuff")
|
||||||
|
return time
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Action is valid, check if we have any cut limb and then modify maxTime
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
if time ~= -1 and dcInst and dcInst:getIsAnyLimbCut() then
|
||||||
|
--TOC_DEBUG.print("Overriding adjustMaxTime")
|
||||||
|
local pl = getPlayer()
|
||||||
|
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(pl:getUsername())
|
||||||
|
|
||||||
|
for k, _ in pairs(amputatedLimbs) do
|
||||||
|
local limbName = k
|
||||||
|
local perkAmp = Perks["Side_" .. CommonMethods.GetSide(limbName)]
|
||||||
|
local perkLevel = pl:getPerkLevel(perkAmp)
|
||||||
|
|
||||||
|
if dcInst:getIsProstEquipped(limbName) then
|
||||||
|
-- TODO We should separate this in multiple perks, since this is gonna be a generic familiarity and could make no actual sense
|
||||||
|
local perkProst = Perks["ProstFamiliarity"]
|
||||||
|
perkLevel = perkLevel + pl:getPerkLevel(perkProst)
|
||||||
|
end
|
||||||
|
|
||||||
|
local perkLevelScaled
|
||||||
|
if perkLevel ~= 0 then perkLevelScaled = perkLevel / 10 else perkLevelScaled = 0 end
|
||||||
|
TOC_DEBUG.print("Perk Level: " .. tostring(perkLevel))
|
||||||
|
TOC_DEBUG.print("OG time: " .. tostring(time))
|
||||||
|
|
||||||
|
-- Modified Time shouldn't EVER be lower compared to the og one.
|
||||||
|
local modifiedTime = time * (StaticData.LIMBS_TIME_MULTIPLIER_IND_NUM[limbName] - perkLevelScaled)
|
||||||
|
|
||||||
|
if modifiedTime >= time then
|
||||||
|
time = modifiedTime
|
||||||
|
end
|
||||||
|
|
||||||
|
--TOC_DEBUG.print("Modified time: " .. tostring(time))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--TOC_DEBUG.print("New time with amputations: " .. tostring(time))
|
||||||
|
return time
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Random bleeding during cicatrization + Perks leveling override *--
|
||||||
|
local og_ISBaseTimedAction_perform = ISBaseTimedAction.perform
|
||||||
|
--- After each action, level up perks
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
function ISBaseTimedAction:perform()
|
||||||
|
og_ISBaseTimedAction_perform(self)
|
||||||
|
|
||||||
|
TOC_DEBUG.print("Running ISBaseTimedAction.perform override")
|
||||||
|
TOC_DEBUG.print("max time: " .. tostring(self.maxTime))
|
||||||
|
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
if not dcInst:getIsAnyLimbCut() then return end
|
||||||
|
|
||||||
|
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(LocalPlayerController.username)
|
||||||
|
local xp = self.maxTime / 100
|
||||||
|
for k, _ in pairs(amputatedLimbs) do
|
||||||
|
local limbName = k
|
||||||
|
|
||||||
|
-- We're checking for only "visible" amputations to prevent from having bleeds everywhere
|
||||||
|
if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
LocalPlayerController.playerObj:getXp():AddXP(Perks["Side_" .. side], xp)
|
||||||
|
if not dcInst:getIsCicatrized(limbName) and dcInst:getIsProstEquipped(limbName) then
|
||||||
|
TOC_DEBUG.print("Trying for bleed, player met the criteria")
|
||||||
|
LocalPlayerController.TryRandomBleed(self.character, limbName)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Level up prosthesis perk
|
||||||
|
if dcInst:getIsProstEquipped(limbName) then
|
||||||
|
LocalPlayerController.playerObj:getXp():AddXP(Perks["ProstFamiliarity"], xp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--* EQUIPPING ITEMS *--
|
||||||
|
-- Check wheter the player can equip items or not, for example dual wielding when you only have one
|
||||||
|
-- hand (and no prosthesis) should be disabled. Same thing for some werable items, like watches.
|
||||||
|
|
||||||
|
---@class ISEquipWeaponAction
|
||||||
|
---@field character IsoPlayer
|
||||||
|
|
||||||
|
--* Equipping items overrides *--
|
||||||
|
local og_ISEquipWeaponAction_isValid = ISEquipWeaponAction.isValid
|
||||||
|
---Add a condition to check the feasibility of having 2 handed weapons or if both arms are cut off
|
||||||
|
---@return boolean
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
function ISEquipWeaponAction:isValid()
|
||||||
|
local isValid = og_ISEquipWeaponAction_isValid(self)
|
||||||
|
if isValid then
|
||||||
|
local isPrimaryHandValid = CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.R)
|
||||||
|
local isSecondaryHandValid = CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.L)
|
||||||
|
-- Both hands are cut off, so it's impossible to equip in any way
|
||||||
|
|
||||||
|
--TOC_DEBUG.print("isPrimaryHandValid : " .. tostring(isPrimaryHandValid))
|
||||||
|
--TOC_DEBUG.print("isSecondaryHandValid : " .. tostring(isSecondaryHandValid))
|
||||||
|
|
||||||
|
if not isPrimaryHandValid and not isSecondaryHandValid then
|
||||||
|
isValid = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return isValid
|
||||||
|
end
|
||||||
|
|
||||||
|
---A recreation of the original method, but with amputations in mind
|
||||||
|
function ISEquipWeaponAction:performWithAmputation()
|
||||||
|
TOC_DEBUG.print("running ISEquipWeaponAction performWithAmputation")
|
||||||
|
local hand = nil
|
||||||
|
local otherHand = nil
|
||||||
|
local getMethodFirst = nil
|
||||||
|
local setMethodFirst = nil
|
||||||
|
local getMethodSecond = nil
|
||||||
|
local setMethodSecond = nil
|
||||||
|
|
||||||
|
if self.primary then
|
||||||
|
hand = StaticData.LIMBS_IND_STR.Hand_R
|
||||||
|
otherHand = StaticData.LIMBS_IND_STR.Hand_L
|
||||||
|
getMethodFirst = self.character.getSecondaryHandItem
|
||||||
|
setMethodFirst = self.character.setSecondaryHandItem
|
||||||
|
getMethodSecond = self.character.getPrimaryHandItem
|
||||||
|
setMethodSecond = self.character.setPrimaryHandItem
|
||||||
|
else
|
||||||
|
hand = StaticData.LIMBS_IND_STR.Hand_L
|
||||||
|
otherHand = StaticData.LIMBS_IND_STR.Hand_R
|
||||||
|
getMethodFirst = self.character.getPrimaryHandItem
|
||||||
|
setMethodFirst = self.character.setPrimaryHandItem
|
||||||
|
getMethodSecond = self.character.getSecondaryHandItem
|
||||||
|
setMethodSecond = self.character.setSecondaryHandItem
|
||||||
|
end
|
||||||
|
|
||||||
|
local isFirstValid = CheckHandFeasibility(hand)
|
||||||
|
local isSecondValid = CheckHandFeasibility(otherHand)
|
||||||
|
|
||||||
|
|
||||||
|
if not self.twoHands then
|
||||||
|
if getMethodFirst(self.character) and getMethodFirst(self.character):isRequiresEquippedBothHands() then
|
||||||
|
setMethodFirst(self.character, nil)
|
||||||
|
-- if this weapon is already equiped in the 2nd hand, we remove it
|
||||||
|
elseif (getMethodFirst(self.character) == self.item or getMethodFirst(self.character) == getMethodSecond(self.character)) then
|
||||||
|
setMethodFirst(self.character, nil)
|
||||||
|
-- if we are equipping a handgun and there is a weapon in the secondary hand we remove it
|
||||||
|
elseif instanceof(self.item, "HandWeapon") and self.item:getSwingAnim() and self.item:getSwingAnim() == "Handgun" then
|
||||||
|
if getMethodFirst(self.character) and instanceof(getMethodFirst(self.character), "HandWeapon") then
|
||||||
|
setMethodFirst(self.character, nil)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
setMethodSecond(self.character, nil)
|
||||||
|
-- TODO We should use the CachedData indexable instead of dcInst
|
||||||
|
|
||||||
|
if isFirstValid then
|
||||||
|
setMethodSecond(self.character, self.item)
|
||||||
|
-- Check other HAND!
|
||||||
|
elseif isSecondValid then
|
||||||
|
setMethodFirst(self.character, self.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
setMethodFirst(self.character, nil)
|
||||||
|
setMethodSecond(self.character, nil)
|
||||||
|
|
||||||
|
-- TOC_DEBUG.print("First Hand: " .. tostring(hand))
|
||||||
|
-- --TOC_DEBUG.print("Prost Group: " .. tostring(prostGroup))
|
||||||
|
-- TOC_DEBUG.print("Other Hand: " .. tostring(otherHand))
|
||||||
|
-- --TOC_DEBUG.print("Other Prost Group: " .. tostring(otherProstGroup))
|
||||||
|
|
||||||
|
-- TOC_DEBUG.print("isPrimaryHandValid: " .. tostring(isFirstValid))
|
||||||
|
-- TOC_DEBUG.print("isSecondaryHandValid: " .. tostring(isSecondValid))
|
||||||
|
|
||||||
|
|
||||||
|
if isFirstValid then
|
||||||
|
setMethodSecond(self.character, self.item)
|
||||||
|
end
|
||||||
|
|
||||||
|
if isSecondValid then
|
||||||
|
setMethodFirst(self.character, self.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISEquipWeaponAction_perform = ISEquipWeaponAction.perform
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
function ISEquipWeaponAction:perform()
|
||||||
|
og_ISEquipWeaponAction_perform(self)
|
||||||
|
|
||||||
|
|
||||||
|
--if self.character == getPlayer() then
|
||||||
|
local dcInst = DataController.GetInstance(self.character:getUsername())
|
||||||
|
-- Just check it any limb has been cut. If not, we can just return from here
|
||||||
|
if dcInst:getIsAnyLimbCut() then
|
||||||
|
self:performWithAmputation()
|
||||||
|
end
|
||||||
|
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ISInventoryPaneContextMenu.doEquipOption(context, playerObj, isWeapon, items, player)
|
||||||
|
-- check if hands if not heavy damaged
|
||||||
|
if (not playerObj:isPrimaryHandItem(isWeapon) or (playerObj:isPrimaryHandItem(isWeapon) and playerObj:isSecondaryHandItem(isWeapon))) and not getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):isDeepWounded() and (getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getFractureTime() == 0 or getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_R):getSplintFactor() > 0) then
|
||||||
|
-- forbid reequipping skinned items to avoid multiple problems for now
|
||||||
|
local add = true
|
||||||
|
if playerObj:getSecondaryHandItem() == isWeapon and isWeapon:getScriptItem():getReplaceWhenUnequip() then
|
||||||
|
add = false
|
||||||
|
end
|
||||||
|
if add then
|
||||||
|
local equipOption = context:addOption(getText("ContextMenu_Equip_Primary"), items,
|
||||||
|
ISInventoryPaneContextMenu.OnPrimaryWeapon, player)
|
||||||
|
equipOption.notAvailable = not CheckHandFeasibility(StaticData.LIMBS_IND_STR.Hand_R)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (not playerObj:isSecondaryHandItem(isWeapon) or (playerObj:isPrimaryHandItem(isWeapon) and playerObj:isSecondaryHandItem(isWeapon))) and not getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_L):isDeepWounded() and (getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_L):getFractureTime() == 0 or getSpecificPlayer(player):getBodyDamage():getBodyPart(BodyPartType.Hand_L):getSplintFactor() > 0) then
|
||||||
|
-- forbid reequipping skinned items to avoid multiple problems for now
|
||||||
|
local add = true
|
||||||
|
if playerObj:getPrimaryHandItem() == isWeapon and isWeapon:getScriptItem():getReplaceWhenUnequip() then
|
||||||
|
add = false
|
||||||
|
end
|
||||||
|
if add then
|
||||||
|
local equipOption = context:addOption(getText("ContextMenu_Equip_Secondary"), items,
|
||||||
|
ISInventoryPaneContextMenu.OnSecondWeapon, player)
|
||||||
|
|
||||||
|
equipOption.notAvailable = not CheckHandFeasibility(StaticData.LIMBS_IND_STR.Hand_L)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local noHandsImpossibleActions = {
|
||||||
|
getText("ContextMenu_Add_escape_rope_sheet"),
|
||||||
|
getText("ContextMenu_Add_escape_rope"),
|
||||||
|
getText("ContextMenu_Remove_escape_rope"),
|
||||||
|
getText("ContextMenu_Barricade"),
|
||||||
|
getText("ContextMenu_Unbarricade"),
|
||||||
|
getText("ContextMenu_MetalBarricade"),
|
||||||
|
getText("ContextMenu_MetalBarBarricade"),
|
||||||
|
getText("ContextMenu_Open_window"),
|
||||||
|
getText("ContextMenu_Close_window"),
|
||||||
|
getText("ContextMenu_PickupBrokenGlass"),
|
||||||
|
getText("ContextMenu_Open_door"),
|
||||||
|
getText("ContextMenu_Close_door"),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local og_ISWorldObjectContextMenu_createMenu = ISWorldObjectContextMenu.createMenu
|
||||||
|
|
||||||
|
---@param player integer
|
||||||
|
---@param worldobjects any
|
||||||
|
---@param x any
|
||||||
|
---@param y any
|
||||||
|
---@param test any
|
||||||
|
function ISWorldObjectContextMenu.createMenu(player, worldobjects, x, y, test)
|
||||||
|
---@type ISContextMenu
|
||||||
|
local ogContext = og_ISWorldObjectContextMenu_createMenu(player, worldobjects, x, y, test)
|
||||||
|
|
||||||
|
-- goddamn it, zomboid devs. ogContext could be a boolean...
|
||||||
|
-- TBH, I don't really care about gamepad support, but all this method can break stuff. Let's just disable thisfor gamepad users.
|
||||||
|
if type(ogContext) == "boolean" or type(ogContext) == "string" then
|
||||||
|
return ogContext
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- The vanilla game doesn't count an item in the off hand as "equipped" for picking up glass. Let's fix that here
|
||||||
|
local brokenGlassOption = ogContext:getOptionFromName(getText("ContextMenu_RemoveBrokenGlass"))
|
||||||
|
|
||||||
|
if brokenGlassOption then
|
||||||
|
local playerObj = getSpecificPlayer(player)
|
||||||
|
if (CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.R) and playerObj:getPrimaryHandItem()) or
|
||||||
|
(CachedDataHandler.GetHandFeasibility(StaticData.SIDES_IND_STR.L) and playerObj:getSecondaryHandItem())
|
||||||
|
then
|
||||||
|
brokenGlassOption.notAvailable = false
|
||||||
|
brokenGlassOption.toolTip = nil -- This is active only when you can't do the action.
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- check if no hands, disable various interactions
|
||||||
|
if not CachedDataHandler.GetBothHandsFeasibility() then
|
||||||
|
TOC_DEBUG.print("NO hands :((")
|
||||||
|
for i = 1, #noHandsImpossibleActions do
|
||||||
|
local optionName = noHandsImpossibleActions[i]
|
||||||
|
local option = ogContext:getOptionFromName(optionName)
|
||||||
|
if option then
|
||||||
|
option.notAvailable = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ogContext
|
||||||
|
end
|
||||||
|
|
||||||
|
--* DISABLE WEARING CERTAIN ITEMS WHEN NO LIMB
|
||||||
|
|
||||||
|
local function CheckLimbFeasibility(limbName)
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
local isFeasible = not dcInst:getIsCut(limbName) or dcInst:getIsProstEquipped(limbName)
|
||||||
|
--TOC_DEBUG.print("isFeasible="..tostring(isFeasible))
|
||||||
|
return isFeasible
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---@param obj any
|
||||||
|
---@param wrappedFunc function
|
||||||
|
---@param item InventoryItem
|
||||||
|
---@return boolean
|
||||||
|
local function WrapClothingAction(obj, wrappedFunc, item)
|
||||||
|
local isEquippable = wrappedFunc(obj)
|
||||||
|
if not isEquippable then return isEquippable end
|
||||||
|
|
||||||
|
local itemBodyLoc = item:getBodyLocation()
|
||||||
|
|
||||||
|
local limbToCheck = StaticData.AFFECTED_BODYLOCS_TO_LIMBS_IND_STR[itemBodyLoc]
|
||||||
|
if CheckLimbFeasibility(limbToCheck) then return isEquippable else return false end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
local og_ISWearClothing_isValid = ISWearClothing.isValid
|
||||||
|
function ISWearClothing:isValid()
|
||||||
|
return WrapClothingAction(self, og_ISWearClothing_isValid, self.item)
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISClothingExtraAction_isValid = ISClothingExtraAction.isValid
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
function ISClothingExtraAction:isValid()
|
||||||
|
return WrapClothingAction(self, og_ISClothingExtraAction_isValid, InventoryItemFactory.CreateItem(self.extra))
|
||||||
|
end
|
||||||
391
media/lua/client/TOC/Controllers/LocalPlayerController.lua
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
require("TOC/Events")
|
||||||
|
-----------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Handle ONLY stuff for the local client
|
||||||
|
|
||||||
|
---@class LocalPlayerController
|
||||||
|
---@field playerObj IsoPlayer
|
||||||
|
---@field username string
|
||||||
|
---@field hasBeenDamaged boolean
|
||||||
|
local LocalPlayerController = {}
|
||||||
|
|
||||||
|
|
||||||
|
--* Initialization
|
||||||
|
|
||||||
|
---Setup the Player Handler and modData, only for local client
|
||||||
|
---@param isForced boolean?
|
||||||
|
function LocalPlayerController.InitializePlayer(isForced)
|
||||||
|
local playerObj = getPlayer()
|
||||||
|
local username = playerObj:getUsername()
|
||||||
|
|
||||||
|
TOC_DEBUG.print("Initializing local player: " .. username)
|
||||||
|
|
||||||
|
DataController:new(username, isForced)
|
||||||
|
LocalPlayerController.playerObj = playerObj
|
||||||
|
LocalPlayerController.username = username
|
||||||
|
|
||||||
|
--Setup the CicatrizationUpdate event and triggers it once
|
||||||
|
Events.OnAmputatedLimb.Add(LocalPlayerController.ToggleUpdateAmputations)
|
||||||
|
LocalPlayerController.ToggleUpdateAmputations()
|
||||||
|
|
||||||
|
-- Since isForced is used to reset an existing player data, we're gonna clean their ISHealthPanel table too
|
||||||
|
if isForced then
|
||||||
|
local ItemsController = require("TOC/Controllers/ItemsController")
|
||||||
|
ItemsController.Player.DeleteAllOldAmputationItems(playerObj)
|
||||||
|
CachedDataHandler.Setup(username)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set a bool to use an overriding GetDamagedParts
|
||||||
|
SetHealthPanelTOC()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---Handles the traits
|
||||||
|
function LocalPlayerController.ManageTraits()
|
||||||
|
|
||||||
|
-- Local player
|
||||||
|
local playerObj = getPlayer()
|
||||||
|
|
||||||
|
local AmputationHandler = require("TOC/Handlers/AmputationHandler")
|
||||||
|
for k, v in pairs(StaticData.TRAITS_BP) do
|
||||||
|
if playerObj:HasTrait(k) then
|
||||||
|
-- Once we find one, we should be done since they're exclusive
|
||||||
|
TOC_DEBUG.print("Player has amputation trait " .. k .. ", executing it")
|
||||||
|
local tempHandler = AmputationHandler:new(v, playerObj)
|
||||||
|
tempHandler:execute(false) -- No damage
|
||||||
|
tempHandler:close()
|
||||||
|
|
||||||
|
-- The wound should be already cicatrized
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
LocalPlayerController.HandleSetCicatrization(DataController.GetInstance(), playerObj, v)
|
||||||
|
dcInst:apply()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We need to manage traits when we're done setupping everything
|
||||||
|
-- It shouldn't be done every single time we initialize the player, fetching data, etc.
|
||||||
|
Events.OnSetupTocData.Add(LocalPlayerController.ManageTraits)
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
--* Health *--
|
||||||
|
|
||||||
|
---Used to heal an area that has been cut previously. There's an exception for bites, those are managed differently
|
||||||
|
---@param bodyPart BodyPart
|
||||||
|
function LocalPlayerController.HealArea(bodyPart)
|
||||||
|
bodyPart:setFractureTime(0)
|
||||||
|
|
||||||
|
bodyPart:setScratched(false, true)
|
||||||
|
bodyPart:setScratchTime(0)
|
||||||
|
|
||||||
|
bodyPart:setBleeding(false)
|
||||||
|
bodyPart:setBleedingTime(0)
|
||||||
|
|
||||||
|
bodyPart:SetBitten(false)
|
||||||
|
bodyPart:setBiteTime(0)
|
||||||
|
|
||||||
|
bodyPart:setCut(false)
|
||||||
|
bodyPart:setCutTime(0)
|
||||||
|
|
||||||
|
bodyPart:setDeepWounded(false)
|
||||||
|
bodyPart:setDeepWoundTime(0)
|
||||||
|
|
||||||
|
bodyPart:setHaveBullet(false, 0)
|
||||||
|
bodyPart:setHaveGlass(false)
|
||||||
|
bodyPart:setSplint(false, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param bodyDamage BodyDamage
|
||||||
|
---@param bodyPart BodyPart
|
||||||
|
---@param limbName string
|
||||||
|
---@param dcInst DataController
|
||||||
|
function LocalPlayerController.HealZombieInfection(bodyDamage, bodyPart, limbName, dcInst)
|
||||||
|
if bodyDamage:isInfected() == false then return end
|
||||||
|
|
||||||
|
bodyDamage:setInfected(false)
|
||||||
|
bodyDamage:setInfectionMortalityDuration(-1)
|
||||||
|
bodyDamage:setInfectionTime(-1)
|
||||||
|
bodyDamage:setInfectionLevel(-1)
|
||||||
|
bodyPart:SetInfected(false)
|
||||||
|
|
||||||
|
dcInst:setIsInfected(limbName, false)
|
||||||
|
dcInst:apply()
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param character IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
function LocalPlayerController.TryRandomBleed(character, limbName)
|
||||||
|
-- Chance should be determined by the cicatrization time
|
||||||
|
local cicTime = DataController.GetInstance():getCicatrizationTime(limbName)
|
||||||
|
if cicTime == 0 then return end
|
||||||
|
|
||||||
|
-- TODO This is just a placeholder, we need to figure out a better way to calculate this chance
|
||||||
|
local normCicTime = CommonMethods.Normalize(cicTime, 0, StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[limbName]) / 2
|
||||||
|
TOC_DEBUG.print("OG cicTime: " .. tostring(cicTime))
|
||||||
|
TOC_DEBUG.print("Normalized cic time : " .. tostring(normCicTime))
|
||||||
|
|
||||||
|
local chance = ZombRandFloat(0.0, 1.0)
|
||||||
|
if chance > normCicTime then
|
||||||
|
TOC_DEBUG.print("Triggered bleeding from non cicatrized wound")
|
||||||
|
local adjacentBodyPartType = BodyPartType[StaticData.LIMBS_ADJACENT_IND_STR[limbName]]
|
||||||
|
|
||||||
|
-- we need to check if the wound is already bleeding before doing anything else to prevent issues with bandages
|
||||||
|
local bp = character:getBodyDamage():getBodyPart(adjacentBodyPartType)
|
||||||
|
bp:setBleedingTime(20) -- TODO Should depend on cicatrization instead of a fixed time
|
||||||
|
-- ADD Could break bandages if bleeding is too much?
|
||||||
|
|
||||||
|
|
||||||
|
--character:getBodyDamage():getBodyPart(adjacentBodyPartType):setBleeding(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
--* Damage handling *--
|
||||||
|
--- Locks OnPlayerGetDamage event, to prevent it from getting spammed constantly
|
||||||
|
LocalPlayerController.hasBeenDamaged = false
|
||||||
|
|
||||||
|
|
||||||
|
---Check if the player has in infected body part or if they have been hit in a cut area
|
||||||
|
---@param character IsoPlayer|IsoGameCharacter
|
||||||
|
function LocalPlayerController.HandleDamage(character)
|
||||||
|
--TOC_DEBUG.print("Player got hit!")
|
||||||
|
-- TOC_DEBUG.print(damageType)
|
||||||
|
if character ~= getPlayer() then
|
||||||
|
-- Disable lock before doing anything else
|
||||||
|
LocalPlayerController.hasBeenDamaged = false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local bd = character:getBodyDamage()
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
local modDataNeedsUpdate = false
|
||||||
|
for i = 1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
local bptEnum = StaticData.LIMBS_TO_BODYLOCS_IND_BPT[limbName]
|
||||||
|
local bodyPart = bd:getBodyPart(bptEnum)
|
||||||
|
if dcInst:getIsCut(limbName) then
|
||||||
|
-- Generic injury, let's heal it since they already cut the limb off
|
||||||
|
if bodyPart:HasInjury() then
|
||||||
|
TOC_DEBUG.print("Healing area - " .. limbName)
|
||||||
|
LocalPlayerController.HealArea(bodyPart)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Special case for bites\zombie infections
|
||||||
|
if bodyPart:IsInfected() then
|
||||||
|
TOC_DEBUG.print("Healed from zombie infection - " .. limbName)
|
||||||
|
LocalPlayerController.HealZombieInfection(bd, bodyPart, limbName, dcInst)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if (bodyPart:bitten() or bodyPart:IsInfected()) and not dcInst:getIsInfected(limbName) then
|
||||||
|
dcInst:setIsInfected(limbName, true)
|
||||||
|
modDataNeedsUpdate = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check other body parts that are not included in the mod, if there's a bite there then the player is fucked
|
||||||
|
-- We can skip this loop if the player has been infected. The one before we kinda need it to handle correctly the bites in case the player wanna cut stuff off anyway
|
||||||
|
if not dcInst:getIsIgnoredPartInfected() then
|
||||||
|
for i = 1, #StaticData.IGNORED_BODYLOCS_BPT do
|
||||||
|
local bodyPartType = StaticData.IGNORED_BODYLOCS_BPT[i]
|
||||||
|
local bodyPart = bd:getBodyPart(bodyPartType)
|
||||||
|
if bodyPart and (bodyPart:bitten() or bodyPart:IsInfected()) then
|
||||||
|
dcInst:setIsIgnoredPartInfected(true)
|
||||||
|
modDataNeedsUpdate = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if modDataNeedsUpdate then
|
||||||
|
dcInst:apply()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Disable the lock
|
||||||
|
LocalPlayerController.hasBeenDamaged = false
|
||||||
|
end
|
||||||
|
|
||||||
|
---Setup HandleDamage, triggered by OnPlayerGetDamage. To prevent a spam caused by this awful event, we use a bool lock
|
||||||
|
---@param character IsoPlayer|IsoGameCharacter
|
||||||
|
---@param damageType string
|
||||||
|
---@param damageAmount number
|
||||||
|
function LocalPlayerController.OnGetDamage(character, damageType, damageAmount)
|
||||||
|
if LocalPlayerController.hasBeenDamaged == false then
|
||||||
|
-- Start checks
|
||||||
|
LocalPlayerController.hasBeenDamaged = true
|
||||||
|
LocalPlayerController.HandleDamage(character)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Events.OnPlayerGetDamage.Add(LocalPlayerController.OnGetDamage)
|
||||||
|
|
||||||
|
--* Amputation Loop handling *--
|
||||||
|
|
||||||
|
---Updates the cicatrization process, run when a limb has been cut. Run it every 1 hour
|
||||||
|
function LocalPlayerController.UpdateAmputations()
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
if not dcInst:getIsDataReady() then
|
||||||
|
TOC_DEBUG.print("Data not ready for UpdateAmputations, waiting next loop")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not dcInst:getIsAnyLimbCut() then
|
||||||
|
Events.EveryHours.Remove(LocalPlayerController.UpdateAmputations)
|
||||||
|
end
|
||||||
|
|
||||||
|
local pl = LocalPlayerController.playerObj
|
||||||
|
local visual = pl:getHumanVisual()
|
||||||
|
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(pl:getUsername())
|
||||||
|
local needsUpdate = false
|
||||||
|
|
||||||
|
for k, _ in pairs(amputatedLimbs) do
|
||||||
|
local limbName = k
|
||||||
|
local isCicatrized = dcInst:getIsCicatrized(limbName)
|
||||||
|
|
||||||
|
if not isCicatrized then
|
||||||
|
needsUpdate = true
|
||||||
|
local cicTime = dcInst:getCicatrizationTime(limbName)
|
||||||
|
TOC_DEBUG.print("Updating cicatrization for " .. tostring(limbName))
|
||||||
|
|
||||||
|
--* Dirtyness of the wound
|
||||||
|
|
||||||
|
-- We need to get the BloodBodyPartType to find out how dirty the zone is
|
||||||
|
local bbptEnum = BloodBodyPartType[limbName]
|
||||||
|
local modifier = 0.01 * SandboxVars.TOC.WoundDirtynessMultiplier
|
||||||
|
|
||||||
|
local dirtynessVis = visual:getDirt(bbptEnum) + visual:getBlood(bbptEnum)
|
||||||
|
local dirtynessWound = dcInst:getWoundDirtyness(limbName) + modifier
|
||||||
|
|
||||||
|
local dirtyness = dirtynessVis + dirtynessWound
|
||||||
|
|
||||||
|
if dirtyness > 1 then
|
||||||
|
dirtyness = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
dcInst:setWoundDirtyness(limbName, dirtyness)
|
||||||
|
TOC_DEBUG.print("Dirtyness for this zone: " .. tostring(dirtyness))
|
||||||
|
|
||||||
|
--* Cicatrization
|
||||||
|
|
||||||
|
local cicDec = SandboxVars.TOC.CicatrizationSpeed - dirtyness
|
||||||
|
if cicDec <= 0 then cicDec = 0.1 end
|
||||||
|
cicTime = cicTime - cicDec
|
||||||
|
|
||||||
|
|
||||||
|
TOC_DEBUG.print("New cicatrization time: " .. tostring(cicTime))
|
||||||
|
if cicTime <= 0 then
|
||||||
|
LocalPlayerController.HandleSetCicatrization(dcInst, pl, limbName)
|
||||||
|
else
|
||||||
|
dcInst:setCicatrizationTime(limbName, cicTime)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if needsUpdate then
|
||||||
|
TOC_DEBUG.print("updating modData from cicatrization loop")
|
||||||
|
dcInst:apply() -- TODO This is gonna be heavy. Not entirely sure
|
||||||
|
else
|
||||||
|
TOC_DEBUG.print("Removing UpdateAmputations")
|
||||||
|
Events.EveryHours.Remove(LocalPlayerController.UpdateAmputations) -- We can remove it safely, no cicatrization happening here boys
|
||||||
|
end
|
||||||
|
TOC_DEBUG.print("updating cicatrization and wound dirtyness!")
|
||||||
|
end
|
||||||
|
|
||||||
|
---Starts safely the loop to update cicatrzation
|
||||||
|
function LocalPlayerController.ToggleUpdateAmputations()
|
||||||
|
TOC_DEBUG.print("Activating amputation handling loop (if it wasn't active before)")
|
||||||
|
CommonMethods.SafeStartEvent("EveryHours", LocalPlayerController.UpdateAmputations)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--* Cicatrization and cicatrization visuals *--
|
||||||
|
|
||||||
|
---Set the boolean and cicTime in DCINST and the visuals for the amputated limb
|
||||||
|
---@param dcInst DataController
|
||||||
|
---@param playerObj IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
function LocalPlayerController.HandleSetCicatrization(dcInst, playerObj, limbName)
|
||||||
|
TOC_DEBUG.print("Setting cicatrization to " .. tostring(limbName))
|
||||||
|
dcInst:setIsCicatrized(limbName, true)
|
||||||
|
dcInst:setCicatrizationTime(limbName, 0)
|
||||||
|
|
||||||
|
-- Set visuals for the amputation
|
||||||
|
local ItemsController = require("TOC/Controllers/ItemsController")
|
||||||
|
ItemsController.Player.OverrideAmputationItemVisuals(playerObj, limbName, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Object drop handling when amputation occurs
|
||||||
|
|
||||||
|
|
||||||
|
function LocalPlayerController.CanItemBeEquipped(itemObj, limbName)
|
||||||
|
local bl = itemObj:getBodyLocation()
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
local sideStr = CommonMethods.GetSideFull(side)
|
||||||
|
|
||||||
|
-- TODO Check from DataController
|
||||||
|
|
||||||
|
if string.contains(limbName, "Hand_") and (bl == sideStr .. "_MiddleFinger" or bl == sideStr .. "_RingFinger") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if string.contains(limbName, "ForeArm_") and (bl == sideStr .. "Wrist") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Drop all items from the affected limb
|
||||||
|
---@param limbName string
|
||||||
|
function LocalPlayerController.DropItemsAfterAmputation(limbName)
|
||||||
|
TOC_DEBUG.print("Triggered DropItemsAfterAmputation")
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
local sideStr = CommonMethods.GetSideFull(side)
|
||||||
|
|
||||||
|
local pl = getPlayer()
|
||||||
|
local wornItems = pl:getWornItems()
|
||||||
|
|
||||||
|
for i = 1, wornItems:size() do
|
||||||
|
local it = wornItems:get(i - 1)
|
||||||
|
if it then
|
||||||
|
local wornItem = wornItems:get(i - 1):getItem()
|
||||||
|
TOC_DEBUG.print(wornItem:getBodyLocation())
|
||||||
|
|
||||||
|
local bl = wornItem:getBodyLocation()
|
||||||
|
if string.contains(limbName, "Hand_") and (bl == sideStr .. "_MiddleFinger" or bl == sideStr .. "_RingFinger") then
|
||||||
|
pl:removeWornItem(wornItem)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if string.contains(limbName, "ForeArm_") and (bl == sideStr .. "Wrist") then
|
||||||
|
pl:removeWornItem(wornItem)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO Consider 2 handed weapons too
|
||||||
|
|
||||||
|
-- equipped items too
|
||||||
|
if side == "R" then
|
||||||
|
pl:setPrimaryHandItem(nil)
|
||||||
|
elseif side == "L" then
|
||||||
|
pl:setSecondaryHandItem(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
Events.OnAmputatedLimb.Add(LocalPlayerController.DropItemsAfterAmputation)
|
||||||
|
Events.OnProsthesisUnequipped.Add(LocalPlayerController.DropItemsAfterAmputation)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return LocalPlayerController
|
||||||
112
media/lua/client/TOC/Controllers/TourniquetController.lua
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
|
||||||
|
|
||||||
|
---@class TourniquetController
|
||||||
|
local TourniquetController = {
|
||||||
|
bodyLoc = "TOC_ArmAccessory"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function TourniquetController.CheckTourniquetOnLimb(player, limbName)
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
|
||||||
|
local wornItems = player:getWornItems()
|
||||||
|
for j=1,wornItems:size() do
|
||||||
|
local wornItem = wornItems:get(j-1)
|
||||||
|
|
||||||
|
local fType = wornItem:getItem():getFullType()
|
||||||
|
if TourniquetController.IsItemTourniquet(fType) then
|
||||||
|
-- Check side
|
||||||
|
if luautils.stringEnds(fType, side) then
|
||||||
|
TOC_DEBUG.print("Found acceptable tourniquet")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TourniquetController.IsItemTourniquet(fType)
|
||||||
|
-- TODO Add legs stuff
|
||||||
|
return string.contains(fType, "Surg_Arm_Tourniquet_")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---@param player IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
---@return boolean
|
||||||
|
function TourniquetController.CheckTourniquet(player, limbName)
|
||||||
|
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
|
||||||
|
local wornItems = player:getWornItems()
|
||||||
|
for j=1,wornItems:size() do
|
||||||
|
local wornItem = wornItems:get(j-1)
|
||||||
|
|
||||||
|
local fType = wornItem:getItem():getFullType()
|
||||||
|
if string.contains(fType, "Surg_Arm_Tourniquet_") then
|
||||||
|
-- Check side
|
||||||
|
if luautils.stringEnds(fType, side) then
|
||||||
|
TOC_DEBUG.print("Found acceptable tourniquet")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
---@param obj any self
|
||||||
|
---@param wrappedFunc function
|
||||||
|
function TourniquetController.WrapClothingAction(obj, wrappedFunc)
|
||||||
|
local isTourniquet = TourniquetController.IsItemTourniquet(obj.item:getFullType())
|
||||||
|
local group
|
||||||
|
if isTourniquet then
|
||||||
|
group = BodyLocations.getGroup("Human")
|
||||||
|
group:setMultiItem(TourniquetController.bodyLoc, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ogValue = wrappedFunc(obj)
|
||||||
|
|
||||||
|
if isTourniquet then
|
||||||
|
group:setMultiItem(TourniquetController.bodyLoc, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ogValue -- Needed for isValid
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Horrendous workaround
|
||||||
|
|
||||||
|
To unequp items, the java side uses WornItems.setItem, which has
|
||||||
|
a check for multiItem. Basically, if it's active, it won't actually remove the item,
|
||||||
|
fucking things up. So, to be 100% sure that we're removing the items, we're gonna
|
||||||
|
disable and re-enable the multi-item bool for the Unequip Action.
|
||||||
|
|
||||||
|
Same story as the prosthesis item basically.
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
local og_ISClothingExtraAction_perform = ISClothingExtraAction.perform
|
||||||
|
function ISClothingExtraAction:perform()
|
||||||
|
TourniquetController.WrapClothingAction(self, og_ISClothingExtraAction_perform)
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISWearClothing_isValid = ISWearClothing.isValid
|
||||||
|
function ISWearClothing:isValid()
|
||||||
|
return TourniquetController.WrapClothingAction(self, og_ISWearClothing_isValid)
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISUnequipAction_perform = ISUnequipAction.perform
|
||||||
|
function ISUnequipAction:perform()
|
||||||
|
return TourniquetController.WrapClothingAction(self, og_ISUnequipAction_perform)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return TourniquetController
|
||||||
5
media/lua/client/TOC/Events.lua
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
--* Setup Events *--
|
||||||
|
LuaEventManager.AddEvent("OnAmputatedLimb") --Triggered when a limb has been amputated
|
||||||
|
LuaEventManager.AddEvent("OnProsthesisUnequipped")
|
||||||
|
LuaEventManager.AddEvent("OnReceivedTocData") -- Triggered when TOC data is ready
|
||||||
|
LuaEventManager.AddEvent("OnSetupTocData") -- Triggered when TOC has been setupped
|
||||||
211
media/lua/client/TOC/Handlers/AmputationHandler.lua
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local ItemsController = require("TOC/Controllers/ItemsController")
|
||||||
|
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||||
|
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
local TourniquetController = require("TOC/Controllers/TourniquetController")
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
--- Manages an amputation. Will be run on the patient client
|
||||||
|
---@class AmputationHandler
|
||||||
|
---@field patientPl IsoPlayer
|
||||||
|
---@field limbName string
|
||||||
|
---@field bodyPartType BodyPartType
|
||||||
|
---@field surgeonPl IsoPlayer?
|
||||||
|
local AmputationHandler = {}
|
||||||
|
|
||||||
|
---@param limbName string
|
||||||
|
---@param surgeonPl IsoPlayer?
|
||||||
|
---@return AmputationHandler
|
||||||
|
function AmputationHandler:new(limbName, surgeonPl)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
|
||||||
|
o.patientPl = getPlayer()
|
||||||
|
o.limbName = limbName
|
||||||
|
o.bodyPartType = BodyPartType[limbName]
|
||||||
|
|
||||||
|
-- TOC_DEBUG.print("limbName = " .. o.limbName)
|
||||||
|
-- TOC_DEBUG.print("bodyPartType = " .. tostring(o.bodyPartType))
|
||||||
|
|
||||||
|
if surgeonPl then
|
||||||
|
o.surgeonPl = surgeonPl
|
||||||
|
else
|
||||||
|
o.surgeonPl = o.patientPl
|
||||||
|
end
|
||||||
|
|
||||||
|
AmputationHandler.instance = o
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--* Static methods *--
|
||||||
|
|
||||||
|
---@param player IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
function AmputationHandler.ApplyDamageDuringAmputation(player, limbName)
|
||||||
|
|
||||||
|
|
||||||
|
local ampGroup = StaticData.LIMBS_TO_AMP_GROUPS_MATCH_IND_STR[limbName]
|
||||||
|
local isTourniquetEquipped = false
|
||||||
|
|
||||||
|
-- Check if tourniquet is applied on the zone
|
||||||
|
for bl, tournAmpGroup in pairs(StaticData.TOURNIQUET_BODYLOCS_TO_GROUPS_IND_STR) do
|
||||||
|
local item = player:getWornItem(bl)
|
||||||
|
|
||||||
|
-- LimbName -> Group -> BodyLoc
|
||||||
|
if item and tournAmpGroup == ampGroup then
|
||||||
|
TOC_DEBUG.print("tourniquet is equipped")
|
||||||
|
isTourniquetEquipped = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local bodyDamage = player:getBodyDamage()
|
||||||
|
local bodyPartType = BodyPartType[limbName]
|
||||||
|
local bodyDamagePart = bodyDamage:getBodyPart(bodyPartType)
|
||||||
|
TOC_DEBUG.print("damage patient - " .. tostring(bodyPartType))
|
||||||
|
|
||||||
|
bodyDamagePart:setBleeding(true)
|
||||||
|
bodyDamagePart:setCut(true)
|
||||||
|
|
||||||
|
local bleedingTime
|
||||||
|
if isTourniquetEquipped then
|
||||||
|
bleedingTime = ZombRand(1,5)
|
||||||
|
else
|
||||||
|
bleedingTime = ZombRand(10, 20)
|
||||||
|
end
|
||||||
|
|
||||||
|
bodyDamagePart:setBleedingTime(bleedingTime)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---@param prevAction ISBaseTimedAction
|
||||||
|
---@param limbName string
|
||||||
|
---@param surgeonPl IsoPlayer
|
||||||
|
---@param patientPl IsoPlayer
|
||||||
|
---@param stitchesItem InventoryItem
|
||||||
|
---@return ISStitch
|
||||||
|
function AmputationHandler.PrepareStitchesAction(prevAction, limbName, surgeonPl, patientPl, stitchesItem)
|
||||||
|
local bd = patientPl:getBodyDamage()
|
||||||
|
|
||||||
|
-- we need the adjacent one, not the actual one
|
||||||
|
local adjacentLimb = StaticData.LIMBS_ADJACENT_IND_STR[limbName]
|
||||||
|
local bodyPart = bd:getBodyPart(BodyPartType[adjacentLimb])
|
||||||
|
|
||||||
|
local stitchesAction = ISStitch:new(surgeonPl, patientPl, stitchesItem, bodyPart, true)
|
||||||
|
ISTimedActionQueue.addAfter(prevAction, stitchesAction)
|
||||||
|
|
||||||
|
return stitchesAction
|
||||||
|
end
|
||||||
|
|
||||||
|
---Setup the ISApplyBandage action that will trigger after the amputation
|
||||||
|
---@param prevAction ISBaseTimedAction
|
||||||
|
---@param limbName string
|
||||||
|
---@param surgeonPl IsoPlayer
|
||||||
|
---@param patientPl IsoPlayer
|
||||||
|
---@param bandageItem InventoryItem
|
||||||
|
---@return ISApplyBandage
|
||||||
|
function AmputationHandler.PrepareBandagesAction(prevAction, limbName, surgeonPl, patientPl, bandageItem)
|
||||||
|
local bd = patientPl:getBodyDamage()
|
||||||
|
-- we need the adjacent one, not the actual one
|
||||||
|
local adjacentLimb = StaticData.LIMBS_ADJACENT_IND_STR[limbName]
|
||||||
|
local bodyPart = bd:getBodyPart(BodyPartType[adjacentLimb])
|
||||||
|
|
||||||
|
local bandageAction = ISApplyBandage:new(surgeonPl, patientPl, bandageItem, bodyPart, true)
|
||||||
|
ISTimedActionQueue.addAfter(prevAction, bandageAction)
|
||||||
|
|
||||||
|
return bandageAction
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--* Main methods *--
|
||||||
|
|
||||||
|
---Set the damage to the adjacent part of the cut area
|
||||||
|
---@param surgeonFactor number
|
||||||
|
function AmputationHandler:damageAfterAmputation(surgeonFactor)
|
||||||
|
|
||||||
|
|
||||||
|
TOC_DEBUG.print("Applying damage after amputation")
|
||||||
|
local patientStats = self.patientPl:getStats()
|
||||||
|
local bd = self.patientPl:getBodyDamage()
|
||||||
|
|
||||||
|
local adjacentLimb = StaticData.LIMBS_ADJACENT_IND_STR[self.limbName]
|
||||||
|
local bodyPart = bd:getBodyPart(BodyPartType[adjacentLimb])
|
||||||
|
local baseDamage = StaticData.LIMBS_BASE_DAMAGE_IND_NUM[self.limbName]
|
||||||
|
|
||||||
|
|
||||||
|
-- Check if player has tourniquet equipped on the limb
|
||||||
|
-- TODO Suboptimal checks, but they should work for now.
|
||||||
|
local hasTourniquet = TourniquetController.CheckTourniquetOnLimb(self.patientPl, self.limbName)
|
||||||
|
if hasTourniquet then
|
||||||
|
TOC_DEBUG.print("Do something different for the damage calculation because tourniquet is applied")
|
||||||
|
baseDamage = baseDamage * 0.5 -- 50% less damage due to tourniquet
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
bodyPart:AddDamage(baseDamage - surgeonFactor)
|
||||||
|
bodyPart:setAdditionalPain(baseDamage - surgeonFactor)
|
||||||
|
bodyPart:setBleeding(true)
|
||||||
|
bodyPart:setBleedingTime(baseDamage - surgeonFactor)
|
||||||
|
bodyPart:setDeepWounded(true)
|
||||||
|
bodyPart:setDeepWoundTime(baseDamage - surgeonFactor)
|
||||||
|
patientStats:setEndurance(surgeonFactor)
|
||||||
|
patientStats:setStress(baseDamage - surgeonFactor)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Execute the amputation. This method doesn't check if the upper limb has been amputated or not, so if
|
||||||
|
--- somehow the method gets triggered and we're trying to cut off a part that doesn't really exist anymore,
|
||||||
|
--- it will still be executed. This is by design, additional checks must be made BEFORE running the AmputationHandler
|
||||||
|
---@param damagePlayer boolean
|
||||||
|
function AmputationHandler:execute(damagePlayer)
|
||||||
|
local surgeonFactor = self.surgeonPl:getPerkLevel(Perks.Doctor) * SandboxVars.TOC.SurgeonAbilityImportance
|
||||||
|
|
||||||
|
-- Set the data in modData
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
dcInst:setCutLimb(self.limbName, false, false, false, surgeonFactor)
|
||||||
|
dcInst:apply() -- This will force rechecking the cached amputated limbs on the other client
|
||||||
|
|
||||||
|
-- Heal the area, we're gonna re-set the damage after (if it's enabled)
|
||||||
|
local bd = self.patientPl:getBodyDamage()
|
||||||
|
local bodyPart = bd:getBodyPart(self.bodyPartType)
|
||||||
|
LocalPlayerController.HealArea(bodyPart)
|
||||||
|
|
||||||
|
-- Give the player the correct amputation item
|
||||||
|
ItemsController.Player.DeleteOldAmputationItem(self.patientPl, self.limbName)
|
||||||
|
ItemsController.Player.SpawnAmputationItem(self.patientPl, self.limbName)
|
||||||
|
|
||||||
|
-- Add it to the list of cut limbs on this local client
|
||||||
|
local username = self.patientPl:getUsername()
|
||||||
|
CachedDataHandler.AddAmputatedLimb(username, self.limbName)
|
||||||
|
|
||||||
|
-- TODO Not optimal, we're already cycling through this when using setCutLimb
|
||||||
|
for i=1, #StaticData.LIMBS_DEPENDENCIES_IND_STR[self.limbName] do
|
||||||
|
local dependedLimbName = StaticData.LIMBS_DEPENDENCIES_IND_STR[self.limbName][i]
|
||||||
|
CachedDataHandler.AddAmputatedLimb(username, dependedLimbName)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cache highest amputation and hand feasibility
|
||||||
|
CachedDataHandler.CalculateCacheableValues(username)
|
||||||
|
|
||||||
|
-- If the part was actually infected, heal the player, if they were in time (infectionLevel < 20)
|
||||||
|
if bd:getInfectionLevel() < 20 and bodyPart:IsInfected() and not dcInst:getIsIgnoredPartInfected() then
|
||||||
|
LocalPlayerController.HealZombieInfection(bd, bodyPart, self.limbName, dcInst)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The last part is to handle the damage that the player will receive after the amputation
|
||||||
|
if not damagePlayer then return end
|
||||||
|
self:damageAfterAmputation(surgeonFactor)
|
||||||
|
|
||||||
|
-- Trigger this event
|
||||||
|
triggerEvent("OnAmputatedLimb", self.limbName)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Deletes the instance
|
||||||
|
function AmputationHandler:close()
|
||||||
|
AmputationHandler.instance = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return AmputationHandler
|
||||||
167
media/lua/client/TOC/Handlers/CachedDataHandler.lua
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
---@class CachedDataHandler
|
||||||
|
local CachedDataHandler = {}
|
||||||
|
|
||||||
|
---Reset everything cache related for that specific user
|
||||||
|
---@param username string
|
||||||
|
function CachedDataHandler.Setup(username)
|
||||||
|
CachedDataHandler.amputatedLimbs[username] = {}
|
||||||
|
-- username -> side
|
||||||
|
CachedDataHandler.highestAmputatedLimbs[username] = {}
|
||||||
|
|
||||||
|
|
||||||
|
-- Local only, doesn't matter for Health Panel
|
||||||
|
CachedDataHandler.handFeasibility = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
---Will calculate all the values that we need
|
||||||
|
function CachedDataHandler.CalculateCacheableValues(username)
|
||||||
|
CachedDataHandler.CalculateHighestAmputatedLimbs(username)
|
||||||
|
if getPlayer():getUsername() == username then
|
||||||
|
CachedDataHandler.CalculateBothHandsFeasibility()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--* Amputated Limbs caching *--
|
||||||
|
CachedDataHandler.amputatedLimbs = {}
|
||||||
|
|
||||||
|
---Calculate the currently amputated limbs for a certain player
|
||||||
|
---@param username string
|
||||||
|
function CachedDataHandler.CalculateAmputatedLimbs(username)
|
||||||
|
TOC_DEBUG.print("Calculating amputated limbs for " .. username)
|
||||||
|
CachedDataHandler.amputatedLimbs[username] = {}
|
||||||
|
local dcInst = DataController.GetInstance(username)
|
||||||
|
|
||||||
|
for i=1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
if dcInst:getIsCut(limbName) then
|
||||||
|
CachedDataHandler.AddAmputatedLimb(username, limbName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---Add an amputated limb to the cached list for that user
|
||||||
|
---@param username string
|
||||||
|
---@param limbName string
|
||||||
|
function CachedDataHandler.AddAmputatedLimb(username, limbName)
|
||||||
|
TOC_DEBUG.print("Added " .. limbName .. " to known amputated limbs for " .. username)
|
||||||
|
|
||||||
|
-- Add it to the generic list
|
||||||
|
if CachedDataHandler.amputatedLimbs[username] == nil then
|
||||||
|
CachedDataHandler.amputatedLimbs[username] = {}
|
||||||
|
end
|
||||||
|
CachedDataHandler.amputatedLimbs[username][limbName] = limbName
|
||||||
|
end
|
||||||
|
|
||||||
|
---Returns a table containing the cached amputated limbs
|
||||||
|
---@param username string
|
||||||
|
---@return table
|
||||||
|
function CachedDataHandler.GetAmputatedLimbs(username)
|
||||||
|
return CachedDataHandler.amputatedLimbs[username]
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Highest amputated limb per side caching *--
|
||||||
|
CachedDataHandler.highestAmputatedLimbs = {}
|
||||||
|
|
||||||
|
---Calcualate the highest point of amputations achieved by the player
|
||||||
|
---@param username string
|
||||||
|
function CachedDataHandler.CalculateHighestAmputatedLimbs(username)
|
||||||
|
TOC_DEBUG.print("Triggered CalculateHighestAmputatedLimbs")
|
||||||
|
local dcInst = DataController.GetInstance(username)
|
||||||
|
if dcInst == nil then
|
||||||
|
TOC_DEBUG.print("DataController not found for " .. username)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
CachedDataHandler.CalculateAmputatedLimbs(username)
|
||||||
|
|
||||||
|
local amputatedLimbs = CachedDataHandler.amputatedLimbs[username]
|
||||||
|
CachedDataHandler.highestAmputatedLimbs[username] = {}
|
||||||
|
--TOC_DEBUG.print("Searching highest amputations for " .. username)
|
||||||
|
|
||||||
|
for k, _ in pairs(amputatedLimbs) do
|
||||||
|
local limbName = k
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then
|
||||||
|
TOC_DEBUG.print("Added Highest Amputation: " .. limbName)
|
||||||
|
CachedDataHandler.highestAmputatedLimbs[username][side] = limbName
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Get the cached highest point of amputation for each side
|
||||||
|
---@param username string
|
||||||
|
---@return table<string, string>
|
||||||
|
function CachedDataHandler.GetHighestAmputatedLimbs(username)
|
||||||
|
return CachedDataHandler.highestAmputatedLimbs[username]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--* Hand feasibility caching *--
|
||||||
|
CachedDataHandler.handFeasibility = {}
|
||||||
|
|
||||||
|
---@param limbName string
|
||||||
|
function CachedDataHandler.CalculateHandFeasibility(limbName)
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
local side = CommonMethods.GetSide(limbName)
|
||||||
|
|
||||||
|
-- TODO if we re run this too early, it might break everything after a forced re-init
|
||||||
|
|
||||||
|
CachedDataHandler.handFeasibility[side] = not dcInst:getIsCut(limbName) or dcInst:getIsProstEquipped(limbName)
|
||||||
|
TOC_DEBUG.print("Calculated hand feasibility: " .. tostring(side))
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param side string Either "L" or "R"
|
||||||
|
---@return boolean
|
||||||
|
function CachedDataHandler.GetHandFeasibility(side)
|
||||||
|
|
||||||
|
-- FIX horrendous workaround, but with a forced init we run the caching too early and it breaks this, setting it to nil.
|
||||||
|
if CachedDataHandler.handFeasibility[side] == nil then
|
||||||
|
CachedDataHandler.CalculateBothHandsFeasibility()
|
||||||
|
end
|
||||||
|
|
||||||
|
return CachedDataHandler.handFeasibility[side]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function CachedDataHandler.CalculateBothHandsFeasibility()
|
||||||
|
CachedDataHandler.CalculateHandFeasibility("Hand_L")
|
||||||
|
CachedDataHandler.CalculateHandFeasibility("Hand_R")
|
||||||
|
local interactStr = "Interact"
|
||||||
|
|
||||||
|
if CachedDataHandler.interactKey == nil or CachedDataHandler.interactKey == 0 then
|
||||||
|
CachedDataHandler.interactKey = getCore():getKey(interactStr)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if not CachedDataHandler.GetBothHandsFeasibility() then
|
||||||
|
TOC_DEBUG.print("Disabling interact key")
|
||||||
|
TOC_DEBUG.print("Cached current key for interact: " .. tostring(CachedDataHandler.interactKey))
|
||||||
|
getCore():addKeyBinding(interactStr, Keyboard.KEY_NONE)
|
||||||
|
else
|
||||||
|
TOC_DEBUG.print("Re-enabling interact key")
|
||||||
|
TOC_DEBUG.print("Cached current key for interact: " .. tostring(CachedDataHandler.interactKey))
|
||||||
|
|
||||||
|
getCore():addKeyBinding(interactStr, CachedDataHandler.interactKey)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CachedDataHandler.GetBothHandsFeasibility()
|
||||||
|
return CachedDataHandler.handFeasibility["L"] or CachedDataHandler.handFeasibility["R"]
|
||||||
|
end
|
||||||
|
|
||||||
|
return CachedDataHandler
|
||||||
180
media/lua/client/TOC/Handlers/ProsthesisHandler.lua
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
---@class ProsthesisHandler
|
||||||
|
local ProsthesisHandler = {}
|
||||||
|
|
||||||
|
local bodyLocArmProst = StaticData.MOD_BODYLOCS_BASE_IND_STR.TOC_ArmProst
|
||||||
|
local bodyLocLegProst = StaticData.MOD_BODYLOCS_BASE_IND_STR.TOC_LegProst
|
||||||
|
|
||||||
|
---Check if the following item is a prosthesis or not
|
||||||
|
---@param item InventoryItem?
|
||||||
|
---@return boolean
|
||||||
|
function ProsthesisHandler.CheckIfProst(item)
|
||||||
|
-- TODO Won't be correct when prost for legs are gonna be in
|
||||||
|
--TOC_DEBUG.print("Checking if item is prost")
|
||||||
|
if item == nil then
|
||||||
|
--TOC_DEBUG.print("Not prost")
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return item:getBodyLocation():contains(bodyLocArmProst)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get the grouping for the prosthesis
|
||||||
|
---@param item InventoryItem
|
||||||
|
---@return string
|
||||||
|
function ProsthesisHandler.GetGroup(item)
|
||||||
|
local fullType = item:getFullType()
|
||||||
|
local side = CommonMethods.GetSide(fullType)
|
||||||
|
|
||||||
|
|
||||||
|
local bodyLocation = item:getBodyLocation()
|
||||||
|
local position
|
||||||
|
if bodyLocation == bodyLocArmProst then
|
||||||
|
position = "Top_"
|
||||||
|
elseif bodyLocation == bodyLocLegProst then
|
||||||
|
position = "Bottom_"
|
||||||
|
else
|
||||||
|
TOC_DEBUG.print("Something is wrong, no position in this item")
|
||||||
|
position = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local index = position .. side
|
||||||
|
local group = StaticData.AMP_GROUPS_IND_STR[index]
|
||||||
|
return group
|
||||||
|
end
|
||||||
|
|
||||||
|
---Check if a prosthesis is equippable. It depends whether the player has a cut limb or not on that specific side. There's an exception for Upper arm, obviously
|
||||||
|
---@param fullType string
|
||||||
|
---@return boolean
|
||||||
|
function ProsthesisHandler.CheckIfEquippable(fullType)
|
||||||
|
--TOC_DEBUG.print("Current item is a prosthesis")
|
||||||
|
local side = CommonMethods.GetSide(fullType)
|
||||||
|
--TOC_DEBUG.print("Checking side: " .. tostring(side))
|
||||||
|
|
||||||
|
local highestAmputatedLimbs = CachedDataHandler.GetHighestAmputatedLimbs(getPlayer():getUsername())
|
||||||
|
|
||||||
|
if highestAmputatedLimbs then
|
||||||
|
local hal = highestAmputatedLimbs[side]
|
||||||
|
if hal and not string.contains(hal, "UpperArm") then
|
||||||
|
--TOC_DEBUG.print("Found acceptable limb to use prosthesis => " .. tostring(hal))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- No acceptable cut limbs
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
---Handle equipping or unequipping prosthetics
|
||||||
|
---@param item InventoryItem
|
||||||
|
---@param isEquipping boolean
|
||||||
|
---@return boolean
|
||||||
|
function ProsthesisHandler.SearchAndSetupProsthesis(item, isEquipping)
|
||||||
|
if not ProsthesisHandler.CheckIfProst(item) then return false end
|
||||||
|
|
||||||
|
local group = ProsthesisHandler.GetGroup(item)
|
||||||
|
TOC_DEBUG.print("Setup Prosthesis => " .. group .. " - is equipping? " .. tostring(isEquipping))
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
dcInst:setIsProstEquipped(group, isEquipping)
|
||||||
|
dcInst:apply()
|
||||||
|
|
||||||
|
-- Calculates hands feasibility once again
|
||||||
|
CachedDataHandler.CalculateBothHandsFeasibility()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
--* Overrides *--
|
||||||
|
|
||||||
|
|
||||||
|
---@param item InventoryItem
|
||||||
|
---@param isEquippable boolean
|
||||||
|
---@return unknown
|
||||||
|
local function HandleProsthesisValidation(item, isEquippable)
|
||||||
|
local isProst = ProsthesisHandler.CheckIfProst(item)
|
||||||
|
if not isProst then return isEquippable end
|
||||||
|
|
||||||
|
local fullType = item:getFullType() -- use fulltype for side
|
||||||
|
if isEquippable then
|
||||||
|
isEquippable = ProsthesisHandler.CheckIfEquippable(fullType)
|
||||||
|
else
|
||||||
|
getPlayer():Say(getText("UI_Say_CantEquip"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return isEquippable
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
local og_ISWearClothing_isValid = ISWearClothing.isValid
|
||||||
|
function ISWearClothing:isValid()
|
||||||
|
local isEquippable = og_ISWearClothing_isValid(self)
|
||||||
|
return HandleProsthesisValidation(self.item, isEquippable)
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISWearClothing_perform = ISWearClothing.perform
|
||||||
|
function ISWearClothing:perform()
|
||||||
|
ProsthesisHandler.SearchAndSetupProsthesis(self.item, true)
|
||||||
|
og_ISWearClothing_perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISClothingExtraAction_isValid = ISClothingExtraAction.isValid
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
function ISClothingExtraAction:isValid()
|
||||||
|
local isEquippable = og_ISClothingExtraAction_isValid(self)
|
||||||
|
-- self.extra is a string, not the item
|
||||||
|
local testItem = InventoryItemFactory.CreateItem(self.extra)
|
||||||
|
return HandleProsthesisValidation(testItem, isEquippable)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local og_ISClothingExtraAction_perform = ISClothingExtraAction.perform
|
||||||
|
function ISClothingExtraAction:perform()
|
||||||
|
local extraItem = InventoryItemFactory.CreateItem(self.extra)
|
||||||
|
ProsthesisHandler.SearchAndSetupProsthesis(extraItem, true)
|
||||||
|
og_ISClothingExtraAction_perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISUnequipAction_perform = ISUnequipAction.perform
|
||||||
|
function ISUnequipAction:perform()
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Horrendous workaround
|
||||||
|
|
||||||
|
To unequp items, the java side uses WornItems.setItem, which has
|
||||||
|
a check for multiItem. Basically, if it's active, it won't actually remove the item,
|
||||||
|
fucking things up. So, to be 100% sure that we're removing the items, we're gonna
|
||||||
|
disable and re-enable the multi-item bool for the Unequip Action.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local isProst = ProsthesisHandler.SearchAndSetupProsthesis(self.item, false)
|
||||||
|
local group
|
||||||
|
if isProst then
|
||||||
|
group = BodyLocations.getGroup("Human")
|
||||||
|
group:setMultiItem("TOC_ArmProst", false)
|
||||||
|
end
|
||||||
|
og_ISUnequipAction_perform(self)
|
||||||
|
|
||||||
|
if isProst then
|
||||||
|
group:setMultiItem("TOC_ArmProst", true)
|
||||||
|
|
||||||
|
-- we need to fetch the limbname associated to the prosthesis
|
||||||
|
local side = CommonMethods.GetSide(self.item:getFullType())
|
||||||
|
local highestAmputatedLimbs = CachedDataHandler.GetHighestAmputatedLimbs(getPlayer():getUsername())
|
||||||
|
if highestAmputatedLimbs then
|
||||||
|
local hal = highestAmputatedLimbs[side]
|
||||||
|
if hal then
|
||||||
|
-- This could break if amputated limbs aren't cached for some reason
|
||||||
|
triggerEvent("OnProsthesisUnequipped", hal)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ProsthesisHandler
|
||||||
71
media/lua/client/TOC/Main.lua
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
local CommandsData = require("TOC/CommandsData")
|
||||||
|
require("TOC/Events")
|
||||||
|
------------------
|
||||||
|
|
||||||
|
---@class Main
|
||||||
|
local Main = {
|
||||||
|
_version = "2.1.4"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Main.Start()
|
||||||
|
TOC_DEBUG.print("Starting The Only Cure version " .. tostring(Main._version))
|
||||||
|
Main.SetupEvents()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Main.SetupEvents()
|
||||||
|
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||||
|
Events.OnReceivedTocData.Add(CachedDataHandler.CalculateCacheableValues)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Main.InitializePlayer()
|
||||||
|
---Looop until we've successfully initialized the mod
|
||||||
|
local function TryToInitialize()
|
||||||
|
local pl = getPlayer()
|
||||||
|
TOC_DEBUG.print("Current username in TryToInitialize: " .. pl:getUsername())
|
||||||
|
if pl:getUsername() == "Bob" then
|
||||||
|
TOC_DEBUG.print("Username is still Bob, waiting")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
LocalPlayerController.InitializePlayer(false)
|
||||||
|
Events.OnTick.Remove(TryToInitialize)
|
||||||
|
end
|
||||||
|
CommonMethods.SafeStartEvent("OnTick", TryToInitialize)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Clean the TOC table for that SP player, to prevent it from clogging ModData up
|
||||||
|
---@param player IsoPlayer
|
||||||
|
function Main.WipeData(player)
|
||||||
|
local username = player:getUsername()
|
||||||
|
TOC_DEBUG.print("Wiping data after death: " .. username)
|
||||||
|
local key = CommandsData.GetKey(username)
|
||||||
|
|
||||||
|
--ModData.remove(key)
|
||||||
|
|
||||||
|
if not isClient() then
|
||||||
|
-- For SP, it's enough just removing the data this way
|
||||||
|
ModData.remove(key)
|
||||||
|
else
|
||||||
|
-- Different story for MP, we're gonna 'force' it to reload it
|
||||||
|
-- at the next character by passing an empty mod data
|
||||||
|
ModData.add(key, {})
|
||||||
|
ModData.transmit(key)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Let's wipe the instance too just to be sure
|
||||||
|
-- TODO This can break things I guess
|
||||||
|
--local DataController = require("TOC/Controllers/DataController")
|
||||||
|
--DataController.DestroyInstance(username)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--* Events *--
|
||||||
|
|
||||||
|
Events.OnGameStart.Add(Main.Start)
|
||||||
|
Events.OnCreatePlayer.Add(Main.InitializePlayer)
|
||||||
|
Events.OnPlayerDeath.Add(Main.WipeData)
|
||||||
207
media/lua/client/TOC/Tests.lua
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
if not getActivatedMods():contains("TEST_FRAMEWORK") or not isDebugEnabled() then return end
|
||||||
|
local TestFramework = require("TestFramework/TestFramework")
|
||||||
|
local TestUtils = require("TestFramework/TestUtils")
|
||||||
|
|
||||||
|
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
|
||||||
|
local AmputationHandler = require("TOC/Handlers/AmputationHandler")
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local StaticData = require("TOC/StaticData")
|
||||||
|
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("LocalPlayerController", "Setup", function()
|
||||||
|
local Tests = {}
|
||||||
|
function Tests.InitializePlayer()
|
||||||
|
LocalPlayerController.InitializePlayer(true)
|
||||||
|
end
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("LocalPlayerController", "Perks", function()
|
||||||
|
local Tests = {}
|
||||||
|
|
||||||
|
function Tests.SetMaxPerks()
|
||||||
|
local pl = getPlayer()
|
||||||
|
for _=0, 10 do
|
||||||
|
pl:LevelPerk(Perks["Side_L"])
|
||||||
|
pl:LevelPerk(Perks["Side_R"])
|
||||||
|
pl:getXp():setXPToLevel(Perks["Side_L"], pl:getPerkLevel(Perks["Side_L"]))
|
||||||
|
pl:getXp():setXPToLevel(Perks["Side_R"], pl:getPerkLevel(Perks["Side_R"]))
|
||||||
|
end
|
||||||
|
|
||||||
|
SyncXp(pl)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.ResetPerks()
|
||||||
|
local pl = getPlayer()
|
||||||
|
for _=0, 10 do
|
||||||
|
pl:LoseLevel(Perks["Side_L"])
|
||||||
|
pl:LoseLevel(Perks["Side_R"])
|
||||||
|
pl:getXp():setXPToLevel(Perks["Side_L"], pl:getPerkLevel(Perks["Side_L"]))
|
||||||
|
pl:getXp():setXPToLevel(Perks["Side_R"], pl:getPerkLevel(Perks["Side_R"]))
|
||||||
|
end
|
||||||
|
SyncXp(pl)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("LocalPlayerController", "Cicatrization", function()
|
||||||
|
local Tests = {}
|
||||||
|
|
||||||
|
function Tests.SetCicatrizationTimeToOne()
|
||||||
|
for i=1, #StaticData.LIMBS_STR do
|
||||||
|
local limbName = StaticData.LIMBS_STR[i]
|
||||||
|
DataController.GetInstance():setCicatrizationTime(limbName, 1)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getCicatrizationTime(limbName) == 1)
|
||||||
|
end
|
||||||
|
DataController.GetInstance():apply()
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("Hand_L"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("AmputationHandler", "Top Left", function()
|
||||||
|
local Tests = {}
|
||||||
|
|
||||||
|
function Tests.CutLeftHand()
|
||||||
|
local handler = AmputationHandler:new("Hand_L")
|
||||||
|
handler:execute(true)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("Hand_L"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CutLeftForearm()
|
||||||
|
local handler = AmputationHandler:new("ForeArm_L")
|
||||||
|
handler:execute(true)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("ForeArm_L") and DataController.GetInstance():getIsCut("Hand_L"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CutLeftUpperarm()
|
||||||
|
local handler = AmputationHandler:new("UpperArm_L")
|
||||||
|
handler:execute(true)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("UpperArm_L") and DataController.GetInstance():getIsCut("ForeArm_L") and DataController.GetInstance():getIsCut("Hand_L"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("AmputationHandler", "Top Right", function()
|
||||||
|
local Tests = {}
|
||||||
|
|
||||||
|
function Tests.CutRightHand()
|
||||||
|
local handler = AmputationHandler:new("Hand_R")
|
||||||
|
handler:execute(true)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("Hand_R"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CutRightForearm()
|
||||||
|
local handler = AmputationHandler:new("ForeArm_R")
|
||||||
|
handler:execute(true)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("ForeArm_R") and DataController.GetInstance():getIsCut("Hand_R"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CutRightUpperarm()
|
||||||
|
local handler = AmputationHandler:new("UpperArm_R")
|
||||||
|
handler:execute(true)
|
||||||
|
TestUtils.assert(DataController.GetInstance():getIsCut("UpperArm_R") and DataController.GetInstance():getIsCut("ForeArm_R") and DataController.GetInstance():getIsCut("Hand_R"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("TimedActions", "CauterizeAction", function()
|
||||||
|
local Tests = {}
|
||||||
|
local CauterizeAction = require("TOC/TimedActions/CauterizeAction")
|
||||||
|
|
||||||
|
function Tests.CauterizeLeftHand()
|
||||||
|
ISTimedActionQueue.add(CauterizeAction:new(getPlayer(), "Hand_L", getPlayer()))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CauterizeLefForeArm()
|
||||||
|
ISTimedActionQueue.add(CauterizeAction:new(getPlayer(), "ForeArm_L", getPlayer()))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CauterizeLeftUpperArm()
|
||||||
|
ISTimedActionQueue.add(CauterizeAction:new(getPlayer(), "UpperArm_L", getPlayer()))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CauterizeRightHand()
|
||||||
|
ISTimedActionQueue.add(CauterizeAction:new(getPlayer(), "Hand_R", getPlayer()))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CauterizeRightForeArm()
|
||||||
|
ISTimedActionQueue.add(CauterizeAction:new(getPlayer(), "ForeArm_R", getPlayer()))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.CauterizeRightUpperArm()
|
||||||
|
ISTimedActionQueue.add(CauterizeAction:new(getPlayer(), "UpperArm_R", getPlayer()))
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("Various", "Player", function()
|
||||||
|
local Tests = {}
|
||||||
|
|
||||||
|
|
||||||
|
function Tests.BleedTest()
|
||||||
|
local pl = getPlayer()
|
||||||
|
|
||||||
|
--pl:getBodyDamage():getBodyPart(BodyPartType.ForeArm_R):setBleeding(true)
|
||||||
|
pl:getBodyDamage():getBodyPart(BodyPartType.ForeArm_R):setBleedingTime(20)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Tests.Kill()
|
||||||
|
getPlayer():Kill(getPlayer())
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
TestFramework.registerTestModule("Various", "Visuals", function()
|
||||||
|
local Tests = {}
|
||||||
|
|
||||||
|
function Tests.AddBloodLeftForearm()
|
||||||
|
local playerObj = getPlayer()
|
||||||
|
local limbName = "ForeArm_L"
|
||||||
|
local fullType = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName
|
||||||
|
|
||||||
|
|
||||||
|
local item = playerObj:getInventory():FindAndReturn(fullType)
|
||||||
|
if instanceof(item, "Clothing") then
|
||||||
|
|
||||||
|
---@cast item Clothing
|
||||||
|
|
||||||
|
print("Found limb to add blood onto")
|
||||||
|
item:setBloodLevel(100)
|
||||||
|
local coveredParts = BloodClothingType.getCoveredParts(item:getBloodClothingType())
|
||||||
|
if coveredParts then
|
||||||
|
for j=0,coveredParts:size()-1 do
|
||||||
|
item:setBlood(coveredParts:get(j), 100)
|
||||||
|
item:setDirt(coveredParts:get(j), 100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
playerObj:resetModelNextFrame()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tests
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
if not getActivatedMods():contains("PerfTestFramework") or not isDebugEnabled() then return end
|
||||||
|
local PerfTest = require("PerfTest/main") -- SHould be global anyway
|
||||||
|
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||||
|
|
||||||
|
PerfTest.RegisterMethod("LocalPlayerController", LocalPlayerController, "InitializePlayer")
|
||||||
|
PerfTest.RegisterMethod("LocalPlayerController", LocalPlayerController, "UpdateAmputations")
|
||||||
|
PerfTest.RegisterMethod("CachedDataHandler", CachedDataHandler, "CalculateHighestAmputatedLimbs")
|
||||||
|
PerfTest.RegisterMethod("ISHealthPanel", ISHealthPanel, "render")
|
||||||
|
|
||||||
|
PerfTest.Init()
|
||||||
89
media/lua/client/TOC/TimedActions/CauterizeAction.lua
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
require "TimedActions/ISBaseTimedAction"
|
||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local LocalPlayerController = require("TOC/Controllers/LocalPlayerController")
|
||||||
|
---------------
|
||||||
|
|
||||||
|
---@class CauterizeAction : ISBaseTimedAction
|
||||||
|
---@field character IsoPlayer
|
||||||
|
---@field ovenObj IsoObject
|
||||||
|
---@field limbName string
|
||||||
|
local CauterizeAction = ISBaseTimedAction:derive("CauterizeAction")
|
||||||
|
|
||||||
|
---@param character IsoPlayer
|
||||||
|
---@param stoveObj IsoObject
|
||||||
|
---@param limbName string
|
||||||
|
---@return CauterizeAction
|
||||||
|
function CauterizeAction:new(character, limbName, stoveObj)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
|
||||||
|
-- We need to follow ISBaseTimedAction. self.character is gonna be the surgeon
|
||||||
|
o.character = character
|
||||||
|
o.stoveObj = stoveObj
|
||||||
|
o.limbName = limbName
|
||||||
|
|
||||||
|
o.stopOnWalk = true
|
||||||
|
o.stopOnRun = true
|
||||||
|
|
||||||
|
-- Max time depends on the strength
|
||||||
|
o.maxTime = 20
|
||||||
|
if o.character:isTimedActionInstant() then o.maxTime = 1 end
|
||||||
|
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:isValid()
|
||||||
|
return not ISHealthPanel.DidPatientMove(self.character, self.character, self.character:getX(), self.character:getY())
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:waitToStart()
|
||||||
|
self.character:faceThisObject(self.ovenObj)
|
||||||
|
return self.character:shouldBeTurning()
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:start()
|
||||||
|
self:setActionAnim("Loot") -- TODO Better anim pls
|
||||||
|
|
||||||
|
-- Setup audio
|
||||||
|
self.sound = self.character:getEmitter():playSound("Cauterization")
|
||||||
|
local radius = 5
|
||||||
|
addSound(self.character, self.character:getX(), self.character:getY(), self.character:getZ(), radius, radius)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:update()
|
||||||
|
self.character:setMetabolicTarget(Metabolics.HeavyWork)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:stopSound()
|
||||||
|
if self.sound then
|
||||||
|
self.character:getEmitter():stopSound(self.sound)
|
||||||
|
self.sound = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:stop()
|
||||||
|
self:stopSound()
|
||||||
|
ISBaseTimedAction.stop(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CauterizeAction:perform()
|
||||||
|
-- Stop the sound
|
||||||
|
self:stopSound()
|
||||||
|
|
||||||
|
local dcInst = DataController.GetInstance()
|
||||||
|
dcInst:setCicatrizationTime(self.limbName, 0)
|
||||||
|
dcInst:setIsCauterized(self.limbName, true)
|
||||||
|
|
||||||
|
-- Set isCicatrized and the visuals in one go, since this action is gonna be run only on a single client
|
||||||
|
LocalPlayerController.HandleSetCicatrization(dcInst, self.character, self.limbName)
|
||||||
|
|
||||||
|
-- TODO Add specific visuals for cauterization
|
||||||
|
|
||||||
|
-- we don't care about the depended limbs, since they're alread "cicatrized"
|
||||||
|
dcInst:apply()
|
||||||
|
|
||||||
|
ISBaseTimedAction.perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return CauterizeAction
|
||||||
123
media/lua/client/TOC/TimedActions/CleanWoundAction.lua
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
local DataController = require("TOC/Controllers/DataController")
|
||||||
|
local CommonMethods = require("TOC/CommonMethods")
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
---@class CleanWoundAction : ISBaseTimedAction
|
||||||
|
---@field doctor IsoPlayer
|
||||||
|
---@field otherPlayer IsoPlayer
|
||||||
|
---@field bandage InventoryItem
|
||||||
|
---@field bodyPart any
|
||||||
|
local CleanWoundAction = ISBaseTimedAction:derive("CleanWoundAction")
|
||||||
|
|
||||||
|
---@param doctor IsoPlayer
|
||||||
|
---@param otherPlayer IsoPlayer
|
||||||
|
---@param bandage InventoryItem
|
||||||
|
---@param bodyPart any
|
||||||
|
---@return CleanWoundAction
|
||||||
|
function CleanWoundAction:new(doctor, otherPlayer, bandage, bodyPart)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
o.character = doctor
|
||||||
|
o.otherPlayer = otherPlayer
|
||||||
|
o.doctorLevel = doctor:getPerkLevel(Perks.Doctor)
|
||||||
|
o.bodyPart = bodyPart
|
||||||
|
o.bandage = bandage
|
||||||
|
o.stopOnWalk = true
|
||||||
|
o.stopOnRun = true
|
||||||
|
|
||||||
|
o.bandagedPlayerX = otherPlayer:getX()
|
||||||
|
o.bandagedPlayerY = otherPlayer:getY()
|
||||||
|
|
||||||
|
o.maxTime = 250 - (o.doctorLevel * 6)
|
||||||
|
if doctor:isTimedActionInstant() then
|
||||||
|
o.maxTime = 1
|
||||||
|
end
|
||||||
|
if doctor:getAccessLevel() ~= "None" then
|
||||||
|
o.doctorLevel = 10
|
||||||
|
end
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
function CleanWoundAction:isValid()
|
||||||
|
if ISHealthPanel.DidPatientMove(self.character, self.otherPlayer, self.bandagedPlayerX, self.bandagedPlayerY) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function CleanWoundAction:waitToStart()
|
||||||
|
if self.character == self.otherPlayer then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
self.character:faceThisObject(self.otherPlayer)
|
||||||
|
return self.character:shouldBeTurning()
|
||||||
|
end
|
||||||
|
|
||||||
|
function CleanWoundAction:update()
|
||||||
|
if self.character ~= self.otherPlayer then
|
||||||
|
self.character:faceThisObject(self.otherPlayer)
|
||||||
|
end
|
||||||
|
local jobType = getText("ContextMenu_CleanWound")
|
||||||
|
ISHealthPanel.setBodyPartActionForPlayer(self.otherPlayer, self.bodyPart, self, jobType, { cleanBurn = true })
|
||||||
|
self.character:setMetabolicTarget(Metabolics.LightDomestic)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CleanWoundAction:start()
|
||||||
|
if self.character == self.otherPlayer then
|
||||||
|
self:setActionAnim(CharacterActionAnims.Bandage)
|
||||||
|
self:setAnimVariable("BandageType", ISHealthPanel.getBandageType(self.bodyPart))
|
||||||
|
self.character:reportEvent("EventBandage")
|
||||||
|
else
|
||||||
|
self:setActionAnim("Loot")
|
||||||
|
self.character:SetVariable("LootPosition", "Mid")
|
||||||
|
self.character:reportEvent("EventLootItem")
|
||||||
|
end
|
||||||
|
self:setOverrideHandModels(nil, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CleanWoundAction:stop()
|
||||||
|
ISHealthPanel.setBodyPartActionForPlayer(self.otherPlayer, self.bodyPart, nil, nil, nil)
|
||||||
|
ISBaseTimedAction.stop(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CleanWoundAction:perform()
|
||||||
|
|
||||||
|
TOC_DEBUG.print("CleanWound for " .. self.otherPlayer:getUsername())
|
||||||
|
|
||||||
|
if self.character:HasTrait("Hemophobic") then
|
||||||
|
self.character:getStats():setPanic(self.character:getStats():getPanic() + 15)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.character:getXp():AddXP(Perks.Doctor, 10)
|
||||||
|
local addPain = (60 - (self.doctorLevel * 1))
|
||||||
|
self.bodyPart:setAdditionalPain(self.bodyPart:getAdditionalPain() + addPain)
|
||||||
|
self.bandage:Use()
|
||||||
|
|
||||||
|
-- TOC Data handling
|
||||||
|
|
||||||
|
local limbName = CommonMethods.GetLimbNameFromBodyPart(self.bodyPart)
|
||||||
|
local dcInst = DataController.GetInstance(self.otherPlayer:getUsername())
|
||||||
|
|
||||||
|
local currentWoundDirtyness = dcInst:getWoundDirtyness(limbName)
|
||||||
|
local newWoundDirtyness = currentWoundDirtyness - (self.bandage:getBandagePower() * 10)
|
||||||
|
if newWoundDirtyness < 0 then newWoundDirtyness = 0 end
|
||||||
|
|
||||||
|
dcInst:setWoundDirtyness(limbName, newWoundDirtyness)
|
||||||
|
|
||||||
|
dcInst:apply()
|
||||||
|
|
||||||
|
-- Clean visual
|
||||||
|
local bbptEnum = BloodBodyPartType[limbName]
|
||||||
|
|
||||||
|
---@type HumanVisual
|
||||||
|
local visual = self.otherPlayer:getHumanVisual()
|
||||||
|
visual:setDirt(bbptEnum, 0)
|
||||||
|
visual:setBlood(bbptEnum, 0)
|
||||||
|
|
||||||
|
ISHealthPanel.setBodyPartActionForPlayer(self.otherPlayer, self.bodyPart, nil, nil, nil)
|
||||||
|
|
||||||
|
-- needed to remove from queue / start next.
|
||||||
|
ISBaseTimedAction.perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return CleanWoundAction
|
||||||
138
media/lua/client/TOC/TimedActions/CutLimbAction.lua
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
require "TimedActions/ISBaseTimedAction"
|
||||||
|
local AmputationHandler = require("TOC/Handlers/AmputationHandler")
|
||||||
|
local CommandsData = require("TOC/CommandsData")
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
---@class CutLimbAction : ISBaseTimedAction
|
||||||
|
---@field patient IsoPlayer
|
||||||
|
---@field character IsoPlayer
|
||||||
|
---@field patientX number
|
||||||
|
---@field patientY number
|
||||||
|
---@field limbName string
|
||||||
|
---@field item InventoryItem
|
||||||
|
---@field stitchesItem InventoryItem?
|
||||||
|
---@field bandageItem InventoryItem?
|
||||||
|
local CutLimbAction = ISBaseTimedAction:derive("CutLimbAction")
|
||||||
|
|
||||||
|
---Starts CutLimbAction
|
||||||
|
---@param surgeon IsoPlayer This is gonna be self.character to have working animations
|
||||||
|
---@param patient IsoPlayer
|
||||||
|
---@param limbName string
|
||||||
|
---@param item InventoryItem This is gonna be the saw, following ISBaseTimedAction
|
||||||
|
---@param stitchesItem InventoryItem?
|
||||||
|
---@param bandageItem InventoryItem?
|
||||||
|
---@return CutLimbAction
|
||||||
|
function CutLimbAction:new(surgeon, patient, limbName, item, stitchesItem, bandageItem)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
|
||||||
|
-- We need to follow ISBaseTimedAction. self.character is gonna be the surgeon
|
||||||
|
o.character = surgeon
|
||||||
|
o.patient = patient
|
||||||
|
o.limbName = limbName
|
||||||
|
o.item = item
|
||||||
|
|
||||||
|
o.patientX = patient:getX()
|
||||||
|
o.patientY = patient:getY()
|
||||||
|
|
||||||
|
o.stitchesItem = stitchesItem or nil
|
||||||
|
o.bandageItem = bandageItem or nil
|
||||||
|
|
||||||
|
o.stopOnWalk = true
|
||||||
|
o.stopOnRun = true
|
||||||
|
|
||||||
|
o.maxTime = 1000 - (surgeon:getPerkLevel(Perks.Doctor) * 50)
|
||||||
|
if o.character:isTimedActionInstant() then o.maxTime = 1 end
|
||||||
|
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:isValid()
|
||||||
|
return not ISHealthPanel.DidPatientMove(self.character,self.patient, self.patientX, self.patientY)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:start()
|
||||||
|
if self.patient == self.character then
|
||||||
|
-- Self
|
||||||
|
AmputationHandler.ApplyDamageDuringAmputation(self.patient, self.limbName)
|
||||||
|
else
|
||||||
|
-- Another player
|
||||||
|
---@type relayDamageDuringAmputationParams
|
||||||
|
local params = {patientNum = self.patient:getOnlineID(), limbName = self.limbName}
|
||||||
|
sendClientCommand(CommandsData.modules.TOC_RELAY, CommandsData.server.Relay.RelayDamageDuringAmputation, params )
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type ISBaseTimedAction
|
||||||
|
local prevAction = self
|
||||||
|
|
||||||
|
-- Handle stitching
|
||||||
|
if self.stitchesItem then
|
||||||
|
TOC_DEBUG.print("Stitches...")
|
||||||
|
prevAction = AmputationHandler.PrepareStitchesAction(prevAction, self.limbName, self.character, self.patient, self.stitchesItem)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Handle bandages
|
||||||
|
if self.bandageItem then
|
||||||
|
prevAction = AmputationHandler.PrepareBandagesAction(prevAction, self.limbName, self.character, self.patient, self.bandageItem)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setup cosmetic stuff
|
||||||
|
self:setActionAnim("SawLog")
|
||||||
|
self:setOverrideHandModels(self.item:getStaticModel())
|
||||||
|
|
||||||
|
-- Setup audio
|
||||||
|
self.sound = self.character:getEmitter():playSound("Amputation")
|
||||||
|
local radius = 5
|
||||||
|
addSound(self.character, self.character:getX(), self.character:getY(), self.character:getZ(), radius, radius)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:waitToStart()
|
||||||
|
if self.character == self.patient then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
self.character:faceThisObject(self.patient)
|
||||||
|
return self.character:shouldBeTurning()
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:update()
|
||||||
|
self.character:setMetabolicTarget(Metabolics.HeavyWork)
|
||||||
|
if self.character ~= self.patient then
|
||||||
|
self.patient:setMetabolicTarget(Metabolics.HeavyWork)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:stopSound()
|
||||||
|
if self.sound then
|
||||||
|
self.character:getEmitter():stopSound(self.sound)
|
||||||
|
self.sound = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:stop()
|
||||||
|
self:stopSound()
|
||||||
|
ISBaseTimedAction.stop(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CutLimbAction:perform()
|
||||||
|
-- Stop the sound
|
||||||
|
self:stopSound()
|
||||||
|
|
||||||
|
if self.patient == self.character then
|
||||||
|
TOC_DEBUG.print("patient and surgeon are the same, executing on the client")
|
||||||
|
local handler = AmputationHandler:new(self.limbName)
|
||||||
|
handler:execute(true)
|
||||||
|
else
|
||||||
|
TOC_DEBUG.print("patient and surgeon not the same, sending relay to server")
|
||||||
|
-- Other player
|
||||||
|
---@type relayExecuteAmputationActionParams
|
||||||
|
local params = {patientNum = self.patient:getOnlineID(), limbName = self.limbName}
|
||||||
|
sendClientCommand(CommandsData.modules.TOC_RELAY, CommandsData.server.Relay.RelayExecuteAmputationAction, params )
|
||||||
|
end
|
||||||
|
|
||||||
|
ISBaseTimedAction.perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return CutLimbAction
|
||||||
139
media/lua/client/TOC/TimedActions/IgnoredActions.lua
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
-- TODO This section must be overhauled
|
||||||
|
|
||||||
|
-- local DataController = require("TOC/Controllers/DataController")
|
||||||
|
-- local StaticData = require("TOC/StaticData")
|
||||||
|
|
||||||
|
---@diagnostic disable: duplicate-set-field
|
||||||
|
-- Bunch of actions shouldn't be modified by the adjusted time
|
||||||
|
|
||||||
|
-----------------------------------------------
|
||||||
|
---* Some actions have specific maxTime calculations and we must account for that
|
||||||
|
---ISAttachItemHotbar
|
||||||
|
---ISDetachItemHotbar
|
||||||
|
---ISEquipWeaponAction
|
||||||
|
---ISUnequipAction
|
||||||
|
|
||||||
|
-- --- We're forced to re-run this crap to fix it
|
||||||
|
-- ---@param action ISBaseTimedAction
|
||||||
|
-- local function HandleSpeedSpecificAction(action, time)
|
||||||
|
-- action.skipTOC = true
|
||||||
|
-- action.maxTime = time
|
||||||
|
-- action.animSpeed = 1.0
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- local og_ISAttachItemHotbar_new = ISAttachItemHotbar.new
|
||||||
|
-- function ISAttachItemHotbar:new(character, item, slot, slotIndex, slotDef)
|
||||||
|
-- local action = og_ISAttachItemHotbar_new(self, character, item, slot, slotIndex, slotDef)
|
||||||
|
-- HandleSpeedSpecificAction(action, -1)
|
||||||
|
-- return action
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- local og_ISDetachItemHotbar_new = ISDetachItemHotbar.new
|
||||||
|
-- function ISDetachItemHotbar:new(character, item)
|
||||||
|
-- local action = og_ISDetachItemHotbar_new(self, character, item)
|
||||||
|
-- HandleSpeedSpecificAction(action, -1)
|
||||||
|
-- return action
|
||||||
|
-- end
|
||||||
|
|
||||||
|
|
||||||
|
-- local og_ISEquipWeaponAction_new = ISEquipWeaponAction.new
|
||||||
|
-- function ISEquipWeaponAction:new(character, item, time, primary, twoHands)
|
||||||
|
|
||||||
|
-- local action = og_ISEquipWeaponAction_new(self, character, item, time, primary, twoHands)
|
||||||
|
-- TOC_DEBUG.print("Override ISEquipWeaponAction New")
|
||||||
|
|
||||||
|
|
||||||
|
-- -- check if right arm is cut off or not. if it is, penality shall apply
|
||||||
|
-- -- if we got here, the action is valid, so we know that we have a prosthesis.
|
||||||
|
|
||||||
|
|
||||||
|
-- local dcInst = DataController.GetInstance()
|
||||||
|
|
||||||
|
-- if not dcInst:getIsCut(StaticData.LIMBS_IND_STR.Hand_R) then
|
||||||
|
-- action.skipTOC = true
|
||||||
|
-- action.maxTime = time
|
||||||
|
-- action.animSpeed = 1.0
|
||||||
|
-- TOC_DEBUG.print("Skipping TOC for ISEquipWeaponAction new")
|
||||||
|
-- end
|
||||||
|
|
||||||
|
|
||||||
|
-- -- if not twoHands then
|
||||||
|
-- -- TOC_DEBUG.print("Not a two handed action, re-adding skip TOC")
|
||||||
|
-- -- HandleSpeedSpecificAction(action)
|
||||||
|
-- -- end
|
||||||
|
-- return action
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- local og_ISUnequipAction_new = ISUnequipAction.new
|
||||||
|
-- function ISUnequipAction:new(character, item, time)
|
||||||
|
-- local action = og_ISUnequipAction_new(self, character, item, time)
|
||||||
|
-- ---@cast item InventoryItem
|
||||||
|
|
||||||
|
-- -- For some reason (I have no clue why), if we re-run the method it breaks basically every unequip clothing action. Not for weapons though.
|
||||||
|
-- if instanceof(item, 'HandWeapon') then
|
||||||
|
-- --print("Running handlespeedspecificaction")
|
||||||
|
-- HandleSpeedSpecificAction(action)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- return action
|
||||||
|
-- end
|
||||||
|
|
||||||
|
------------------------------------------------------
|
||||||
|
--- Normal cases
|
||||||
|
|
||||||
|
|
||||||
|
local og_ISEatFoodAction_new = ISEatFoodAction.new
|
||||||
|
function ISEatFoodAction:new(character, item, percentage)
|
||||||
|
local action = og_ISEatFoodAction_new(self, character, item, percentage)
|
||||||
|
--TOC_DEBUG.print("Override ISEatFoodAction")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISReadABook_new = ISReadABook.new
|
||||||
|
function ISReadABook:new(character, item, time)
|
||||||
|
local action = og_ISReadABook_new(self, character, item, time)
|
||||||
|
--TOC_DEBUG.print("Override ISReadABook")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISTakePillAction_new = ISTakePillAction.new
|
||||||
|
function ISTakePillAction:new(character, item, time)
|
||||||
|
local action = og_ISTakePillAction_new(self, character, item, time)
|
||||||
|
--TOC_DEBUG.print("Override ISTakePillAction")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISTakeWaterAction_new = ISTakeWaterAction.new
|
||||||
|
function ISTakeWaterAction:new(character, item, waterUnit, waterObject, time, oldItem)
|
||||||
|
local action = og_ISTakeWaterAction_new(self, character, item, waterUnit, waterObject, time, oldItem)
|
||||||
|
--TOC_DEBUG.print("Override ISTakeWaterAction")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISDrinkFromBottle_new = ISDrinkFromBottle.new
|
||||||
|
function ISDrinkFromBottle:new(character, item, uses)
|
||||||
|
local action = og_ISDrinkFromBottle_new(self, character, item, uses)
|
||||||
|
--TOC_DEBUG.print("Override ISDrinkFromBottle")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISFinalizeDealAction_new = ISFinalizeDealAction.new
|
||||||
|
function ISFinalizeDealAction:new(player, otherPlayer, itemsToGive, itemsToReceive, time)
|
||||||
|
local action = og_ISFinalizeDealAction_new(self, player, otherPlayer, itemsToGive, itemsToReceive, time)
|
||||||
|
--TOC_DEBUG.print("Override ISFinalizeDealAction")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||
|
|
||||||
|
local og_ISCampingInfoAction_new = ISCampingInfoAction.new
|
||||||
|
function ISCampingInfoAction:new(character, campfireObject, campfire)
|
||||||
|
local action = og_ISCampingInfoAction_new(self, character, campfireObject, campfire)
|
||||||
|
--TOC_DEBUG.print("Override ISCampingInfoAction")
|
||||||
|
action.skipTOC = true
|
||||||
|
return action
|
||||||
|
end
|
||||||