Merge branch 'dev-42.13' of https://github.com/ZioPao/The-Only-Cure into dev-42.13-merge
This commit is contained in:
62
42/media/clothing/clothingItems/Amputation_ForeArm_L.xml
Normal file
62
42/media/clothing/clothingItems/Amputation_ForeArm_L.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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>4</m_Masks>
|
||||
<m_Masks>3</m_Masks>
|
||||
|
||||
<!-- <m_UnderlayMasksFolder>media/textures/Amputations/Masks</m_UnderlayMasksFolder> -->
|
||||
|
||||
|
||||
<!-- 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>
|
||||
60
42/media/clothing/clothingItems/Amputation_ForeArm_R.xml
Normal file
60
42/media/clothing/clothingItems/Amputation_ForeArm_R.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?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>
|
||||
|
||||
<!-- <m_UnderlayMasksFolder>media/textures/Amputations/Masks</m_UnderlayMasksFolder> -->
|
||||
|
||||
<!-- 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>
|
||||
39
42/media/clothing/clothingItems/Amputation_Hand_L.xml
Normal file
39
42/media/clothing/clothingItems/Amputation_Hand_L.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\Hand\skin01_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin02_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin03_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin04_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin05_b</textureChoices>
|
||||
|
||||
<textureChoices>Amputations\Human\Hand\skin01_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin02_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin03_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin04_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\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>
|
||||
|
||||
</clothingItem>
|
||||
37
42/media/clothing/clothingItems/Amputation_Hand_R.xml
Normal file
37
42/media/clothing/clothingItems/Amputation_Hand_R.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<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\Hand\skin01_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin02_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin03_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin04_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin05_b</textureChoices>
|
||||
|
||||
<textureChoices>Amputations\Human\Hand\skin01_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin02_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin03_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\skin04_hairy_b</textureChoices>
|
||||
<textureChoices>Amputations\Human\Hand\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>
|
||||
</clothingItem>
|
||||
58
42/media/clothing/clothingItems/Amputation_UpperArm_L.xml
Normal file
58
42/media/clothing/clothingItems/Amputation_UpperArm_L.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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>
|
||||
|
||||
<!-- <m_UnderlayMasksFolder>media/textures/Amputations/Masks</m_UnderlayMasksFolder> -->
|
||||
|
||||
<!-- 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>
|
||||
58
42/media/clothing/clothingItems/Amputation_UpperArm_R.xml
Normal file
58
42/media/clothing/clothingItems/Amputation_UpperArm_R.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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>
|
||||
<!-- <m_UnderlayMasksFolder>media/textures/Amputations/Masks</m_UnderlayMasksFolder> -->
|
||||
|
||||
<!-- 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
42/media/clothing/clothingItems/Prost_HookArm_L.xml
Normal file
10
42/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
42/media/clothing/clothingItems/Prost_HookArm_R.xml
Normal file
10
42/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>
|
||||
10
42/media/clothing/clothingItems/Prost_NormalArm_L.xml
Normal file
10
42/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
42/media/clothing/clothingItems/Prost_NormalArm_R.xml
Normal file
10
42/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>
|
||||
10
42/media/clothing/clothingItems/Surg_Arm_Tourniquet_L.xml
Normal file
10
42/media/clothing/clothingItems/Surg_Arm_Tourniquet_L.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<clothingItem>
|
||||
<m_MaleModel>Surgery\Tourniquet_Left</m_MaleModel>
|
||||
<m_FemaleModel>Surgery\Tourniquet_Left</m_FemaleModel>
|
||||
<m_GUID>afbab35d-8bd4-4d61-87c7-054651ead1bd</m_GUID>
|
||||
<m_Static>false</m_Static>
|
||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||
<textureChoices>Surgery\tourniquet</textureChoices>
|
||||
</clothingItem>
|
||||
10
42/media/clothing/clothingItems/Surg_Arm_Tourniquet_R.xml
Normal file
10
42/media/clothing/clothingItems/Surg_Arm_Tourniquet_R.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<clothingItem>
|
||||
<m_MaleModel>Surgery\Tourniquet_Right</m_MaleModel>
|
||||
<m_FemaleModel>Surgery\Tourniquet_Right</m_FemaleModel>
|
||||
<m_GUID>9a5fe063-63c7-4e6f-81ca-ee77c6678e0d</m_GUID>
|
||||
<m_Static>false</m_Static>
|
||||
<m_AllowRandomHue>false</m_AllowRandomHue>
|
||||
<m_AllowRandomTint>false</m_AllowRandomTint>
|
||||
<textureChoices>Surgery\tourniquet</textureChoices>
|
||||
</clothingItem>
|
||||
61
42/media/fileGuidTable.xml
Normal file
61
42/media/fileGuidTable.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fileGuidTable>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Amputation_Hand_R.xml</path>
|
||||
<guid>f114e53a-b92e-4639-8d8c-2b43ab981885</guid>
|
||||
</files>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Amputation_ForeArm_R.xml</path>
|
||||
<guid>e6f80efd-22e5-49e0-8b24-537519d42b37</guid>
|
||||
</files>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Amputation_UpperArm_R.xml</path>
|
||||
<guid>db8ccad2-b76f-44bd-93ab-1eefa25beade</guid>
|
||||
</files>
|
||||
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Amputation_Hand_L.xml</path>
|
||||
<guid>2de93af2-b7a8-4c04-84d1-28d92cce8a0f</guid>
|
||||
</files>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Amputation_ForeArm_L.xml</path>
|
||||
<guid>d3816fe0-48e1-4cf5-a8e4-48c72595edb4</guid>
|
||||
</files>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Amputation_UpperArm_L.xml</path>
|
||||
<guid>646cafa5-3fa1-41af-9ca0-aa57cca3b36d</guid>
|
||||
</files>
|
||||
|
||||
<!--Prosthetics -->
|
||||
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Prost_HookArm_L.xml</path>
|
||||
<guid>05338f5e-e984-49c2-be79-81af9ae8e818</guid>
|
||||
</files>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Prost_HookArm_R.xml</path>
|
||||
<guid>8ee7e1bc-2c21-428e-a15d-760d98df973d</guid>
|
||||
</files>
|
||||
|
||||
<files>
|
||||
<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>
|
||||
</files>
|
||||
<files>
|
||||
<path>media/clothing/clothingItems/Surg_Arm_Tourniquet_R.xml</path>
|
||||
<guid>9a5fe063-63c7-4e6f-81ca-ee77c6678e0d</guid>
|
||||
</files>
|
||||
|
||||
|
||||
</fileGuidTable>
|
||||
@@ -1,10 +0,0 @@
|
||||
local LimitActionsController = require("TOC/Controllers/LimitActionsController") -- declared in common
|
||||
local OverridenMethodsArchive = require("TOC/OverridenMethodsArchive")
|
||||
|
||||
local og_ISClothingExtraAction_isValid = OverridenMethodsArchive.Get("ISClothingExtraAction_isValid")
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISClothingExtraAction:isValid()
|
||||
-- TOC_DEBUG.print("Inside ISClothingExtraAction:isValid 42")
|
||||
-- TOC_DEBUG.print(OverridenMethodsArchive.Get("ISClothingExtraAction_isValid"))
|
||||
return LimitActionsController.WrapClothingAction(self, og_ISClothingExtraAction_isValid, instanceItem(self.extra))
|
||||
end
|
||||
@@ -1,40 +0,0 @@
|
||||
local ProsthesisHandler = require("TOC/Handlers/ProsthesisHandler") -- declared in common
|
||||
local OverridenMethodsArchive = require("TOC/OverridenMethodsArchive")
|
||||
|
||||
|
||||
|
||||
local og_ISClothingExtraAction_isValid = OverridenMethodsArchive.Get("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 = instanceItem(self.extra)
|
||||
return ProsthesisHandler.Validate(testItem, isEquippable)
|
||||
end
|
||||
|
||||
|
||||
local og_ISClothingExtraAction_perform = OverridenMethodsArchive.Get("ISClothingExtraAction_perform")
|
||||
function ISClothingExtraAction:perform()
|
||||
local extraItem = instanceItem(self.extra)
|
||||
ProsthesisHandler.SearchAndSetupProsthesis(extraItem, true)
|
||||
og_ISClothingExtraAction_perform(self)
|
||||
end
|
||||
|
||||
|
||||
local og_ISUnequipAction_complete = ISUnequipAction.complete
|
||||
function ISUnequipAction:complete()
|
||||
-- Horrendous workaround. For B42, as of now, it will basically happen two times, once with :perform and once with :complete. Shouldn't
|
||||
-- matter for performance but it's really ugly.
|
||||
-- local isProst = ProsthesisHandler.SearchAndSetupProsthesis(self.item, false)
|
||||
-- local group
|
||||
-- if isProst then
|
||||
-- group = BodyLocations.getGroup("Human")
|
||||
-- group:setMultiItem("TOC_ArmProst", false)
|
||||
-- end
|
||||
og_ISUnequipAction_complete(self)
|
||||
|
||||
-- if isProst then
|
||||
-- group:setMultiItem("TOC_ArmProst", true)
|
||||
-- end
|
||||
|
||||
end
|
||||
50
42/media/lua/client/TOC/API.lua
Normal file
50
42/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
42/media/lua/client/TOC/Admin.lua
Normal file
114
42/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 not(isClient() and isAdmin() or isDebugEnabled()) 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
|
||||
|
||||
|
||||
-- ugly This whole section should be done better
|
||||
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
|
||||
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})
|
||||
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
42/media/lua/client/TOC/ClientRelayCommands.lua
Normal file
77
42/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
42/media/lua/client/TOC/CommonMethods.lua
Normal file
48
42/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
|
||||
79
42/media/lua/client/TOC/Compat.lua
Normal file
79
42/media/lua/client/TOC/Compat.lua
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
---@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}
|
||||
|
||||
|
||||
|
||||
-- TODO Check if FirstAidOverhaul can be made compatible
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
480
42/media/lua/client/TOC/Controllers/DataController.lua
Normal file
480
42/media/lua/client/TOC/Controllers/DataController.lua
Normal file
@@ -0,0 +1,480 @@
|
||||
if isServer() then return end
|
||||
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
----------------
|
||||
|
||||
--- An instance will be abbreviated with dcInst
|
||||
-- https://github.com/ZioPao/The-Only-Cure/issues/187
|
||||
|
||||
--- 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
|
||||
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()
|
||||
|
||||
triggerEvent("OnSetupTocData")
|
||||
end
|
||||
|
||||
---In case of desync between the table on ModData and the table here
|
||||
---@param tocData tocModDataType
|
||||
function DataController:applyOnlineData(tocData)
|
||||
if not tocData or not tocData.limbs then
|
||||
TOC_DEBUG.print("Received invalid tocData")
|
||||
return
|
||||
end
|
||||
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 or not self.tocData or not self.tocData.limbs then return false end
|
||||
return self.tocData.limbs[limbName] and self.tocData.limbs[limbName].isCut or false
|
||||
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]
|
||||
for k, v in pairs(ampStatus) do
|
||||
if v ~= nil then
|
||||
limbData[k] = v
|
||||
end
|
||||
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
|
||||
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
|
||||
181
42/media/lua/client/TOC/Controllers/ItemsController.lua
Normal file
181
42/media/lua/client/TOC/Controllers/ItemsController.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
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)
|
||||
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)
|
||||
-- TODO Fix visual bug
|
||||
-- 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]
|
||||
|
||||
-- TODO Won't work with dedicated clothingItems for multi amps
|
||||
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
|
||||
415
42/media/lua/client/TOC/Controllers/LimitActionsController.lua
Normal file
415
42/media/lua/client/TOC/Controllers/LimitActionsController.lua
Normal file
@@ -0,0 +1,415 @@
|
||||
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")
|
||||
|
||||
local OverridenMethodsArchive = require("TOC/OverridenMethodsArchive")
|
||||
-----------------
|
||||
---@class LimitActionsController
|
||||
local LimitActionsController = {}
|
||||
|
||||
|
||||
--* DISABLE WEARING CERTAIN ITEMS WHEN NO LIMB
|
||||
|
||||
function LimitActionsController.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
|
||||
function LimitActionsController.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 LimitActionsController.CheckLimbFeasibility(limbToCheck) then return isEquippable else return false end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- We need to override when the player changes key binds manually to be sure that TOC changes are re-applied
|
||||
local og_MainOptions_apply = MainOptions.apply
|
||||
function MainOptions:apply(closeAfter)
|
||||
og_MainOptions_apply(self, closeAfter)
|
||||
CachedDataHandler.OverrideBothHandsFeasibility()
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------
|
||||
--* 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)
|
||||
--TOC_DEBUG.print("Running override for adjustMaxTime")
|
||||
-- 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.current.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() or self.noExp then return end
|
||||
|
||||
|
||||
--* LEVELING
|
||||
-- First check level of perks. if already at max, skip
|
||||
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(LocalPlayerController.username)
|
||||
local xp = self.maxTime / 100
|
||||
-- TODO Exp should be added while doing the action, not after it's done
|
||||
|
||||
-- Prevent xp from being negative and decreasing perks
|
||||
if xp < 0 then xp = 0 end
|
||||
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)
|
||||
|
||||
local ampPerk = Perks["Side_" .. side]
|
||||
local ampPerkLevel = LocalPlayerController.playerObj:getPerkLevel(ampPerk)
|
||||
|
||||
if ampPerkLevel < 10 then
|
||||
--TOC_DEBUG.print("Levelling")
|
||||
LocalPlayerController.playerObj:getXp():AddXP(ampPerk, xp)
|
||||
end
|
||||
|
||||
|
||||
-- Level up prosthesis perk
|
||||
if dcInst:getIsProstEquipped(limbName) then
|
||||
local prostPerk = Perks["ProstFamiliarity"]
|
||||
local prostPerkLevel = LocalPlayerController.playerObj:getPerkLevel(prostPerk)
|
||||
if prostPerkLevel < 10 then
|
||||
LocalPlayerController.playerObj:getXp():AddXP(prostPerk, xp)
|
||||
end
|
||||
end
|
||||
|
||||
-- Bleeding when not cicatrized
|
||||
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
|
||||
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
|
||||
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
local og_ISWearClothing_isValid = ISWearClothing.isValid
|
||||
function ISWearClothing:isValid()
|
||||
return LimitActionsController.WrapClothingAction(self, og_ISWearClothing_isValid, self.item)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local og_ISClothingExtraAction_isValid = OverridenMethodsArchive.Save("ISClothingExtraAction_isValid", ISClothingExtraAction.isValid)
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISClothingExtraAction:isValid()
|
||||
return LimitActionsController.WrapClothingAction(self, og_ISClothingExtraAction_isValid, instanceItem(self.extra))
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--* Book exception for exp
|
||||
|
||||
local og_ISReadABook_perform = ISReadABook.perform
|
||||
function ISReadABook:perform()
|
||||
self.noExp = true
|
||||
og_ISReadABook_perform(self)
|
||||
|
||||
end
|
||||
|
||||
return LimitActionsController
|
||||
393
42/media/lua/client/TOC/Controllers/LocalPlayerController.lua
Normal file
393
42/media/lua/client/TOC/Controllers/LocalPlayerController.lua
Normal file
@@ -0,0 +1,393 @@
|
||||
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")
|
||||
local TOC = require("TOC/Registries")
|
||||
-----------
|
||||
|
||||
|
||||
|
||||
|
||||
-- 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(TOC.traits[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:SetInfected(false)
|
||||
|
||||
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, limbName, dcInst)
|
||||
-- FIX Different in B42.13, to be set with stats?
|
||||
if bodyDamage:isInfected() == false then return end
|
||||
|
||||
bodyDamage:setInfected(false)
|
||||
bodyDamage:setInfectionMortalityDuration(-1)
|
||||
bodyDamage:setInfectionTime(-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, 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
|
||||
115
42/media/lua/client/TOC/Controllers/TourniquetController.lua
Normal file
115
42/media/lua/client/TOC/Controllers/TourniquetController.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
|
||||
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
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISClothingExtraAction:perform()
|
||||
TourniquetController.WrapClothingAction(self, og_ISClothingExtraAction_perform)
|
||||
end
|
||||
|
||||
local og_ISWearClothing_isValid = ISWearClothing.isValid
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISWearClothing:isValid()
|
||||
return TourniquetController.WrapClothingAction(self, og_ISWearClothing_isValid)
|
||||
end
|
||||
|
||||
local og_ISUnequipAction_perform = ISUnequipAction.perform
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISUnequipAction:perform()
|
||||
return TourniquetController.WrapClothingAction(self, og_ISUnequipAction_perform)
|
||||
end
|
||||
|
||||
|
||||
return TourniquetController
|
||||
5
42/media/lua/client/TOC/Events.lua
Normal file
5
42/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
|
||||
213
42/media/lua/client/TOC/Handlers/AmputationHandler.lua
Normal file
213
42/media/lua/client/TOC/Handlers/AmputationHandler.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
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:set(CharacterStat.ENDURANCE, surgeonFactor)
|
||||
patientStats:set(CharacterStat.STRESS, 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)
|
||||
|
||||
-- TODO Test this again for 42.13
|
||||
-- If the part was actually infected, heal the player, if they were in time (infectionLevel < 20)
|
||||
local infectionLevel = self.patientPl:getStats():get(CharacterStat.ZOMBIE_INFECTION)
|
||||
if infectionLevel < 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
|
||||
177
42/media/lua/client/TOC/Handlers/CachedDataHandler.lua
Normal file
177
42/media/lua/client/TOC/Handlers/CachedDataHandler.lua
Normal file
@@ -0,0 +1,177 @@
|
||||
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.OverrideBothHandsFeasibility()
|
||||
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.OverrideBothHandsFeasibility()
|
||||
end
|
||||
|
||||
return CachedDataHandler.handFeasibility[side]
|
||||
end
|
||||
|
||||
function CachedDataHandler.OverrideBothHandsFeasibility()
|
||||
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))
|
||||
|
||||
if StaticData.COMPAT_42 then
|
||||
getCore():addKeyBinding(interactStr, Keyboard.KEY_NONE, 0, false, false, false)
|
||||
else
|
||||
getCore():addKeyBinding(interactStr, Keyboard.KEY_NONE)
|
||||
|
||||
end
|
||||
else
|
||||
--TOC_DEBUG.print("Re-enabling interact key")
|
||||
--TOC_DEBUG.print("Cached current key for interact: " .. tostring(CachedDataHandler.interactKey))
|
||||
|
||||
if StaticData.COMPAT_42 then
|
||||
getCore():addKeyBinding(interactStr, CachedDataHandler.interactKey, 0, false, false, false)
|
||||
else
|
||||
getCore():addKeyBinding(interactStr, CachedDataHandler.interactKey)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CachedDataHandler.GetBothHandsFeasibility()
|
||||
return CachedDataHandler.handFeasibility["L"] or CachedDataHandler.handFeasibility["R"]
|
||||
end
|
||||
|
||||
return CachedDataHandler
|
||||
|
||||
189
42/media/lua/client/TOC/Handlers/ProsthesisHandler.lua
Normal file
189
42/media/lua/client/TOC/Handlers/ProsthesisHandler.lua
Normal file
@@ -0,0 +1,189 @@
|
||||
local CommonMethods = require("TOC/CommonMethods")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local DataController = require("TOC/Controllers/DataController")
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
|
||||
local OverridenMethodsArchive = require("TOC/OverridenMethodsArchive")
|
||||
-------------------------
|
||||
|
||||
---@class ProsthesisHandler
|
||||
local ProsthesisHandler = {}
|
||||
|
||||
local bodylocArmProstBaseline = "toc:toc_armprost"
|
||||
--local bodyLocLegProst = "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
|
||||
if item == nil then
|
||||
TOC_DEBUG.print("Not prost")
|
||||
|
||||
return false
|
||||
end
|
||||
return item:getBodyLocation():toString():contains(bodylocArmProstBaseline)
|
||||
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:toString():contains(bodylocArmProstBaseline) then
|
||||
position = "Top_"
|
||||
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.OverrideBothHandsFeasibility()
|
||||
return true
|
||||
end
|
||||
|
||||
function ProsthesisHandler.Validate(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
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
--* Overrides *--
|
||||
|
||||
|
||||
local og_ISWearClothing_isValid = ISWearClothing.isValid
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISWearClothing:isValid()
|
||||
local isEquippable = og_ISWearClothing_isValid(self)
|
||||
return ProsthesisHandler.Validate(self.item, isEquippable)
|
||||
end
|
||||
|
||||
local og_ISWearClothing_perform = ISWearClothing.perform
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISWearClothing:perform()
|
||||
ProsthesisHandler.SearchAndSetupProsthesis(self.item, true)
|
||||
og_ISWearClothing_perform(self)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local og_ISClothingExtraAction_isValid = OverridenMethodsArchive.Save("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
|
||||
|
||||
-- B42 Compatibility to add
|
||||
local testItem = InventoryItemFactory.CreateItem(self.extra)
|
||||
return ProsthesisHandler.Validate(testItem, isEquippable)
|
||||
end
|
||||
|
||||
local og_ISClothingExtraAction_perform = OverridenMethodsArchive.Save("ISClothingExtraAction_perform", ISClothingExtraAction.perform)
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function ISClothingExtraAction:perform()
|
||||
|
||||
|
||||
-- B42 Compatibility to add
|
||||
|
||||
local extraItem = InventoryItemFactory.CreateItem(self.extra)
|
||||
ProsthesisHandler.SearchAndSetupProsthesis(extraItem, true)
|
||||
og_ISClothingExtraAction_perform(self)
|
||||
end
|
||||
|
||||
local og_ISUnequipAction_perform = ISUnequipAction.perform
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
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
42/media/lua/client/TOC/Main.lua
Normal file
71
42/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.3"
|
||||
}
|
||||
|
||||
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)
|
||||
206
42/media/lua/client/TOC/Tests.lua
Normal file
206
42/media/lua/client/TOC/Tests.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
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
42/media/lua/client/TOC/TimedActions/CauterizeAction.lua
Normal file
89
42/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
|
||||
126
42/media/lua/client/TOC/TimedActions/CleanWoundAction.lua
Normal file
126
42/media/lua/client/TOC/TimedActions/CleanWoundAction.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
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
|
||||
---@field doctorLevel number
|
||||
---@field bandagedPlayerX number
|
||||
---@field bandagedPlayerY number
|
||||
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 -- B42 Deprecated
|
||||
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
42/media/lua/client/TOC/TimedActions/CutLimbAction.lua
Normal file
138
42/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
42/media/lua/client/TOC/TimedActions/IgnoredActions.lua
Normal file
139
42/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 OverrideAction(action, maxTime)
|
||||
-- TODO Add forced debuff instead of just relying on the vanilla values?
|
||||
action.skipTOC = true
|
||||
action.maxTime = maxTime
|
||||
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)
|
||||
OverrideAction(action, 30) -- Default time for this action
|
||||
return action
|
||||
end
|
||||
|
||||
local og_ISDetachItemHotbar_new = ISDetachItemHotbar.new
|
||||
function ISDetachItemHotbar:new(character, item)
|
||||
local action = og_ISDetachItemHotbar_new(self, character, item)
|
||||
OverrideAction(action, 25) -- Default time for this action
|
||||
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()
|
||||
|
||||
-- Brutal Handwork should be considered. Use the twohands thing
|
||||
if not (dcInst:getIsAnyLimbCut() and twoHands) then
|
||||
OverrideAction(action, time)
|
||||
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
|
||||
|
||||
-- TODO Consider other cases where unequipping something should skip TOC.
|
||||
if instanceof(item, 'HandWeapon') then
|
||||
OverrideAction(action, time)
|
||||
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
|
||||
|
||||
|
||||
if StaticData.COMPAT_42 == false then
|
||||
-- TODO confirm that this doesn't exist anymore in B42
|
||||
-- B42 nenen
|
||||
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
|
||||
|
||||
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
|
||||
@@ -0,0 +1,80 @@
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
|
||||
-- Since amputations are actually clothing items, we need to override ISWashYourself to account for that
|
||||
|
||||
-- TODO Clean this up
|
||||
|
||||
local og_ISWashYourself_perform = ISWashYourself.perform
|
||||
function ISWashYourself:perform()
|
||||
|
||||
TOC_DEBUG.print("ISWashYourself override")
|
||||
|
||||
---@type IsoPlayer
|
||||
local pl = self.character
|
||||
local plInv = pl:getInventory()
|
||||
-- Search for amputations and clean them here
|
||||
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(pl:getUsername())
|
||||
for limbName, _ in pairs(amputatedLimbs) do
|
||||
|
||||
TOC_DEBUG.print("Checking if " .. limbName .. " is in inventory and washing it")
|
||||
|
||||
-- get clothing item
|
||||
local foundItem = plInv:FindAndReturn(StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName)
|
||||
if foundItem and instanceof(foundItem, "Clothing") then
|
||||
|
||||
TOC_DEBUG.print("Washing " .. limbName)
|
||||
|
||||
---@cast foundItem Clothing
|
||||
foundItem:setWetness(100)
|
||||
foundItem:setBloodLevel(0)
|
||||
foundItem:setDirtyness(0) -- TODO Integrate with other dirtyness
|
||||
|
||||
local coveredParts = BloodClothingType.getCoveredParts(foundItem:getBloodClothingType())
|
||||
for j=0, coveredParts:size() - 1 do
|
||||
foundItem:setBlood(coveredParts:get(j), 0)
|
||||
foundItem:setDirt(coveredParts:get(j), 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
og_ISWashYourself_perform(self)
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
local og_ISWashYourself_GetRequiredWater = ISWashYourself.GetRequiredWater
|
||||
|
||||
|
||||
---@param character IsoPlayer
|
||||
---@return integer
|
||||
function ISWashYourself.GetRequiredWater(character)
|
||||
|
||||
local units = og_ISWashYourself_GetRequiredWater(character)
|
||||
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(character:getUsername())
|
||||
local plInv = character:getInventory()
|
||||
for limbName, _ in pairs(amputatedLimbs) do
|
||||
|
||||
TOC_DEBUG.print("Checking if " .. limbName .. " is in inventory and washing it")
|
||||
|
||||
-- get clothing item
|
||||
local item = plInv:FindAndReturn(StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limbName)
|
||||
if item and instanceof(item, "Clothing") then
|
||||
local coveredParts = BloodClothingType.getCoveredParts(item:getBloodClothingType())
|
||||
if coveredParts then
|
||||
for i=1,coveredParts:size() do
|
||||
local part = coveredParts:get(i-1)
|
||||
if item:getBlood(part) > 0 then
|
||||
units = units + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return units
|
||||
end
|
||||
116
42/media/lua/client/TOC/UI/ConfirmationPanel.lua
Normal file
116
42/media/lua/client/TOC/UI/ConfirmationPanel.lua
Normal file
@@ -0,0 +1,116 @@
|
||||
---@class ConfirmationPanel : ISPanel
|
||||
local ConfirmationPanel = ISPanel:derive("ConfirmationPanel")
|
||||
|
||||
---Starts a new confirmation panel
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param width number
|
||||
---@param height number
|
||||
---@param alertText string
|
||||
---@param onConfirmFunc function
|
||||
---@return ConfirmationPanel
|
||||
function ConfirmationPanel:new(x, y, width, height, alertText, parentPanel, onConfirmFunc)
|
||||
local o = ISPanel:new(x, y, width, height)
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
|
||||
o:initialise()
|
||||
o.alertText = alertText
|
||||
o.onConfirmFunc = onConfirmFunc
|
||||
o.parentPanel = parentPanel
|
||||
ConfirmationPanel.instance = o
|
||||
|
||||
---@cast o ConfirmationPanel
|
||||
return o
|
||||
end
|
||||
|
||||
function ConfirmationPanel:createChildren()
|
||||
ISPanel.createChildren(self)
|
||||
self.borderColor = { r = 1, g = 0, b = 0, a = 1 }
|
||||
|
||||
self.textPanel = ISRichTextPanel:new(0, 0, self.width, self.height)
|
||||
self.textPanel:initialise()
|
||||
self:addChild(self.textPanel)
|
||||
self.textPanel.defaultFont = UIFont.Medium
|
||||
self.textPanel.anchorTop = true
|
||||
self.textPanel.anchorLeft = false
|
||||
self.textPanel.anchorBottom = true
|
||||
self.textPanel.anchorRight = false
|
||||
self.textPanel.marginLeft = 0
|
||||
self.textPanel.marginTop = 10
|
||||
self.textPanel.marginRight = 0
|
||||
self.textPanel.marginBottom = 0
|
||||
self.textPanel.autosetheight = false
|
||||
self.textPanel.background = false
|
||||
self.textPanel:setText(self.alertText)
|
||||
self.textPanel:paginate()
|
||||
|
||||
local yPadding = 10
|
||||
local xPadding = self:getWidth() / 4
|
||||
local btnWidth = 100
|
||||
local btnHeight = 25
|
||||
|
||||
|
||||
local yButton = self:getHeight() - yPadding - btnHeight
|
||||
|
||||
self.btnYes = ISButton:new(xPadding, yButton, btnWidth, btnHeight, getText("IGUI_Yes"), self, self.onClick)
|
||||
self.btnYes.internal = "YES"
|
||||
self.btnYes:initialise()
|
||||
self.btnYes.borderColor = { r = 1, g = 0, b = 0, a = 1 }
|
||||
self.btnYes:setEnable(true)
|
||||
self:addChild(self.btnYes)
|
||||
|
||||
self.btnNo = ISButton:new(self:getWidth() - xPadding - btnWidth, yButton, btnWidth, btnHeight, getText("IGUI_No"), self,
|
||||
self.onClick)
|
||||
self.btnNo.internal = "NO"
|
||||
self.btnNo:initialise()
|
||||
self.btnNo:setEnable(true)
|
||||
self:addChild(self.btnNo)
|
||||
end
|
||||
|
||||
function ConfirmationPanel:onClick(btn)
|
||||
if btn.internal == 'YES' then
|
||||
self.onConfirmFunc(self.parentPanel)
|
||||
self:close()
|
||||
elseif btn.internal == 'NO' then
|
||||
self:close()
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------
|
||||
|
||||
---@param alertText string
|
||||
---@param x any
|
||||
---@param y any
|
||||
---@param parentPanel any
|
||||
---@param onConfirmFunc any
|
||||
---@return ConfirmationPanel
|
||||
function ConfirmationPanel.Open(alertText, x, y, parentPanel, onConfirmFunc)
|
||||
local width = 500
|
||||
local height = 120
|
||||
|
||||
|
||||
local screenWidth = getCore():getScreenWidth()
|
||||
local screenHeight = getCore():getScreenHeight()
|
||||
|
||||
-- Check for oversize
|
||||
if x+width > screenWidth then
|
||||
x = screenWidth - width
|
||||
end
|
||||
|
||||
if y+height > screenHeight then
|
||||
y = screenHeight - height
|
||||
end
|
||||
|
||||
local panel = ConfirmationPanel:new(x, y, width, height, alertText, parentPanel, onConfirmFunc)
|
||||
panel:initialise()
|
||||
panel:addToUIManager()
|
||||
panel:bringToTop()
|
||||
return panel
|
||||
end
|
||||
|
||||
function ConfirmationPanel.Close()
|
||||
ConfirmationPanel.instance:close()
|
||||
end
|
||||
|
||||
return ConfirmationPanel
|
||||
273
42/media/lua/client/TOC/UI/HealthPanel.lua
Normal file
273
42/media/lua/client/TOC/UI/HealthPanel.lua
Normal file
@@ -0,0 +1,273 @@
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local DataController = require("TOC/Controllers/DataController")
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
local Compat = require("TOC/Compat")
|
||||
|
||||
local CutLimbInteractionHandler = require("TOC/UI/Interactions/CutLimbInteractionHandler")
|
||||
local WoundCleaningInteractionHandler = require("TOC/UI/Interactions/WoundCleaningInteractionHandler")
|
||||
------------------------
|
||||
|
||||
|
||||
local isReady = false
|
||||
|
||||
|
||||
local xMod, yMod
|
||||
|
||||
if StaticData.COMPAT_42 then
|
||||
-- B42 For some reason (I didn't investigate), when applying stuff to the health panel there is an un-accounted shift in B42.
|
||||
xMod = 5
|
||||
yMod = 13
|
||||
else
|
||||
xMod = 0
|
||||
yMod = 0
|
||||
end
|
||||
|
||||
|
||||
function SetHealthPanelTOC()
|
||||
|
||||
-- depending on compatibility
|
||||
isReady = true
|
||||
end
|
||||
|
||||
|
||||
-- We're overriding ISHealthPanel to add custom textures to the body panel.
|
||||
-- By doing so we can show the player which limbs have been cut without having to use another menu
|
||||
-- We can show prosthesis too this way
|
||||
-- We also manage the drag'n drop of items on the body to let the players use the saw this way too
|
||||
---@diagnostic disable: duplicate-set-field
|
||||
|
||||
--ISHealthBodyPartPanel = ISBodyPartPanel:derive("ISHealthBodyPartPanel")
|
||||
|
||||
--* Handling drag n drop of the saw *--
|
||||
|
||||
local og_ISHealthPanel_dropItemsOnBodyPart = ISHealthPanel.dropItemsOnBodyPart
|
||||
function ISHealthPanel:dropItemsOnBodyPart(bodyPart, items)
|
||||
og_ISHealthPanel_dropItemsOnBodyPart(self, bodyPart, items)
|
||||
|
||||
TOC_DEBUG.print("override to dropItemsOnBodyPart running")
|
||||
local cutLimbInteraction = CutLimbInteractionHandler:new(self, bodyPart)
|
||||
local woundCleaningInteraction = WoundCleaningInteractionHandler:new(self, bodyPart, self.character:getUsername())
|
||||
|
||||
for _,item in ipairs(items) do
|
||||
cutLimbInteraction:checkItem(item)
|
||||
woundCleaningInteraction:checkItem(item)
|
||||
end
|
||||
if cutLimbInteraction:dropItems(items) or woundCleaningInteraction:dropItems(items) then
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local og_ISHealthPanel_doBodyPartContextMenu = ISHealthPanel.doBodyPartContextMenu
|
||||
function ISHealthPanel:doBodyPartContextMenu(bodyPart, x, y)
|
||||
og_ISHealthPanel_doBodyPartContextMenu(self, bodyPart, x, y)
|
||||
local playerNum = self.otherPlayer and self.otherPlayer:getPlayerNum() or self.character:getPlayerNum()
|
||||
|
||||
-- To not recreate it but reuse the one that has been created in the original method
|
||||
|
||||
-- TODO This will work ONLY when an addOption has been already done in the og method.
|
||||
local context = getPlayerContextMenu(playerNum)
|
||||
context:bringToTop()
|
||||
context:setVisible(true)
|
||||
|
||||
|
||||
local cutLimbInteraction = CutLimbInteractionHandler:new(self, bodyPart)
|
||||
self:checkItems({cutLimbInteraction})
|
||||
cutLimbInteraction:addToMenu(context)
|
||||
|
||||
local woundCleaningInteraction = WoundCleaningInteractionHandler:new(self, bodyPart, self.character:getUsername())
|
||||
self:checkItems({woundCleaningInteraction})
|
||||
woundCleaningInteraction:addToMenu(context)
|
||||
end
|
||||
|
||||
|
||||
--* Modifications and additional methods to handle visible amputation on the health menu *--
|
||||
|
||||
---Get a value between 1 and 0.1 for the cicatrization time
|
||||
---@param cicTime integer
|
||||
---@return integer
|
||||
local function GetColorFromCicatrizationTime(cicTime, limbName)
|
||||
local defaultTime = StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[limbName]
|
||||
local delta = cicTime/defaultTime
|
||||
return math.max(0.15, math.min(delta, 1))
|
||||
end
|
||||
|
||||
---Try to draw the highest amputation in the health panel, based on the cicatrization time
|
||||
---@param side string L or R
|
||||
---@param username string
|
||||
function ISHealthPanel:tryDrawAmputation(highestAmputations, side, username)
|
||||
local redColor
|
||||
local texture
|
||||
|
||||
if TOC_DEBUG.enableHealthPanelDebug then
|
||||
redColor = 1
|
||||
texture = getTexture("media/ui/test_pattern.png")
|
||||
else
|
||||
if highestAmputations[side] == nil then return end
|
||||
local limbName = highestAmputations[side]
|
||||
--TOC_DEBUG.print("Drawing " .. tostring(limbName) .. " for " .. username)
|
||||
|
||||
local cicTime = DataController.GetInstance(username):getCicatrizationTime(limbName)
|
||||
redColor = GetColorFromCicatrizationTime(cicTime, limbName)
|
||||
|
||||
local sexPl = self.character:isFemale() and "Female" or "Male"
|
||||
texture = StaticData.HEALTH_PANEL_TEXTURES[sexPl][limbName]
|
||||
end
|
||||
-- B42, for some reason the positioning of the texture changed. Realigned it manually with those fixed values
|
||||
self:drawTexture(texture, self.healthPanel.x - xMod, self.healthPanel.y - yMod, 1, redColor, 0, 0)
|
||||
end
|
||||
function ISHealthPanel:tryDrawProsthesis(highestAmputations, side, username)
|
||||
local dc = DataController.GetInstance(username) -- TODO CACHE PROSTHESIS!!! Don't use DC here
|
||||
local limbName = highestAmputations[side]
|
||||
if limbName and dc:getIsProstEquipped(limbName) then
|
||||
self:drawTexture(StaticData.HEALTH_PANEL_TEXTURES.ProstArm[side], self.healthPanel.x - xMod, self.healthPanel.y - yMod, 1, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
local og_ISHealthPanel_render = ISHealthPanel.render
|
||||
function ISHealthPanel:render()
|
||||
og_ISHealthPanel_render(self)
|
||||
local username = self.character:getUsername()
|
||||
local highestAmputations = CachedDataHandler.GetHighestAmputatedLimbs(username)
|
||||
|
||||
if highestAmputations ~= nil then
|
||||
|
||||
-- Left Texture
|
||||
self:tryDrawAmputation(highestAmputations, "L", username)
|
||||
self:tryDrawProsthesis(highestAmputations, "L", username)
|
||||
|
||||
-- Right Texture
|
||||
self:tryDrawAmputation(highestAmputations, "R", username)
|
||||
self:tryDrawProsthesis(highestAmputations, "R", username)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- We need to override this to force the alpha to 1
|
||||
local og_ISCharacterInfoWindow_render = ISCharacterInfoWindow.prerender
|
||||
function ISCharacterInfoWindow:prerender()
|
||||
og_ISCharacterInfoWindow_render(self)
|
||||
self.backgroundColor.a = 1
|
||||
end
|
||||
|
||||
-- We need to override this to force the alpha to 1 for the Medical Check in particular
|
||||
local og_ISHealthPanel_prerender = ISHealthPanel.prerender
|
||||
function ISHealthPanel:prerender()
|
||||
og_ISHealthPanel_prerender(self)
|
||||
self.backgroundColor.a = 1
|
||||
end
|
||||
|
||||
--- The medical check wrap the health panel into this. We need to override its color
|
||||
local overrideBackgroundColor = true
|
||||
local og_ISUIElement_wrapInCollapsableWindow = ISUIElement.wrapInCollapsableWindow
|
||||
---@param title string
|
||||
---@param resizable any
|
||||
---@param subClass any
|
||||
---@return any
|
||||
function ISUIElement:wrapInCollapsableWindow(title, resizable, subClass)
|
||||
local panel = og_ISUIElement_wrapInCollapsableWindow(self, title, resizable, subClass)
|
||||
|
||||
if overrideBackgroundColor then
|
||||
TOC_DEBUG.print("Overriding color for panel - " .. title)
|
||||
self.backgroundColor.a = 1
|
||||
panel.backgroundColor.a = 1
|
||||
end
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
-- This is run when a player is trying the Medical Check action on another player
|
||||
local og_ISMedicalCheckAction_perform = ISMedicalCheckAction.perform
|
||||
function ISMedicalCheckAction:perform()
|
||||
local username = self.otherPlayer:getUsername()
|
||||
TOC_DEBUG.print("Medical Action on " .. username )
|
||||
|
||||
-- We need to recalculate them here before we can create the highest amputations point
|
||||
CachedDataHandler.CalculateAmputatedLimbs(username)
|
||||
og_ISMedicalCheckAction_perform(self)
|
||||
end
|
||||
|
||||
local og_ISHealthBodyPartListBox_doDrawItem = ISHealthBodyPartListBox.doDrawItem
|
||||
function ISHealthBodyPartListBox:doDrawItem(y, item, alt)
|
||||
y = og_ISHealthBodyPartListBox_doDrawItem(self, y, item, alt)
|
||||
y = y - 5
|
||||
local x = 15
|
||||
local fontHgt = getTextManager():getFontHeight(UIFont.Small)
|
||||
|
||||
local username = self.parent.character:getUsername()
|
||||
--local amputatedLimbs = CachedDataHandler.GetIndexedAmputatedLimbs(username)
|
||||
|
||||
---@type BodyPart
|
||||
local bodyPart = item.item.bodyPart
|
||||
|
||||
local bodyPartTypeStr = BodyPartType.ToString(bodyPart:getType())
|
||||
local limbName = StaticData.LIMBS_IND_STR[bodyPartTypeStr]
|
||||
|
||||
|
||||
-- We should cache a lot of other stuff to have this working with CacheDataHandler :(
|
||||
if limbName then
|
||||
local dcInst = DataController.GetInstance(username)
|
||||
if dcInst:getIsCut(limbName) and dcInst:getIsVisible(limbName) then
|
||||
if dcInst:getIsCicatrized(limbName) then
|
||||
if dcInst:getIsCauterized(limbName) then
|
||||
self:drawText("- " .. getText("IGUI_HealthPanel_Cauterized"), x, y, 0.58, 0.75, 0.28, 1, UIFont.Small)
|
||||
else
|
||||
self:drawText("- " .. getText("IGUI_HealthPanel_Cicatrized"), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small)
|
||||
end
|
||||
|
||||
y = y + fontHgt
|
||||
else
|
||||
local cicaTime = dcInst:getCicatrizationTime(limbName)
|
||||
|
||||
-- Show it in percentage
|
||||
local maxCicaTime = StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[limbName]
|
||||
local percentage = (1 - cicaTime/maxCicaTime) * 100
|
||||
self:drawText("- " .. getText("IGUI_HealthPanel_Cicatrization") .. string.format(" %.2f", percentage) .. "%", x, y, 0.89, 0.28, 0.28, 1, UIFont.Small)
|
||||
y = y + fontHgt
|
||||
|
||||
local scaledDirtyness = math.floor(dcInst:getWoundDirtyness(limbName) * 100)
|
||||
self:drawText("- " .. getText("IGUI_HealthPanel_WoundDirtyness") .. string.format(" %d", scaledDirtyness) .. "%", x, y, 0.89, 0.28, 0.28, 1, UIFont.Small)
|
||||
y = y + fontHgt
|
||||
|
||||
end
|
||||
|
||||
if dcInst:getIsProstEquipped(limbName) then
|
||||
self:drawText("- " .. getText("IGUI_HealthPanel_ProstEquipped"), x, y, 0.28, 0.89, 0.28, 1, UIFont.Small)
|
||||
y = y + fontHgt
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
y = y + 5
|
||||
return y
|
||||
end
|
||||
|
||||
local og_ISHealthPanel_getDamagedParts = ISHealthPanel.getDamagedParts
|
||||
function ISHealthPanel:getDamagedParts()
|
||||
-- check for imeds or if TOC is ready to display its stuff on the health panel
|
||||
if isReady == false or Compat.handlers['iMeds'].isActive or Compat.handlers['iMedsFixed'].isActive then
|
||||
return og_ISHealthPanel_getDamagedParts(self)
|
||||
elseif isReady then
|
||||
local result = {}
|
||||
local bodyParts = self:getPatient():getBodyDamage():getBodyParts()
|
||||
if isClient() and not self:getPatient():isLocalPlayer() then
|
||||
bodyParts = self:getPatient():getBodyDamageRemote():getBodyParts()
|
||||
end
|
||||
|
||||
local patientUsername = self:getPatient():getUsername()
|
||||
local mdh = DataController.GetInstance(patientUsername)
|
||||
for i=1,bodyParts:size() do
|
||||
local bodyPart = bodyParts:get(i-1)
|
||||
local bodyPartTypeStr = BodyPartType.ToString(bodyPart:getType())
|
||||
local limbName = StaticData.LIMBS_IND_STR[bodyPartTypeStr]
|
||||
|
||||
if ISHealthPanel.cheat or bodyPart:HasInjury() or bodyPart:bandaged() or bodyPart:stitched() or bodyPart:getSplintFactor() > 0 or bodyPart:getAdditionalPain() > 10 or bodyPart:getStiffness() > 5 or (mdh:getIsCut(limbName) and mdh:getIsVisible(limbName)) then
|
||||
table.insert(result, bodyPart)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,287 @@
|
||||
local BaseHandler = require("TOC/UI/Interactions/HealthPanelBaseHandler")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local DataController = require("TOC/Controllers/DataController")
|
||||
local ConfirmationPanel = require("TOC/UI/ConfirmationPanel")
|
||||
|
||||
local CutLimbAction = require("TOC/TimedActions/CutLimbAction")
|
||||
---------------------
|
||||
|
||||
|
||||
|
||||
|
||||
--* Various functions to help during these pesky checks
|
||||
|
||||
---Check if the item type corresponds to a compatible saw
|
||||
---@param itemType string
|
||||
local function CheckIfSaw(itemType)
|
||||
return itemType == StaticData.SAWS_TYPES_IND_STR.saw
|
||||
or itemType == StaticData.SAWS_TYPES_IND_STR.gardenSaw
|
||||
end
|
||||
|
||||
---Return a compatible bandage
|
||||
---@param player IsoPlayer
|
||||
---@return InventoryItem?
|
||||
local function GetBandageItem(player)
|
||||
local plInv = player:getInventory()
|
||||
local bandageItem = plInv:FindAndReturn("Base.Bandage") or plInv:FindAndReturn("Base.RippedSheets")
|
||||
|
||||
---@cast bandageItem InventoryItem
|
||||
|
||||
return bandageItem
|
||||
end
|
||||
|
||||
---Return a suture needle or thread (only if the player has a needle too)
|
||||
---@param player IsoPlayer
|
||||
---@return InventoryItem?
|
||||
local function GetStitchesConsumableItem(player)
|
||||
local plInv = player:getInventory()
|
||||
|
||||
-- Suture needle has priority
|
||||
|
||||
local sutureNeedle = plInv:FindAndReturn("Base.SutureNeedle")
|
||||
|
||||
if sutureNeedle then
|
||||
return sutureNeedle
|
||||
else
|
||||
-- Didn't find the suture one, so let's search for the normal one + thread
|
||||
|
||||
local needleItem = plInv:FindAndReturn("Base.Needle")
|
||||
|
||||
if needleItem == nil then return nil end
|
||||
|
||||
-- Found the normal one, searching for thread
|
||||
|
||||
local threadItem = plInv:FindAndReturn("Base.Thread")
|
||||
---@cast threadItem DrainableComboItem
|
||||
|
||||
if threadItem and threadItem:getUsedDelta() > 0 then
|
||||
return threadItem
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local textConfirmAmp = getText("IGUI_Confirmation_Amputate")
|
||||
local textAmp = getText("ContextMenu_Amputate")
|
||||
local textAmpBandage = getText("ContextMenu_Amputate_Bandage")
|
||||
local textAmpStitch = getText("ContextMenu_Amputate_Stitch")
|
||||
local textAmpStitchBandage = getText("ContextMenu_Amputate_Stitch_Bandage")
|
||||
|
||||
---Add the action to the queue
|
||||
---@param limbName string
|
||||
---@param surgeon IsoPlayer
|
||||
---@param patient IsoPlayer
|
||||
---@param sawItem InventoryItem
|
||||
---@param stitchesItem InventoryItem?
|
||||
---@param bandageItem InventoryItem?
|
||||
local function PerformAction(surgeon, patient, limbName, sawItem, stitchesItem, bandageItem)
|
||||
|
||||
|
||||
local x = (getCore():getScreenWidth() - 500) / 2
|
||||
local y = getCore():getScreenHeight() / 2
|
||||
|
||||
|
||||
ConfirmationPanel.Open(textConfirmAmp, x, y, nil, function()
|
||||
|
||||
-- get saw in hand
|
||||
-- todo primary or secondary depending on amputation status of surgeon
|
||||
ISTimedActionQueue.add(ISEquipWeaponAction:new(surgeon, sawItem, 50, true, false))
|
||||
|
||||
local lHandItem = surgeon:getSecondaryHandItem()
|
||||
if lHandItem then
|
||||
ISTimedActionQueue.add(ISUnequipAction:new(surgeon, lHandItem, 50))
|
||||
end
|
||||
|
||||
|
||||
ISTimedActionQueue.add(CutLimbAction:new(surgeon, patient, limbName, sawItem, stitchesItem, bandageItem))
|
||||
|
||||
end)
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
---Adds the actions to the inventory context menu
|
||||
---@param player IsoPlayer
|
||||
---@param context ISContextMenu
|
||||
---@param sawItem InventoryItem
|
||||
---@param stitchesItem InventoryItem?
|
||||
---@param bandageItem InventoryItem?
|
||||
local function AddInvAmputationOptions(player, context, sawItem, stitchesItem, bandageItem)
|
||||
local text
|
||||
|
||||
-- Set the correct text option
|
||||
if stitchesItem and bandageItem then
|
||||
--TOC_DEBUG.print("stitches and bandage")
|
||||
text = textAmpStitchBandage
|
||||
elseif not bandageItem and stitchesItem then
|
||||
--TOC_DEBUG.print("only stitches")
|
||||
text = textAmpStitch
|
||||
elseif not stitchesItem and bandageItem then
|
||||
--TOC_DEBUG.print("only bandages")
|
||||
text = textAmpBandage
|
||||
else
|
||||
text = textAmp
|
||||
end
|
||||
|
||||
TOC_DEBUG.print("Current text " .. tostring(text))
|
||||
local option = context:addOption(text, nil)
|
||||
local subMenu = context:getNew(context)
|
||||
context:addSubMenu(option, subMenu)
|
||||
|
||||
|
||||
|
||||
-- TODO Separate into groups
|
||||
|
||||
|
||||
-- Amputate -> Top/Bottom - > Left/Right - > Limb
|
||||
-- for i=1, #StaticData.PROSTHESES_GROUPS_STR do
|
||||
-- local group = StaticData.PROSTHESES_GROUPS_STR[i]
|
||||
|
||||
-- for j=1, #StaticData.SIDES_IND_STR do
|
||||
|
||||
-- end
|
||||
|
||||
-- end
|
||||
|
||||
-- for k,v in pairs(StaticData.LIMBS_TO_PROST_GROUP_MATCH_IND_STR) do
|
||||
-- TOC_DEBUG.print(k)
|
||||
|
||||
-- end
|
||||
|
||||
|
||||
local dc = DataController.GetInstance()
|
||||
for i = 1, #StaticData.LIMBS_STR do
|
||||
local limbName = StaticData.LIMBS_STR[i]
|
||||
if not dc:getIsCut(limbName) then
|
||||
local limbTranslatedName = getText("ContextMenu_Limb_" .. limbName)
|
||||
subMenu:addOption(limbTranslatedName, player, PerformAction, player, limbName, sawItem, stitchesItem, bandageItem)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---Handler for OnFillInventoryObjectContextMenu
|
||||
---@param playerNum number
|
||||
---@param context ISContextMenu
|
||||
---@param items table
|
||||
local function AddInventoryAmputationMenu(playerNum, context, items)
|
||||
local item
|
||||
|
||||
-- We can't access the item if we don't create the loop and start ipairs.
|
||||
for _, v in ipairs(items) do
|
||||
item = v
|
||||
if not instanceof(v, "InventoryItem") then
|
||||
item = v.items[1]
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
local itemType = item:getType()
|
||||
if CheckIfSaw(itemType) then
|
||||
local player = getSpecificPlayer(playerNum)
|
||||
local sawItem = item
|
||||
local stitchesItem = GetStitchesConsumableItem(player)
|
||||
local bandageItem = GetBandageItem(player)
|
||||
|
||||
TOC_DEBUG.print("Stitches item: " .. tostring(stitchesItem))
|
||||
TOC_DEBUG.print("Bandage item: " .. tostring(bandageItem))
|
||||
|
||||
AddInvAmputationOptions(player, context, sawItem, stitchesItem, bandageItem)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Events.OnFillInventoryObjectContextMenu.Add(AddInventoryAmputationMenu)
|
||||
|
||||
-------------------------------------
|
||||
|
||||
---@class CutLimbInteractionHandler : BaseHandler
|
||||
---@field items table
|
||||
---@field limbName string
|
||||
---@field itemType string temporary
|
||||
local CutLimbInteractionHandler = BaseHandler:derive("CutLimbInteractionHandler")
|
||||
|
||||
|
||||
---Creates new CutLimbInteractionHandler
|
||||
---@param panel ISUIElement
|
||||
---@param bodyPart BodyPart
|
||||
---@return CutLimbInteractionHandler
|
||||
function CutLimbInteractionHandler:new(panel, bodyPart)
|
||||
local o = BaseHandler.new(self, panel, bodyPart)
|
||||
o.items.ITEMS = {}
|
||||
o.limbName = BodyPartType.ToString(bodyPart:getType())
|
||||
o.itemType = "Saw"
|
||||
--TOC_DEBUG.print("init CutLimbInteractionHandler")
|
||||
return o
|
||||
end
|
||||
|
||||
---@param item InventoryItem
|
||||
function CutLimbInteractionHandler:checkItem(item)
|
||||
--TOC_DEBUG.print("CutLimbInteractionHandler checkItem")
|
||||
local itemType = item:getType()
|
||||
|
||||
if CheckIfSaw(itemType) then
|
||||
TOC_DEBUG.print("added to list -> " .. itemType)
|
||||
self:addItem(self.items.ITEMS, item)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param type any
|
||||
function CutLimbInteractionHandler:openConfirmation(x, y, type)
|
||||
ConfirmationPanel.Open(textConfirmAmp, x, y, nil, function()
|
||||
self.onMenuOptionSelected(self, type)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
|
||||
---@param context ISContextMenu
|
||||
function CutLimbInteractionHandler:addToMenu(context)
|
||||
--TOC_DEBUG.print("CutLimbInteractionHandler addToMenu")
|
||||
local types = self:getAllItemTypes(self.items.ITEMS)
|
||||
local patientUsername = self:getPatient():getUsername()
|
||||
if #types > 0 and StaticData.LIMBS_TO_BODYLOCS_IND_BPT[self.limbName] and not DataController.GetInstance(patientUsername):getIsCut(self.limbName) then
|
||||
TOC_DEBUG.print("addToMenu, types > 0")
|
||||
|
||||
local x = (getCore():getScreenWidth() - 500) / 2
|
||||
local y = getCore():getScreenHeight() / 2
|
||||
|
||||
for i=1, #types do
|
||||
context:addOption(getText("ContextMenu_Amputate"), self, self.openConfirmation, x, y, types[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CutLimbInteractionHandler:dropItems(items)
|
||||
local types = self:getAllItemTypes(items)
|
||||
if #self.items.ITEMS > 0 and #types == 1 and StaticData.LIMBS_TO_BODYLOCS_IND_BPT[self.limbName] then
|
||||
self:onMenuOptionSelected(types[1])
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Check if CutLimbInteractionHandler is valid, the limb must not be cut to be valid
|
||||
---@return boolean
|
||||
function CutLimbInteractionHandler:isValid()
|
||||
--TOC_DEBUG.print("CutLimbInteractionHandler isValid")
|
||||
self:checkItems()
|
||||
local patientUsername = self:getPatient():getUsername()
|
||||
return not DataController.GetInstance(patientUsername):getIsCut(self.limbName)
|
||||
end
|
||||
|
||||
function CutLimbInteractionHandler:perform(previousAction, itemType)
|
||||
local item = self:getItemOfType(self.items.ITEMS, itemType)
|
||||
previousAction = self:toPlayerInventory(item, previousAction)
|
||||
TOC_DEBUG.print("Perform CutLimbInteractionHandler on " .. self.limbName)
|
||||
local action = CutLimbAction:new(self:getDoctor(),self:getPatient(), self.limbName, item)
|
||||
ISTimedActionQueue.addAfter(previousAction, action)
|
||||
end
|
||||
|
||||
return CutLimbInteractionHandler
|
||||
@@ -0,0 +1,141 @@
|
||||
-- Had to copy and paste this stuff from the base game since this is a local only class. Kinda shit, but eh
|
||||
|
||||
---@class BaseHandler : ISBaseObject
|
||||
---@field panel ISUIElement
|
||||
---@field bodyPart BodyPart
|
||||
---@field items table
|
||||
local BaseHandler = ISBaseObject:derive("BaseHandler")
|
||||
|
||||
---@param panel ISUIElement
|
||||
---@param bodyPart BodyPart
|
||||
---@return table
|
||||
function BaseHandler:new(panel, bodyPart)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
o.panel = panel
|
||||
o.bodyPart = bodyPart
|
||||
o.items = {}
|
||||
return o
|
||||
end
|
||||
|
||||
function BaseHandler:isInjured()
|
||||
TOC_DEBUG.print("Running isInjured")
|
||||
local bodyPart = self.bodyPart
|
||||
return (bodyPart:HasInjury() or bodyPart:stitched() or bodyPart:getSplintFactor() > 0) and not bodyPart:bandaged()
|
||||
end
|
||||
|
||||
function BaseHandler:checkItems()
|
||||
for k,v in pairs(self.items) do
|
||||
table.wipe(v)
|
||||
end
|
||||
|
||||
local containers = ISInventoryPaneContextMenu.getContainers(self:getDoctor())
|
||||
local done = {}
|
||||
local childContainers = {}
|
||||
if containers ~= nil then
|
||||
for i=1, containers:size() do
|
||||
local container = containers:get(i-1)
|
||||
done[container] = true
|
||||
table.wipe(childContainers)
|
||||
self:checkContainerItems(container, childContainers)
|
||||
for _,container2 in ipairs(childContainers) do
|
||||
if not done[container2] then
|
||||
done[container2] = true
|
||||
self:checkContainerItems(container2, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function BaseHandler:checkContainerItems(container, childContainers)
|
||||
local containerItems = container:getItems()
|
||||
for i=1,containerItems:size() do
|
||||
local item = containerItems:get(i-1)
|
||||
if item:IsInventoryContainer() then
|
||||
if childContainers then
|
||||
table.insert(childContainers, item:getInventory())
|
||||
end
|
||||
else
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
self:checkItem(item) -- This is in inherited classes, we never use this class by itself
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function BaseHandler:dropItems(items)
|
||||
return false
|
||||
end
|
||||
|
||||
function BaseHandler:addItem(items, item)
|
||||
table.insert(items, item)
|
||||
end
|
||||
|
||||
function BaseHandler:getAllItemTypes(items)
|
||||
local done = {}
|
||||
local types = {}
|
||||
for _,item in ipairs(items) do
|
||||
if not done[item:getFullType()] then
|
||||
table.insert(types, item:getFullType())
|
||||
done[item:getFullType()] = true
|
||||
end
|
||||
end
|
||||
return types
|
||||
end
|
||||
|
||||
function BaseHandler:getItemOfType(items, type)
|
||||
for _,item in ipairs(items) do
|
||||
if item:getFullType() == type then
|
||||
return item
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function BaseHandler:getItemOfTag(items, type)
|
||||
for _,item in ipairs(items) do
|
||||
if item:hasTag(type) then
|
||||
return item
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function BaseHandler:getAllItemsOfType(items, type)
|
||||
items = {}
|
||||
for _,item in ipairs(items) do
|
||||
if item:getFullType() == type then
|
||||
table.insert(items, item)
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
function BaseHandler:onMenuOptionSelected(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
|
||||
ISTimedActionQueue.add(HealthPanelAction:new(self:getDoctor(), self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
|
||||
end
|
||||
|
||||
function BaseHandler:toPlayerInventory(item, previousAction)
|
||||
if item:getContainer() ~= self:getDoctor():getInventory() then
|
||||
local action = ISInventoryTransferAction:new(self:getDoctor(), item, item:getContainer(), self:getDoctor():getInventory())
|
||||
ISTimedActionQueue.addAfter(previousAction, action)
|
||||
-- FIX: ISHealthPanel.actions never gets cleared
|
||||
self.panel.actions = self.panel.actions or {}
|
||||
self.panel.actions[action] = self.bodyPart
|
||||
return action
|
||||
end
|
||||
return previousAction
|
||||
end
|
||||
|
||||
---@return IsoPlayer
|
||||
function BaseHandler:getDoctor()
|
||||
return self.panel.otherPlayer or self.panel.character
|
||||
end
|
||||
|
||||
---@return IsoPlayer
|
||||
function BaseHandler:getPatient()
|
||||
return self.panel.character
|
||||
end
|
||||
|
||||
return BaseHandler
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
local BaseHandler = require("TOC/UI/Interactions/HealthPanelBaseHandler")
|
||||
local CommonMethods = require("TOC/CommonMethods")
|
||||
local DataController = require("TOC/Controllers/DataController")
|
||||
|
||||
local CleanWoundAction = require("TOC/TimedActions/CleanWoundAction")
|
||||
-------------------------
|
||||
---@class WoundCleaningInteractionHandler : BaseHandler
|
||||
---@field username string
|
||||
---@field limbName string
|
||||
local WoundCleaningInteractionHandler = BaseHandler:derive("WoundCleaningInteractionHandler")
|
||||
|
||||
---@param panel any
|
||||
---@param bodyPart any
|
||||
---@param username string
|
||||
---@return table
|
||||
function WoundCleaningInteractionHandler:new(panel, bodyPart, username)
|
||||
local o = BaseHandler.new(self, panel, bodyPart)
|
||||
o.items.ITEMS = {}
|
||||
o.username = username
|
||||
|
||||
o.limbName = CommonMethods.GetLimbNameFromBodyPart(bodyPart)
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function WoundCleaningInteractionHandler:checkItem(item)
|
||||
-- Disinfected rag or bandage
|
||||
--TOC_DEBUG.print("WoundCleaningInteractionHandler checkItem")
|
||||
if item:getBandagePower() >=2 and item:isAlcoholic() then
|
||||
--TOC_DEBUG.print("Adding " .. item:getName())
|
||||
self:addItem(self.items.ITEMS, item)
|
||||
end
|
||||
end
|
||||
|
||||
function WoundCleaningInteractionHandler:addToMenu(context)
|
||||
--TOC_DEBUG.print("WoundCleaningInteraction addToMenu")
|
||||
|
||||
local types = self:getAllItemTypes(self.items.ITEMS)
|
||||
if #types > 0 and self:isValid() then
|
||||
TOC_DEBUG.print("WoundCleaningInteraction inside addToMenu")
|
||||
local option = context:addOption(getText("ContextMenu_CleanWound"), nil)
|
||||
local subMenu = context:getNew(context)
|
||||
context:addSubMenu(option, subMenu)
|
||||
for i=1, #types do
|
||||
local item = self:getItemOfType(self.items.ITEMS, types[i])
|
||||
subMenu:addOption(item:getName(), self, self.onMenuOptionSelected, item:getFullType())
|
||||
TOC_DEBUG.print(item:getName())
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function WoundCleaningInteractionHandler:dropItems(items)
|
||||
local types = self:getAllItemTypes(items)
|
||||
if #self.items.ITEMS > 0 and #types == 1 and self:isActionValid() then
|
||||
self:onMenuOptionSelected(types[1])
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function WoundCleaningInteractionHandler:isValid()
|
||||
self:checkItems()
|
||||
return self:isActionValid()
|
||||
end
|
||||
|
||||
function WoundCleaningInteractionHandler:isActionValid()
|
||||
if self.limbName == nil then return false end
|
||||
local dcInst = DataController.GetInstance(self.username)
|
||||
local check = dcInst:getIsCut(self.limbName) and not dcInst:getIsCicatrized(self.limbName) and dcInst:getWoundDirtyness(self.limbName) > 0
|
||||
--TOC_DEBUG.print("WoundCleaningInteraction isValid: " .. tostring(check))
|
||||
return check
|
||||
end
|
||||
|
||||
function WoundCleaningInteractionHandler:perform(previousAction, itemType)
|
||||
local item = self:getItemOfType(self.items.ITEMS, itemType)
|
||||
previousAction = self:toPlayerInventory(item, previousAction)
|
||||
local action = CleanWoundAction:new(self:getDoctor(), self:getPatient(), item, self.bodyPart)
|
||||
ISTimedActionQueue.addAfter(previousAction, action)
|
||||
end
|
||||
|
||||
|
||||
return WoundCleaningInteractionHandler
|
||||
99
42/media/lua/client/TOC/UI/SurgeryInteractions.lua
Normal file
99
42/media/lua/client/TOC/UI/SurgeryInteractions.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
local DataController = require("TOC/Controllers/DataController")
|
||||
local CauterizeAction = require("TOC/TimedActions/CauterizeAction")
|
||||
---------------
|
||||
|
||||
|
||||
---@param tooltip ISToolTip
|
||||
---@param desc string
|
||||
local function AppendToDescription(tooltip, desc)
|
||||
if tooltip.description == "" then
|
||||
desc = string.upper(string.sub(desc, 1, 1)) .. string.sub(desc, 2)
|
||||
tooltip.description = desc
|
||||
else
|
||||
desc = string.lower(string.sub(desc, 1, 1)) .. string.sub(desc, 2)
|
||||
tooltip.description = tooltip.description .. getText("Tooltip_Surgery_And") .. desc
|
||||
end
|
||||
end
|
||||
|
||||
---@param playerNum number
|
||||
---@param context ISContextMenu
|
||||
---@param worldObjects any
|
||||
---@param test any
|
||||
local function AddStoveContextMenu(playerNum, context, worldObjects, test)
|
||||
if test then return true end
|
||||
|
||||
local pl = getSpecificPlayer(playerNum)
|
||||
|
||||
local dcInst = DataController.GetInstance()
|
||||
if not dcInst:getIsAnyLimbCut() then return end
|
||||
local amputatedLimbs = CachedDataHandler.GetAmputatedLimbs(pl:getUsername())
|
||||
|
||||
---@type IsoStove?
|
||||
local stoveObj = nil
|
||||
for _, obj in pairs(worldObjects) do
|
||||
if instanceof(obj, "IsoStove") then
|
||||
stoveObj = obj
|
||||
break
|
||||
end
|
||||
end
|
||||
if stoveObj == nil then return end
|
||||
local tempTooltip = ISToolTip:new()
|
||||
tempTooltip:initialise()
|
||||
tempTooltip.description = ""
|
||||
tempTooltip:setVisible(false)
|
||||
|
||||
local addMainOption = false
|
||||
local subMenu
|
||||
|
||||
for k, _ in pairs(amputatedLimbs) do
|
||||
|
||||
-- We need to let the player cauterize ONLY the visible one!
|
||||
---@type string
|
||||
local limbName = k
|
||||
if dcInst:getIsVisible(limbName) and not dcInst:getIsCicatrized(limbName) then
|
||||
if addMainOption == false then
|
||||
-- Adds the cauterize option ONLY when it's needed
|
||||
local optionMain = context:addOption(getText("ContextMenu_Cauterize"), nil)
|
||||
subMenu = context:getNew(context)
|
||||
context:addSubMenu(optionMain, subMenu)
|
||||
addMainOption = true
|
||||
end
|
||||
|
||||
local option = subMenu:addOption(getText("ContextMenu_Limb_" .. limbName), nil, function()
|
||||
local adjacent = AdjacentFreeTileFinder.Find(stoveObj:getSquare(), pl)
|
||||
ISTimedActionQueue.add(ISWalkToTimedAction:new(pl, adjacent))
|
||||
ISTimedActionQueue.add(CauterizeAction:new(pl, limbName, stoveObj))
|
||||
end)
|
||||
|
||||
|
||||
-- Notifications, in case the player can't do the action
|
||||
local isPlayerCourageous = pl:hasTrait(CharacterTrait.BRAVE) or pl:hasTrait(CharacterTrait.DESENSITIZED) or pl:getPerkLevel(Perks.Strength) > 5
|
||||
local isTempHighEnough = stoveObj:getCurrentTemperature()-1 >= 2.50
|
||||
local isLimbFree = not dcInst:getIsProstEquipped(limbName)
|
||||
TOC_DEBUG.print(stoveObj:getCurrentTemperature())
|
||||
|
||||
option.notAvailable = not(isPlayerCourageous and isTempHighEnough and isLimbFree)
|
||||
if not isTempHighEnough then
|
||||
AppendToDescription(tempTooltip, getText("Tooltip_Surgery_TempTooLow"))
|
||||
end
|
||||
|
||||
if not isPlayerCourageous then
|
||||
AppendToDescription(tempTooltip, getText("Tooltip_Surgery_Coward"))
|
||||
end
|
||||
|
||||
if not isLimbFree then
|
||||
AppendToDescription(tempTooltip, getText("Tooltip_Surgery_LimbNotFree"))
|
||||
end
|
||||
|
||||
if option.notAvailable then
|
||||
tempTooltip:setName(getText("Tooltip_Surgery_CantCauterize"))
|
||||
option.toolTip = tempTooltip
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Events.OnFillWorldObjectContextMenu.Add(AddStoveContextMenu)
|
||||
157
42/media/lua/client/TOC/Zombies/ZombiesAmputation.lua
Normal file
157
42/media/lua/client/TOC/Zombies/ZombiesAmputation.lua
Normal file
@@ -0,0 +1,157 @@
|
||||
require "lua_timers"
|
||||
|
||||
local ItemsController = require("TOC/Controllers/ItemsController")
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
-------------------------------
|
||||
|
||||
---@param zombie IsoZombie|IsoGameCharacter|IsoMovingObject|IsoObject
|
||||
---@return integer trueID
|
||||
local function GetZombieID(zombie)
|
||||
-- Big love to Chuck and Sir Doggy Jvla for this code
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local pID = zombie:getPersistentOutfitID()
|
||||
local bits = string.split(string.reverse(Long.toUnsignedString(pID, 2)), "")
|
||||
while #bits < 16 do bits[#bits + 1] = 0 end
|
||||
|
||||
-- trueID
|
||||
bits[16] = 0
|
||||
local trueID = Long.parseUnsignedLong(string.reverse(table.concat(bits, "")), 2)
|
||||
|
||||
return trueID
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
|
||||
|
||||
---@param item InventoryItem
|
||||
local function PredicateAmputationItems(item)
|
||||
return item:getType():contains("Amputation_")
|
||||
end
|
||||
|
||||
---@param item InventoryItem
|
||||
local function PredicateAmputationItemLeft(item)
|
||||
return item:getType():contains("Amputation_") and item:getType():contains("_L")
|
||||
end
|
||||
|
||||
---@param item InventoryItem
|
||||
local function PredicateAmputationItemRight(item)
|
||||
return item:getType():contains("Amputation_") and item:getType():contains("_R")
|
||||
end
|
||||
|
||||
---@param zombie IsoZombie
|
||||
local function SpawnAmputation(zombie, side)
|
||||
local index = ZombRand(1, #StaticData.PARTS_STR)
|
||||
local limb = StaticData.PARTS_STR[index] .. "_" .. side
|
||||
local amputationFullType = StaticData.AMPUTATION_CLOTHING_ITEM_BASE .. limb
|
||||
|
||||
|
||||
ItemsController.Zombie.SpawnAmputationItem(zombie, amputationFullType)
|
||||
|
||||
|
||||
-- Add reference and transmit it to server
|
||||
local pID = GetZombieID(zombie)
|
||||
local zombieKey = CommandsData.GetZombieKey()
|
||||
local zombiesMD = ModData.getOrCreate(zombieKey)
|
||||
if zombiesMD[pID] == nil then zombiesMD[pID] = {} end
|
||||
zombiesMD[pID][side] = amputationFullType
|
||||
ModData.add(zombieKey, zombiesMD)
|
||||
ModData.transmit(zombieKey)
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
|
||||
local bloodAmount = 10
|
||||
|
||||
|
||||
---@param player IsoGameCharacter
|
||||
---@param zombie IsoZombie
|
||||
---@param handWeapon HandWeapon
|
||||
local function HandleZombiesAmputations(player, zombie, handWeapon, damage)
|
||||
if not SandboxVars.TOC.EnableZombieAmputations then return end
|
||||
|
||||
if not instanceof(zombie, "IsoZombie") or not instanceof(player, "IsoPlayer") then return end
|
||||
if player ~= getPlayer() then return end
|
||||
|
||||
-- Check type of weapon. No hands, only knifes or such
|
||||
local weaponCategories = handWeapon:getScriptItem():getCategories()
|
||||
if not (weaponCategories:contains("Axe") or weaponCategories:contains("LongBlade")) then return end
|
||||
|
||||
local isCrit = player:isCriticalHit()
|
||||
local randomChance = ZombRand(0, 100) > (100 - SandboxVars.TOC.ZombieAmputationDamageChance)
|
||||
if (damage > SandboxVars.TOC.ZombieAmputationDamageThreshold and randomChance) or isCrit then
|
||||
TOC_DEBUG.print("Amputating zombie limbs - damage: " .. tostring(damage))
|
||||
local zombieInv = zombie:getInventory()
|
||||
|
||||
-- Check left or right
|
||||
local randSide = ZombRand(2) -- Random side
|
||||
local preferredSide = randSide == 0 and "L" or "R"
|
||||
local alternateSide = preferredSide == "L" and "R" or "L"
|
||||
|
||||
local predicatePreferred = preferredSide == "L" and PredicateAmputationItemLeft or PredicateAmputationItemRight
|
||||
local predicateAlternate = alternateSide == "L" and PredicateAmputationItemLeft or PredicateAmputationItemRight
|
||||
|
||||
if not zombieInv:containsEval(predicatePreferred) then
|
||||
SpawnAmputation(zombie, preferredSide)
|
||||
elseif not zombieInv:containsEval(predicateAlternate) then
|
||||
SpawnAmputation(zombie, alternateSide)
|
||||
end
|
||||
|
||||
TOC_DEBUG.print("Amputating zombie limbs - damage: " .. tostring(damage) .. ", preferred limb side: " .. preferredSide)
|
||||
|
||||
-- add blood splat every couple of seconds for a while
|
||||
addBloodSplat(getCell():getGridSquare(zombie:getX(), zombie:getY(), zombie:getZ()), bloodAmount)
|
||||
local timerName = tostring(GetZombieID(zombie)) .. "_timer"
|
||||
timer:Create(timerName, 1, 10, function()
|
||||
addBloodSplat(getCell():getGridSquare(zombie:getX(), zombie:getY(), zombie:getZ()), bloodAmount)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnWeaponHitCharacter.Add(HandleZombiesAmputations)
|
||||
|
||||
-----------------------------
|
||||
|
||||
local localOnlyZombiesMD
|
||||
|
||||
local function SetupZombiesModData()
|
||||
if not SandboxVars.TOC.EnableZombieAmputations then return end
|
||||
local zombieKey = CommandsData.GetZombieKey()
|
||||
localOnlyZombiesMD = ModData.getOrCreate(zombieKey)
|
||||
end
|
||||
|
||||
Events.OnInitGlobalModData.Add(SetupZombiesModData)
|
||||
|
||||
|
||||
---@param zombie IsoZombie
|
||||
local function ReapplyAmputation(zombie)
|
||||
if not SandboxVars.TOC.EnableZombieAmputations then return end
|
||||
|
||||
local pID = GetZombieID(zombie)
|
||||
|
||||
if localOnlyZombiesMD[pID] ~= nil then
|
||||
-- check if zombie has amputation
|
||||
local zombiesAmpData = localOnlyZombiesMD[pID]
|
||||
local zombieInv = zombie:getInventory()
|
||||
local foundItem = zombieInv:containsEvalRecurse(PredicateAmputationItems)
|
||||
|
||||
if foundItem then
|
||||
return
|
||||
else
|
||||
local leftAmp = zombiesAmpData['L']
|
||||
if leftAmp then
|
||||
ItemsController.Zombie.SpawnAmputationItem(zombie, leftAmp)
|
||||
end
|
||||
|
||||
local rightAmp = zombiesAmpData['R']
|
||||
if rightAmp then
|
||||
ItemsController.Zombie.SpawnAmputationItem(zombie, rightAmp)
|
||||
end
|
||||
|
||||
-- Removes reference, local only
|
||||
localOnlyZombiesMD[pID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnZombieUpdate.Add(ReapplyAmputation)
|
||||
171
42/media/lua/client/lua_timers.lua
Normal file
171
42/media/lua/client/lua_timers.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
-- Made by Vyshnia
|
||||
-- Workshop ID: 2875394066
|
||||
-- Mod ID: LuaTimers
|
||||
|
||||
local os_time = os.time
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
local assert = assert
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
|
||||
timer = {
|
||||
Timers = {},
|
||||
SimpleTimers = {}
|
||||
}
|
||||
|
||||
function timer:Simple(delay, func)
|
||||
assert(type(delay) == "number", "Delay of timer should be a number type")
|
||||
assert(type(func) == "function", "Func of timer should be a function type (lol)")
|
||||
|
||||
table_insert(self.SimpleTimers, {
|
||||
EndTime = os_time() + delay,
|
||||
Func = func
|
||||
})
|
||||
end
|
||||
|
||||
function timer:Create(name, delay, repetitions, func)
|
||||
assert(type(name) == "string", "ID of timer should be a string type")
|
||||
assert(type(delay) == "number", "Delay of timer should be a number type")
|
||||
assert(type(repetitions) == "number", "Repetitions of timer should be a number type")
|
||||
assert(type(func) == "function", "Func of timer should be a function type (lol)")
|
||||
|
||||
self.Timers[name] = {
|
||||
Delay = delay,
|
||||
StartRepetitions = repetitions,
|
||||
Repetitions = repetitions,
|
||||
Infinity = repetitions == 0,
|
||||
LastFuncTime = os_time(),
|
||||
Func = func,
|
||||
Paused = false,
|
||||
}
|
||||
end
|
||||
|
||||
local function timerUpdate()
|
||||
local cur_time = os_time()
|
||||
|
||||
for k, v in pairs(timer.Timers) do
|
||||
if not v.Paused then
|
||||
if cur_time >= v.LastFuncTime + v.Delay then
|
||||
v.Func()
|
||||
|
||||
v.LastFuncTime = cur_time
|
||||
|
||||
if not v.Infinity then
|
||||
v.Repetitions = v.Repetitions - 1
|
||||
|
||||
if v.Repetitions <= 0 then
|
||||
timer.Timers[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local simple_timers = timer.SimpleTimers
|
||||
|
||||
for i = #simple_timers, 1, -1 do
|
||||
local t = simple_timers[i]
|
||||
|
||||
if t.EndTime <= cur_time then
|
||||
t.Func()
|
||||
|
||||
table_remove(simple_timers, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
Events.OnTickEvenPaused.Add(timerUpdate)
|
||||
|
||||
function timer:Remove(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
self.Timers[name] = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function timer:Exists(name)
|
||||
return self.Timers[name] and true or false
|
||||
end
|
||||
|
||||
function timer:Start(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
t.Repetitions = t.StartRepetitions
|
||||
t.LastFuncTime = os_time()
|
||||
t.Paused = false
|
||||
t.PausedTime = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function timer:Pause(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
if t.Paused then return false end
|
||||
|
||||
t.Paused = true
|
||||
t.PausedTime = os_time()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function timer:UnPause(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
if not t.Paused then return false end
|
||||
|
||||
t.Paused = false
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
timer.Resume = timer.UnPause
|
||||
|
||||
function timer:Toggle(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return false end
|
||||
|
||||
t.Paused = not t.Paused
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function timer:TimeLeft(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return end
|
||||
|
||||
if t.Paused then
|
||||
return (t.Repetitions - 1) * t.Delay + (t.LastFuncTime + t.Delay - t.PausedTime)
|
||||
else
|
||||
return (t.Repetitions - 1) * t.Delay + (t.LastFuncTime + t.Delay - os_time())
|
||||
end
|
||||
end
|
||||
|
||||
function timer:NextTimeLeft(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
if not t then return end
|
||||
|
||||
if t.Paused then
|
||||
return t.LastFuncTime + t.Delay - t.PausedTime
|
||||
else
|
||||
return t.LastFuncTime + t.Delay - os_time()
|
||||
end
|
||||
end
|
||||
|
||||
function timer:RepsLeft(name)
|
||||
local t = self.Timers[name]
|
||||
|
||||
return t and t.Repetitions
|
||||
end
|
||||
32
42/media/lua/server/TOC/DebugCommands.lua
Normal file
32
42/media/lua/server/TOC/DebugCommands.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
local ServerDataHandler = require("TOC/ServerDataHandler")
|
||||
----------------------------
|
||||
|
||||
local DebugCommands = {}
|
||||
|
||||
---comment
|
||||
---@param playerObj IsoPlayer
|
||||
---@param args table
|
||||
function DebugCommands.PrintAllTocData(playerObj, args)
|
||||
TOC_DEBUG.printTable(ServerDataHandler.modData)
|
||||
end
|
||||
|
||||
---Print ALL TOC data
|
||||
---@param playerObj IsoPlayer
|
||||
---@param args printTocDataParams
|
||||
function DebugCommands.PrintTocData(playerObj, args)
|
||||
local key = CommandsData.GetKey(args.username)
|
||||
local tocData = ServerDataHandler.GetTable(key)
|
||||
TOC_DEBUG.printTable(tocData)
|
||||
end
|
||||
|
||||
--------------------
|
||||
|
||||
local function OnClientDebugCommand(module, command, playerObj, args)
|
||||
if module == CommandsData.modules.TOC_DEBUG and DebugCommands[command] then
|
||||
DebugCommands[command](playerObj, args)
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnClientCommand.Add(OnClientDebugCommand)
|
||||
|
||||
31
42/media/lua/server/TOC/Distributions.lua
Normal file
31
42/media/lua/server/TOC/Distributions.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
require('Items/Distributions')
|
||||
require('Items/SuburbsDistributions')
|
||||
|
||||
-- Insert Prosts and various items in the Medical Clinic loot table
|
||||
|
||||
local prosthesisLoot = {
|
||||
[1] = {
|
||||
name = "TOC.Prost_HookArm_L",
|
||||
chance = 3
|
||||
},
|
||||
|
||||
[2] = {
|
||||
name = "TOC.Prost_NormalArm_L",
|
||||
chance = 2
|
||||
},
|
||||
|
||||
[3] = {
|
||||
name = "TOC.Surg_Arm_Tourniquet_L",
|
||||
chance = 20
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for i=1, #prosthesisLoot do
|
||||
local tab = prosthesisLoot[i]
|
||||
table.insert(ProceduralDistributions.list.MedicalClinicTools.items, tab.name)
|
||||
table.insert(ProceduralDistributions.list.MedicalClinicTools.items, tab.chance)
|
||||
end
|
||||
|
||||
|
||||
|
||||
15
42/media/lua/server/TOC/LimitActionsController.lua
Normal file
15
42/media/lua/server/TOC/LimitActionsController.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
local CachedDataHandler = require("TOC/Handlers/CachedDataHandler")
|
||||
------------------------------
|
||||
|
||||
local og_ISObjectClickHandler_doClickSpecificObject = ISObjectClickHandler.doClickSpecificObject
|
||||
|
||||
---@param object IsoObject
|
||||
---@param playerNum any
|
||||
---@param playerObj IsoPlayer
|
||||
function ISObjectClickHandler.doClickSpecificObject(object, playerNum, playerObj)
|
||||
if CachedDataHandler.GetBothHandsFeasibility() then
|
||||
og_ISObjectClickHandler_doClickSpecificObject(object, playerNum, playerObj)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
60
42/media/lua/server/TOC/ServerDataHandler.lua
Normal file
60
42/media/lua/server/TOC/ServerDataHandler.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
if isClient() then return end -- The event makes this necessary to prevent clients from running this file
|
||||
local StaticData = require("TOC/StaticData")
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
------------------------
|
||||
|
||||
local ServerDataHandler = {}
|
||||
ServerDataHandler.modData = {}
|
||||
|
||||
---Get the server mod data table containing that player TOC data
|
||||
---@param key string
|
||||
---@return tocModDataType
|
||||
function ServerDataHandler.GetTable(key)
|
||||
return ServerDataHandler.modData[key]
|
||||
end
|
||||
|
||||
---Add table to the ModData and a local table
|
||||
---@param key string
|
||||
---@param table tocModDataType
|
||||
function ServerDataHandler.AddTable(key, table)
|
||||
-- Check if key is valid
|
||||
if not luautils.stringStarts(key, StaticData.MOD_NAME .. "_") then return end
|
||||
|
||||
TOC_DEBUG.print("Received TOC ModData: " .. tostring(key))
|
||||
--TOC_DEBUG.printTable(table)
|
||||
|
||||
-- Set that the data has been modified and it's updated on the server
|
||||
ModData.add(key, table) -- Add it to the server mod data
|
||||
ServerDataHandler.modData[key] = table
|
||||
|
||||
|
||||
-- Check integrity of table. if it doesn't contains toc data, it means that we received a reset
|
||||
if table.limbs == nil then return end
|
||||
|
||||
-- Since this could be triggered by a different client than the one referenced in the key, we're gonna
|
||||
-- apply the changes back to the key client again to be sure that everything is in sync
|
||||
local username = CommandsData.GetUsername(key)
|
||||
TOC_DEBUG.print("Reapplying to " .. username)
|
||||
|
||||
-- Since getPlayerFromUsername doesn't work in mp, we're gonna do this workaround. ew
|
||||
local onlinePlayers = getOnlinePlayers()
|
||||
local selectedPlayer
|
||||
for i=0, onlinePlayers:size() - 1 do
|
||||
|
||||
---@type IsoPlayer
|
||||
local player = onlinePlayers:get(i)
|
||||
if player:getUsername() == username then
|
||||
selectedPlayer = player
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
TOC_DEBUG.print("Player username from IsoPlayer: " .. selectedPlayer:getUsername())
|
||||
sendServerCommand(selectedPlayer, CommandsData.modules.TOC_RELAY, CommandsData.client.Relay.ReceiveApplyFromServer, {})
|
||||
|
||||
end
|
||||
|
||||
Events.OnReceiveGlobalModData.Add(ServerDataHandler.AddTable)
|
||||
|
||||
|
||||
return ServerDataHandler
|
||||
67
42/media/lua/server/TOC/ServerRelayCommands.lua
Normal file
67
42/media/lua/server/TOC/ServerRelayCommands.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
require ("TOC/Debug")
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
--------------------------------------------
|
||||
|
||||
local ServerRelayCommands = {}
|
||||
|
||||
-- TODO We can easily make this a lot more simple without having functions
|
||||
|
||||
---Relay DamageDuringAmputation to another client
|
||||
---@param args relayDamageDuringAmputationParams
|
||||
function ServerRelayCommands.RelayDamageDuringAmputation(_, args)
|
||||
local patientPl = getPlayerByOnlineID(args.patientNum)
|
||||
|
||||
---@type receiveDamageDuringAmputationParams
|
||||
local params = {limbName = args.limbName}
|
||||
sendServerCommand(patientPl, CommandsData.modules.TOC_RELAY, CommandsData.client.Relay.ReceiveDamageDuringAmputation, params)
|
||||
end
|
||||
|
||||
---Relay ExecuteAmputationAction to another client
|
||||
---@param surgeonPl IsoPlayer
|
||||
---@param args relayExecuteAmputationActionParams
|
||||
function ServerRelayCommands.RelayExecuteAmputationAction(surgeonPl, args)
|
||||
local patientPl = getPlayerByOnlineID(args.patientNum)
|
||||
local surgeonNum = surgeonPl:getOnlineID()
|
||||
|
||||
---@type receiveDamageDuringAmputationParams
|
||||
local params = {surgeonNum = surgeonNum, limbName = args.limbName, damagePlayer = true}
|
||||
sendServerCommand(patientPl, CommandsData.modules.TOC_RELAY, CommandsData.client.Relay.ReceiveExecuteAmputationAction, params)
|
||||
end
|
||||
|
||||
--* ADMIN ONLY *--
|
||||
---Relay a local init from another client
|
||||
---@param adminObj IsoPlayer
|
||||
---@param args relayExecuteInitializationParams
|
||||
function ServerRelayCommands.RelayExecuteInitialization(adminObj, args)
|
||||
local patientPl = getPlayerByOnlineID(args.patientNum)
|
||||
sendServerCommand(patientPl, CommandsData.modules.TOC_RELAY, CommandsData.client.Relay.ReceiveExecuteInitialization, {})
|
||||
|
||||
end
|
||||
|
||||
---Relay a forced amputation to another client.
|
||||
---@param adminObj IsoPlayer
|
||||
---@param args relayForcedAmputationParams
|
||||
function ServerRelayCommands.RelayForcedAmputation(adminObj, args)
|
||||
local patientPl = getPlayerByOnlineID(args.patientNum)
|
||||
local adminNum = adminObj:getOnlineID()
|
||||
|
||||
---@type receiveDamageDuringAmputationParams
|
||||
local ampParams = {surgeonNum = adminNum, limbName = args.limbName, damagePlayer = false} -- the only difference between relayExecuteAmputationAction and this is the damage
|
||||
sendServerCommand(patientPl, CommandsData.modules.TOC_RELAY, CommandsData.client.Relay.ReceiveExecuteAmputationAction, ampParams)
|
||||
|
||||
-- Automatic cicatrization
|
||||
sendServerCommand(patientPl, CommandsData.modules.TOC_RELAY, CommandsData.client.Relay.ReceiveForcedCicatrization, {limbName = args.limbName})
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
|
||||
local function OnClientRelayCommand(module, command, playerObj, args)
|
||||
if module == CommandsData.modules.TOC_RELAY and ServerRelayCommands[command] then
|
||||
TOC_DEBUG.print("Received Client Relay command - " .. tostring(command))
|
||||
ServerRelayCommands[command](playerObj, args)
|
||||
end
|
||||
end
|
||||
|
||||
Events.OnClientCommand.Add(OnClientRelayCommand)
|
||||
109
42/media/lua/shared/TOC/BodyLocations.lua
Normal file
109
42/media/lua/shared/TOC/BodyLocations.lua
Normal file
@@ -0,0 +1,109 @@
|
||||
--Based on RabenRabo's bodylocation solution from their mod "Fantasy Bodyparts" and "Fantasy Legs" sub-mod.
|
||||
--Modified by GanydeBielovzki with permission for batch use for the Frockin' Splendor franchise and spin-offs.
|
||||
--To copy, further modify or otherwise use this code the original creator and the modifier must be credited.
|
||||
|
||||
local function copyBodyLocationProperties(oldGroup, oldLocID, newGroup)
|
||||
for k = 0, oldGroup:size()-1 do
|
||||
local otherLocID = oldGroup:getLocationByIndex(k):getId()
|
||||
if oldGroup:isExclusive(oldLocID, otherLocID)
|
||||
then
|
||||
newGroup:setExclusive(oldLocID, otherLocID)
|
||||
end
|
||||
if oldGroup:isHideModel(oldLocID, otherLocID)
|
||||
then
|
||||
newGroup:setHideModel(oldLocID, otherLocID)
|
||||
end
|
||||
if oldGroup:isAltModel(oldLocID, otherLocID)
|
||||
then
|
||||
newGroup:setAltModel(oldLocID, otherLocID)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addBodyLocationsAt(groupName, locationList)
|
||||
local results = {}
|
||||
|
||||
-- get list (!!actually a view!!) of all groups and copy to array (BodyLocations.reset() will also clear the view)
|
||||
local allGroupsList = BodyLocations.getAllGroups()
|
||||
local allGroups = {}
|
||||
for i = 0, allGroupsList:size()-1 do
|
||||
allGroups[i + 1] = allGroupsList:get(i)
|
||||
end
|
||||
|
||||
BodyLocations.reset()
|
||||
|
||||
-- recreate all groups/bodylocations and insert new bodylocations
|
||||
for i = 1, #allGroups do
|
||||
local oldGroup = allGroups[i]
|
||||
local newGroup = BodyLocations.getGroup(oldGroup:getId())
|
||||
|
||||
-- FIRST: Process all original locations AND insert new ones at correct positions
|
||||
for j = 0, oldGroup:size()-1 do
|
||||
local oldLoc = oldGroup:getLocationByIndex(j)
|
||||
local oldLocID = oldLoc:getId()
|
||||
|
||||
-- For each location definition, check if it should be inserted here
|
||||
for _, locDef in ipairs(locationList) do
|
||||
if oldGroup:getId() == groupName then
|
||||
local newLocID = type(locDef.name) ~= "string" and locDef.name or
|
||||
ItemBodyLocation.get(ResourceLocation.of(locDef.name))
|
||||
|
||||
local refLocID = type(locDef.reference) ~= "string" and locDef.reference or
|
||||
ResourceLocation.of(locDef.reference)
|
||||
|
||||
local isTargetGroupAndLoc = refLocID == oldLocID
|
||||
|
||||
if isTargetGroupAndLoc and locDef.before then
|
||||
results[locDef.name] = newGroup:getOrCreateLocation(newLocID)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add the original location
|
||||
newGroup:getOrCreateLocation(oldLocID)
|
||||
|
||||
-- Check for "after" insertions
|
||||
for _, locDef in ipairs(locationList) do
|
||||
if oldGroup:getId() == groupName then
|
||||
local newLocID = type(locDef.name) ~= "string" and locDef.name or
|
||||
ItemBodyLocation.get(ResourceLocation.of(locDef.name))
|
||||
|
||||
local refLocID = type(locDef.reference) ~= "string" and locDef.reference or
|
||||
ResourceLocation.of(locDef.reference)
|
||||
|
||||
local isTargetGroupAndLoc = refLocID == oldLocID
|
||||
|
||||
if isTargetGroupAndLoc and not locDef.before then
|
||||
results[locDef.name] = newGroup:getOrCreateLocation(newLocID)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- SECOND: copy bodylocation properties from old groups to new groups
|
||||
for j = 0, oldGroup:size()-1 do
|
||||
local oldLocID = oldGroup:getLocationByIndex(j):getId()
|
||||
newGroup:setMultiItem(oldLocID, oldGroup:isMultiItem(oldLocID))
|
||||
copyBodyLocationProperties(oldGroup, oldLocID, newGroup)
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
end
|
||||
|
||||
local results = addBodyLocationsAt("Human", {
|
||||
{name = "toc:Arm_L", reference = ItemBodyLocation.FULL_TOP, before = false},
|
||||
{name = "toc:Arm_R", reference = ItemBodyLocation.FULL_TOP, before = false},
|
||||
{name = "toc:ArmProst_L", reference = ItemBodyLocation.FULL_TOP, before = false},
|
||||
{name = "toc:ArmProst_R", reference = ItemBodyLocation.FULL_TOP, before = false},
|
||||
{name = "toc:ArmAccessory_L", reference = ItemBodyLocation.FULL_TOP, before = false},
|
||||
{name = "toc:ArmAccessory_R", reference = ItemBodyLocation.FULL_TOP, before = false},
|
||||
})
|
||||
|
||||
|
||||
results['toc:Arm_L']:setMultiItem(true)
|
||||
results['toc:Arm_R']:setMultiItem(true)
|
||||
results['toc:ArmProst_L']:setMultiItem(true)
|
||||
results['toc:ArmProst_R']:setMultiItem(true)
|
||||
results['toc:ArmAccessory_L']:setMultiItem(true)
|
||||
results['toc:ArmAccessory_R']:setMultiItem(true)
|
||||
57
42/media/lua/shared/TOC/CommandsData.lua
Normal file
57
42/media/lua/shared/TOC/CommandsData.lua
Normal file
@@ -0,0 +1,57 @@
|
||||
local StaticData = require("TOC/StaticData")
|
||||
------------------------
|
||||
|
||||
local CommandsData = {}
|
||||
|
||||
CommandsData.modules = {
|
||||
TOC_DEBUG = "TOC_DEBUG",
|
||||
TOC_RELAY = "TOC_RELAY"
|
||||
}
|
||||
|
||||
CommandsData.client = {
|
||||
Relay = {
|
||||
ReceiveDamageDuringAmputation = "ReceiveDamageDuringAmputation", ---@alias receiveDamageDuringAmputationParams { limbName : string}
|
||||
ReceiveExecuteAmputationAction = "ReceiveExecuteAmputationAction", ---@alias receiveExecuteAmputationActionParams {surgeonNum : number, limbName : string, damagePlayer : boolean}
|
||||
|
||||
--* APPLY *--
|
||||
ReceiveApplyFromServer = "ReceiveApplyFromServer",
|
||||
|
||||
--* ADMIN ONLY --*
|
||||
ReceiveExecuteInitialization = "ReceiveExecuteInitialization",
|
||||
ReceiveForcedCicatrization = "ReceiveForcedCicatrization" ---@alias receiveForcedCicatrizationParams {limbName : string}
|
||||
}
|
||||
}
|
||||
|
||||
CommandsData.server = {
|
||||
Debug = {
|
||||
PrintTocData = "PrintTocData", ---@alias printTocDataParams {username : string}
|
||||
PrintAllTocData = "PrintAllTocData"
|
||||
},
|
||||
|
||||
Relay = {
|
||||
RelayDamageDuringAmputation = "RelayDamageDuringAmputation", ---@alias relayDamageDuringAmputationParams {patientNum : number, limbName : string}
|
||||
RelayExecuteAmputationAction = "RelayExecuteAmputationAction", ---@alias relayExecuteAmputationActionParams {patientNum : number, limbName : string}
|
||||
|
||||
--* ADMIN ONLY *--
|
||||
RelayExecuteInitialization = "RelayExecuteInitialization", ---@alias relayExecuteInitializationParams {patientNum : number}
|
||||
RelayForcedAmputation = "RelayForcedAmputation" ---@alias relayForcedAmputationParams {patientNum : number, limbName : string}
|
||||
}
|
||||
}
|
||||
|
||||
---Get the correct key for that particular player to be used in the global mod data table
|
||||
---@param username string
|
||||
---@return string
|
||||
function CommandsData.GetKey(username)
|
||||
return StaticData.MOD_NAME .. "_" .. username
|
||||
end
|
||||
|
||||
function CommandsData.GetUsername(key)
|
||||
return string.sub(key, #StaticData.MOD_NAME + 2, #key) -- Not sure why +2... Something with kahlua, it should be +1
|
||||
end
|
||||
|
||||
function CommandsData.GetZombieKey()
|
||||
return StaticData.MOD_NAME .. "_ZOMBIES"
|
||||
end
|
||||
|
||||
|
||||
return CommandsData
|
||||
112
42/media/lua/shared/TOC/Debug.lua
Normal file
112
42/media/lua/shared/TOC/Debug.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
TOC_DEBUG = {}
|
||||
TOC_DEBUG.disablePaneMod = false
|
||||
TOC_DEBUG.enableHealthPanelDebug = false
|
||||
|
||||
function TOC_DEBUG.TogglePaneMod()
|
||||
TOC_DEBUG.disablePaneMod = not TOC_DEBUG.disablePaneMod
|
||||
end
|
||||
|
||||
function TOC_DEBUG.ToggleHealthPanelDebug()
|
||||
TOC_DEBUG.enableHealthPanelDebug = not TOC_DEBUG.enableHealthPanelDebug
|
||||
end
|
||||
|
||||
---Print debug
|
||||
---@param string string
|
||||
function TOC_DEBUG.print(string)
|
||||
if isDebugEnabled() then
|
||||
local runningFile = TOC_DEBUG.getRunningFile()
|
||||
print("[TOC]" .. "[" .. runningFile .. "] " .. tostring(string))
|
||||
else
|
||||
print(string)
|
||||
end
|
||||
end
|
||||
|
||||
---Horrendous but I don't really care about performance for this
|
||||
---@return string
|
||||
function TOC_DEBUG.getRunningFile()
|
||||
local coroutine = getCurrentCoroutine()
|
||||
|
||||
local o = getCoroutineObjStack(coroutine, 0)
|
||||
if o then
|
||||
local s = KahluaUtil.rawTostring2(o)
|
||||
local match = string.match(s, "file: (%w+)%.lua")
|
||||
if match then return match end
|
||||
|
||||
end
|
||||
|
||||
return ""
|
||||
|
||||
end
|
||||
|
||||
function TOC_DEBUG.printTable(table, indent)
|
||||
if not table then return end
|
||||
indent = indent or ""
|
||||
|
||||
for key, value in pairs(table) do
|
||||
if type(value) == "table" then
|
||||
print(indent .. key .. " (table):")
|
||||
TOC_DEBUG.printTable(value, indent .. " ")
|
||||
else
|
||||
print(indent .. key .. ":", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------
|
||||
--* Random debug commands *--
|
||||
|
||||
function TOC_DEBUG.TestBodyDamage(id)
|
||||
local StaticData = require("TOC/StaticData")
|
||||
|
||||
local pl = getPlayerByOnlineID(id)
|
||||
local bd = pl:getBodyDamage()
|
||||
|
||||
TOC_DEBUG.print(tostring(bd))
|
||||
|
||||
if bd then
|
||||
TOC_DEBUG.print("bd for " .. pl:getUsername() .. " exists")
|
||||
local bptEnum = StaticData.LIMBS_TO_BODYLOCS_IND_BPT["Hand_L"]
|
||||
local bodyPart = bd:getBodyPart(bptEnum)
|
||||
|
||||
bodyPart:setBleeding(true)
|
||||
bodyPart:setCut(true)
|
||||
TOC_DEBUG.print(tostring(bodyPart))
|
||||
end
|
||||
end
|
||||
|
||||
function TOC_DEBUG.TestBloodDrop()
|
||||
local pl = getPlayer()
|
||||
|
||||
--IsoZombieGiblets.GibletType.A
|
||||
--local giblets = IsoZombieGiblets.new(getCell())
|
||||
|
||||
local sq = pl:getSquare()
|
||||
local t = IsoZombieGiblets.class.GibletType
|
||||
|
||||
print(t)
|
||||
--IsoBall.new(getCell(), pl:getX(), pl:)
|
||||
addBloodSplat(sq, 100)
|
||||
|
||||
|
||||
--pl:getChunk():addBloodSplat(pl:getX(), pl:getY(), pl:getZ(), 100)
|
||||
--IsoZombieGiblets.new(x, getCell(), pl:getX(), pl:getY(), pl:getZ(), 100, 1)
|
||||
|
||||
end
|
||||
---------------------------------
|
||||
--* Debug server commands *--
|
||||
|
||||
local CommandsData = require("TOC/CommandsData")
|
||||
|
||||
function TOC_DEBUG.printPlayerServerModData(username)
|
||||
sendClientCommand(CommandsData.modules.TOC_DEBUG, CommandsData.server.Debug.PrintTocData, {username = username})
|
||||
end
|
||||
|
||||
function TOC_DEBUG.printAllServerModData()
|
||||
sendClientCommand(CommandsData.modules.TOC_DEBUG, CommandsData.server.Debug.PrintAllTocData, {})
|
||||
end
|
||||
|
||||
function TOC_DEBUG.testRelayDamage()
|
||||
---@type relayDamageDuringAmputationParams
|
||||
local params = {limbName = "Hand_R", patientNum = getPlayer():getOnlineID()}
|
||||
sendClientCommand(CommandsData.modules.TOC_RELAY, CommandsData.server.Relay.RelayDamageDuringAmputation, params)
|
||||
end
|
||||
31
42/media/lua/shared/TOC/OverridenMethodsArchive.lua
Normal file
31
42/media/lua/shared/TOC/OverridenMethodsArchive.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
-- instead of relying on local to save og methods, we save them in a table here that we can use later.
|
||||
|
||||
---@class OverridenMethodsArchive
|
||||
local OverridenMethodsArchive = {}
|
||||
OverridenMethodsArchive.methods = {}
|
||||
|
||||
-- Save an original method, if it wasn't already saved and returns it to be used in common
|
||||
function OverridenMethodsArchive.Save(methodName, method)
|
||||
if not OverridenMethodsArchive.methods[methodName] then
|
||||
OverridenMethodsArchive.methods[methodName] = method
|
||||
TOC_DEBUG.print("Saved method " .. methodName)
|
||||
end
|
||||
|
||||
|
||||
return method
|
||||
|
||||
end
|
||||
|
||||
-- Get the original method
|
||||
function OverridenMethodsArchive.Get(methodName)
|
||||
--TOC_DEBUG.print("Getting og method " .. methodName)
|
||||
|
||||
--TOC_DEBUG.print("OverridenMethodsArchive.list[methodName] = " .. tostring(OverridenMethodsArchive.methods[methodName]))
|
||||
--TOC_DEBUG.print(methodName)
|
||||
--TOC_DEBUG.print(OverridenMethodsArchive.methods[methodName])
|
||||
return OverridenMethodsArchive.methods[methodName]
|
||||
|
||||
end
|
||||
|
||||
|
||||
return OverridenMethodsArchive
|
||||
1
42/media/lua/shared/TOC/Registries.lua
Normal file
1
42/media/lua/shared/TOC/Registries.lua
Normal file
@@ -0,0 +1 @@
|
||||
return _TOCRegistries
|
||||
300
42/media/lua/shared/TOC/StaticData.lua
Normal file
300
42/media/lua/shared/TOC/StaticData.lua
Normal file
@@ -0,0 +1,300 @@
|
||||
---@alias partDataType { isCut : boolean?, isInfected : boolean?, isOperated : boolean?, isCicatrized : boolean?, isCauterized : boolean?, isVisible : boolean?, woundDirtyness : number, cicatrizationTime : number }
|
||||
---@alias limbsTable {Hand_L : partDataType, ForeArm_L : partDataType, UpperArm_L : partDataType, Hand_R : partDataType, ForeArm_R : partDataType, UpperArm_R : partDataType }
|
||||
---@alias prosthesisData {isProstEquipped : boolean, prostFactor : number }
|
||||
---@alias prosthesesTable {Top_L : prosthesisData, Top_R : prosthesisData } -- TODO add Bottom_L and Bottom_R
|
||||
---@alias tocModDataType { limbs : limbsTable, prostheses : prosthesesTable, isIgnoredPartInfected : boolean, isAnyLimbCut : boolean}
|
||||
---------------------------
|
||||
|
||||
-- _STR = Only strings, no index
|
||||
-- _IND_STR = indexed Strings
|
||||
-- _IND_BPT = Indexed BodyPartType
|
||||
|
||||
-- PART = Single part, could be hand, forearm, etc
|
||||
-- LIMB = Part + side
|
||||
-- BODYLOCS = Body Locations
|
||||
|
||||
|
||||
|
||||
local StaticData = {}
|
||||
|
||||
---Mod name, used to setup Global Mod Data and various stuff
|
||||
StaticData.MOD_NAME = "TOC"
|
||||
|
||||
-- Game version, used to correct some stuff instead of relying on versioned folders
|
||||
|
||||
StaticData.COMPAT_42 = luautils.stringStarts(getGameVersion(), "42")
|
||||
|
||||
-------------------------
|
||||
--* Base
|
||||
|
||||
|
||||
-- TODO Add references inside tables instead of making multiple tables
|
||||
|
||||
StaticData.SIDES_IND_STR = {
|
||||
R = "R",
|
||||
L = "L"
|
||||
}
|
||||
StaticData.SIDES_STR = {
|
||||
"R", "L"
|
||||
}
|
||||
StaticData.PARTS_IND_STR = {
|
||||
Hand = "Hand",
|
||||
ForeArm = "ForeArm",
|
||||
UpperArm = "UpperArm"
|
||||
}
|
||||
StaticData.PARTS_STR = {
|
||||
"Hand",
|
||||
"ForeArm",
|
||||
"UpperArm"
|
||||
}
|
||||
|
||||
|
||||
-- No "MAX" here.
|
||||
StaticData.IGNORED_BODYLOCS_BPT = {
|
||||
BodyPartType.Foot_L, BodyPartType.Foot_R, BodyPartType.Groin, BodyPartType.Head,
|
||||
BodyPartType.LowerLeg_L, BodyPartType.LowerLeg_R, BodyPartType.Neck, BodyPartType.Torso_Lower,
|
||||
BodyPartType.Torso_Upper, BodyPartType.UpperLeg_L, BodyPartType.UpperLeg_R
|
||||
}
|
||||
|
||||
|
||||
-- Assembled BodyParts string
|
||||
StaticData.LIMBS_STR = {}
|
||||
StaticData.LIMBS_IND_STR = {}
|
||||
StaticData.LIMBS_DEPENDENCIES_IND_STR = {}
|
||||
StaticData.LIMBS_ADJACENT_IND_STR = {}
|
||||
StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM = {}
|
||||
StaticData.LIMBS_BASE_DAMAGE_IND_NUM = {}
|
||||
StaticData.LIMBS_TIME_MULTIPLIER_IND_NUM = {}
|
||||
|
||||
|
||||
|
||||
StaticData.LIMBS_TO_BODYLOCS_IND_BPT = {} -- {limbName = bodyLoc}
|
||||
StaticData.BODYLOCS_TO_LIMBS_IND_STR = {} -- {bodyLoc = limbName}
|
||||
|
||||
-- FIXME You weren't considering surgeonFactor, which decreases that base time. Fuck mod 60
|
||||
-- CicatrizationBaseTime should be mod 60 since we're using EveryHours to update the cicatrizationTime
|
||||
|
||||
---@param assembledName string
|
||||
---@param side string
|
||||
local function AssembleHandData(assembledName, side)
|
||||
StaticData.LIMBS_BASE_DAMAGE_IND_NUM[assembledName] = 60
|
||||
StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[assembledName] = 120
|
||||
StaticData.LIMBS_TIME_MULTIPLIER_IND_NUM[assembledName] = 2
|
||||
StaticData.LIMBS_DEPENDENCIES_IND_STR[assembledName] = {}
|
||||
StaticData.LIMBS_ADJACENT_IND_STR[assembledName] = StaticData.PARTS_IND_STR.ForeArm .. "_" .. side
|
||||
end
|
||||
|
||||
---@param assembledName string
|
||||
---@param side string
|
||||
local function AssembleForearmData(assembledName, side)
|
||||
StaticData.LIMBS_BASE_DAMAGE_IND_NUM[assembledName] = 80
|
||||
StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[assembledName] = 144
|
||||
StaticData.LIMBS_TIME_MULTIPLIER_IND_NUM[assembledName] = 3
|
||||
StaticData.LIMBS_DEPENDENCIES_IND_STR[assembledName] = { StaticData.PARTS_IND_STR.Hand .. "_" .. side }
|
||||
StaticData.LIMBS_ADJACENT_IND_STR[assembledName] = StaticData.PARTS_IND_STR.UpperArm .. "_" .. side
|
||||
end
|
||||
|
||||
---@param assembledName string
|
||||
---@param side string
|
||||
local function AssembleUpperarmData(assembledName, side)
|
||||
StaticData.LIMBS_BASE_DAMAGE_IND_NUM[assembledName] = 100
|
||||
StaticData.LIMBS_CICATRIZATION_TIME_IND_NUM[assembledName] = 192
|
||||
StaticData.LIMBS_TIME_MULTIPLIER_IND_NUM[assembledName] = 4
|
||||
StaticData.LIMBS_DEPENDENCIES_IND_STR[assembledName] = { StaticData.PARTS_IND_STR.Hand .. "_" .. side,
|
||||
StaticData.PARTS_IND_STR.ForeArm .. "_" .. side }
|
||||
StaticData.LIMBS_ADJACENT_IND_STR[assembledName] = "Torso_Upper"
|
||||
end
|
||||
|
||||
for side, _ in pairs(StaticData.SIDES_IND_STR) do
|
||||
for part, _ in pairs(StaticData.PARTS_IND_STR) do
|
||||
local assembledName = part .. "_" .. side
|
||||
|
||||
-- Assembled strings
|
||||
table.insert(StaticData.LIMBS_STR, assembledName) -- We need a table like this to cycle through it easily
|
||||
StaticData.LIMBS_IND_STR[assembledName] = assembledName
|
||||
|
||||
|
||||
-- BodyParts stuff
|
||||
---@type BodyPartType
|
||||
local bptType = BodyPartType[assembledName]
|
||||
local bptString = BodyPartType.ToString(bptType)
|
||||
|
||||
|
||||
StaticData.LIMBS_TO_BODYLOCS_IND_BPT[assembledName] = bptType
|
||||
StaticData.BODYLOCS_TO_LIMBS_IND_STR[bptString] = assembledName
|
||||
|
||||
-- Dependencies and cicatrization time
|
||||
if part == StaticData.PARTS_IND_STR.Hand then
|
||||
AssembleHandData(assembledName, side)
|
||||
elseif part == StaticData.PARTS_IND_STR.ForeArm then
|
||||
AssembleForearmData(assembledName, side)
|
||||
elseif part == StaticData.PARTS_IND_STR.UpperArm then
|
||||
AssembleUpperarmData(assembledName, side)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------
|
||||
--* Amputation Groups
|
||||
|
||||
StaticData.AMP_GROUPS_BASE_IND_STR = {
|
||||
Top = "Top",
|
||||
Bottom = "Bottom"
|
||||
}
|
||||
|
||||
-- FIX This should be aligned with the body locs, no reason anymore to keep it separated
|
||||
StaticData.AMP_GROUPS_IND_STR = {}
|
||||
StaticData.AMP_GROUPS_STR = {}
|
||||
|
||||
for side, _ in pairs(StaticData.SIDES_IND_STR) do
|
||||
for group, _ in pairs(StaticData.AMP_GROUPS_BASE_IND_STR) do
|
||||
local sidedGroup = group .. "_" .. side
|
||||
StaticData.AMP_GROUPS_IND_STR[sidedGroup] = sidedGroup
|
||||
table.insert(StaticData.AMP_GROUPS_STR, sidedGroup)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- TODO We can do this in one pass if we do it before
|
||||
|
||||
StaticData.AMP_GROUP_TO_LIMBS_MATCH_IND_STR = {} -- This is probably unnecessary
|
||||
StaticData.LIMBS_TO_AMP_GROUPS_MATCH_IND_STR = {}
|
||||
|
||||
for side, _ in pairs(StaticData.SIDES_IND_STR) do
|
||||
for part, _ in pairs(StaticData.PARTS_IND_STR) do
|
||||
local limbName = part .. "_" .. side
|
||||
local group
|
||||
if part == StaticData.PARTS_IND_STR.Hand or part == StaticData.PARTS_IND_STR.ForeArm or part == StaticData.PARTS_IND_STR.UpperArm then
|
||||
group = StaticData.AMP_GROUPS_BASE_IND_STR.Top
|
||||
else
|
||||
group = StaticData.AMP_GROUPS_BASE_IND_STR.Bottom
|
||||
end
|
||||
|
||||
local sidedGroup = group .. "_" .. side
|
||||
if StaticData.AMP_GROUP_TO_LIMBS_MATCH_IND_STR[sidedGroup] == nil then
|
||||
StaticData.AMP_GROUP_TO_LIMBS_MATCH_IND_STR[sidedGroup] = {}
|
||||
end
|
||||
table.insert(StaticData.AMP_GROUP_TO_LIMBS_MATCH_IND_STR[sidedGroup], limbName)
|
||||
|
||||
StaticData.LIMBS_TO_AMP_GROUPS_MATCH_IND_STR[limbName] = sidedGroup
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
StaticData.TOURNIQUET_BODYLOCS_TO_GROUPS_IND_STR = {
|
||||
[ItemBodyLocation.HANDS_LEFT] = StaticData.AMP_GROUPS_IND_STR.Top_L,
|
||||
[ItemBodyLocation.HANDS_RIGHT] = StaticData.AMP_GROUPS_IND_STR.Top_R
|
||||
}
|
||||
|
||||
|
||||
StaticData.AFFECTED_BODYLOCS_TO_LIMBS_IND_STR = {}
|
||||
|
||||
local handsBodyLocs = {"Hands%s", "%s_MiddleFinger", "%s_RingFinger"}
|
||||
local foreArmBodyLocs = {"%sWrist"}
|
||||
|
||||
|
||||
|
||||
for side, _ in pairs(StaticData.SIDES_IND_STR) do
|
||||
for part, _ in pairs(StaticData.PARTS_IND_STR) do
|
||||
local limbName = part .. "_" .. side
|
||||
|
||||
local sideFull
|
||||
if side == 'R' then sideFull = "Right" else sideFull = "Left" end
|
||||
|
||||
if part == "Hand" then
|
||||
for i=1, #handsBodyLocs do
|
||||
local bl = string.format(handsBodyLocs[i], sideFull)
|
||||
StaticData.AFFECTED_BODYLOCS_TO_LIMBS_IND_STR[bl] = limbName
|
||||
end
|
||||
elseif part == "ForeArm" then
|
||||
-- -- UGLY very ugly
|
||||
-- for i=1, #handsBodyLocs do
|
||||
-- local bl = string.format(handsBodyLocs[i], sideFull)
|
||||
-- StaticData.AFFECTED_BODYLOCS_TO_LIMBS_IND_STR[bl] = limbName
|
||||
-- end
|
||||
for i=1, #foreArmBodyLocs do
|
||||
local bl = string.format(foreArmBodyLocs[i], sideFull)
|
||||
StaticData.AFFECTED_BODYLOCS_TO_LIMBS_IND_STR[bl] = limbName
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--* Traits
|
||||
|
||||
-- Link a trait to a specific body part
|
||||
StaticData.TRAITS_BP = {
|
||||
Amputee_Hand = "Hand_L",
|
||||
Amputee_ForeArm = "ForeArm_L",
|
||||
Amputee_UpperArm = "UpperArm_L",
|
||||
}
|
||||
|
||||
-----------------
|
||||
--* Visuals and clothing
|
||||
|
||||
--- Textures
|
||||
StaticData.HEALTH_PANEL_TEXTURES = {
|
||||
|
||||
Female = {
|
||||
Hand_L = getTexture("media/ui/Female/Hand_L.png"),
|
||||
ForeArm_L = getTexture("media/ui/Female/ForeArm_L.png"),
|
||||
UpperArm_L = getTexture("media/ui/Female/UpperArm_L.png"),
|
||||
|
||||
Hand_R = getTexture("media/ui/Female/Hand_R.png"),
|
||||
ForeArm_R = getTexture("media/ui/Female/ForeArm_R.png"),
|
||||
UpperArm_R = getTexture("media/ui/Female/UpperArm_R.png")
|
||||
},
|
||||
|
||||
Male = {
|
||||
Hand_L = getTexture("media/ui/Male/Hand_L.png"),
|
||||
ForeArm_L = getTexture("media/ui/Male/ForeArm_L.png"),
|
||||
UpperArm_L = getTexture("media/ui/Male/UpperArm_L.png"),
|
||||
|
||||
Hand_R = getTexture("media/ui/Male/Hand_R.png"),
|
||||
ForeArm_R = getTexture("media/ui/Male/ForeArm_R.png"),
|
||||
UpperArm_R = getTexture("media/ui/Male/UpperArm_R.png")
|
||||
},
|
||||
|
||||
ProstArm = {
|
||||
L = getTexture("media/ui/ProstArm_L.png"),
|
||||
R = getTexture("media/ui/ProstArm_R.png")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StaticData.AMPUTATION_CLOTHING_ITEM_BASE = "TOC.Amputation_"
|
||||
|
||||
|
||||
------------------
|
||||
--* Items check
|
||||
|
||||
local sawObj
|
||||
local gardenSawObj
|
||||
|
||||
if StaticData.COMPAT_42 then
|
||||
sawObj = instanceItem("Base.Saw")
|
||||
gardenSawObj = instanceItem("Base.GardenSaw")
|
||||
else
|
||||
sawObj = InventoryItemFactory.CreateItem("Base.Saw")
|
||||
gardenSawObj = InventoryItemFactory.CreateItem("Base.GardenSaw")
|
||||
end
|
||||
|
||||
|
||||
StaticData.SAWS_NAMES_IND_STR = {
|
||||
saw = sawObj:getName(),
|
||||
gardenSaw = gardenSawObj:getName()
|
||||
}
|
||||
|
||||
StaticData.SAWS_TYPES_IND_STR = {
|
||||
saw = sawObj:getType(),
|
||||
gardenSaw = gardenSawObj:getType()
|
||||
}
|
||||
|
||||
|
||||
return StaticData
|
||||
22
42/media/lua/shared/Translate/DE/ContextMenu_DE.txt
Normal file
22
42/media/lua/shared/Translate/DE/ContextMenu_DE.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
ContextMenu_DE = {
|
||||
ContextMenu_Amputate = "Amputieren",
|
||||
ContextMenu_Amputate_Bandage = "Amputieren und bandagieren",
|
||||
ContextMenu_Amputate_Stitch = "Amputieren und nähen",
|
||||
ContextMenu_Amputate_Stitch_Bandage = "Amputieren, nähen und bandagieren",
|
||||
ContextMenu_Cauterize = "Kauterisieren",
|
||||
|
||||
ContextMenu_Limb_Hand_L = "Linke Hand",
|
||||
ContextMenu_Limb_ForeArm_L = "Linker Unterarm",
|
||||
ContextMenu_Limb_UpperArm_L = "Linker Oberarm"
|
||||
ContextMenu_Limb_Hand_R = "Rechte Hand",
|
||||
ContextMenu_Limb_ForeArm_R = "Rechter Unterarm",
|
||||
ContextMenu_Limb_UpperArm_R = "Rechter Oberarm",
|
||||
ContextMenu_InstallProstRight = "Instaliere Prothese am rechten Arm",
|
||||
ContextMenu_InstallProstLeft = "Instaliere Prothese am linken Arm",
|
||||
ContextMenu_PutTourniquetArmLeft = "Lege das Tourniquet am linken Arm an",
|
||||
ContextMenu_PutTourniquetLegL = "Lege das Tourniquet am linken Bein an",
|
||||
ContextMenu_PutTourniquetArmRight = "Lege das Tourniquet am rechten Arm an",
|
||||
ContextMenu_PutTourniquetLegR = "Lege das Tourniquet am rechten Bein an",
|
||||
ContextMenu_CleanWound = "Saubere Wunde",
|
||||
|
||||
}
|
||||
18
42/media/lua/shared/Translate/DE/IG_UI_DE.txt
Normal file
18
42/media/lua/shared/Translate/DE/IG_UI_DE.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
IG_UI_DE = {
|
||||
IGUI_Yes = "Ja",
|
||||
IGUI_No = "Nein",
|
||||
|
||||
IGUI_perks_Amputations = "Amputationen",
|
||||
IGUI_perks_Side_R = "Rechte Seite",
|
||||
IGUI_perks_Side_L = "Linke Seite",
|
||||
IGUI_perks_Prosthesis = "Prothese",
|
||||
IGUI_perks_ProstFamiliarity= "Vertrautheit",
|
||||
IGUI_ItemCat_Prosthesis = "Prothese",
|
||||
IGUI_ItemCat_Surgery = "Operation",
|
||||
IGUI_ItemCat_Amputation = "Amputation"
|
||||
IGUI_HealthPanel_Cicatrization = "Vernarbung",
|
||||
IGUI_HealthPanel_Cicatrized = "Vernarbt",
|
||||
IGUI_HealthPanel_Cauterized = "Kauterisiert",
|
||||
IGUI_HealthPanel_WoundDirtyness = "Wundverschmutzung",
|
||||
IGUI_HealthPanel_ProstEquipped = "Prothese angelegt",
|
||||
}
|
||||
9
42/media/lua/shared/Translate/DE/ItemName_DE.txt
Normal file
9
42/media/lua/shared/Translate/DE/ItemName_DE.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
ItemName_DE = {
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_L = "Tourniquet",
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_R = "Tourniquet",
|
||||
ItemName_TOC.Prost_NormalArm_L = "Armprothese Links",
|
||||
ItemName_TOC.Prost_NormalArm_R = "Armprothese Rechts",
|
||||
ItemName_TOC.Prost_HookArm_L = "Linke Armprothese - Haken",
|
||||
ItemName_TOC.Prost_HookArm_R = "Rechte Armprothese - Haken",
|
||||
}
|
||||
4
42/media/lua/shared/Translate/DE/Recipes_DE.txt
Normal file
4
42/media/lua/shared/Translate/DE/Recipes_DE.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Recipes_DE = {
|
||||
Recipe_Craft_Prosthetic_Arm = "Baue Armprothese",
|
||||
Recipe_Craft_Prosthetic_Hook = "Baue Hakenprothese",
|
||||
}
|
||||
6
42/media/lua/shared/Translate/DE/Sandbox_DE.txt
Normal file
6
42/media/lua/shared/Translate/DE/Sandbox_DE.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Sandbox_EN = {
|
||||
Sandbox_TOC = "The Only Cure - Die einzige Heilung",
|
||||
Sandbox_TOC_CicatrizationSpeed = "Vernarbungs Geschwindigkeit",
|
||||
Sandbox_TOC_WoundDirtynessMultiplier = "Wundenverschmutzung Multiplikator",
|
||||
Sandbox_TOC_SurgeonAbilityImportance = "Relevanz der Fähigkeiten des Chirurgen",
|
||||
}
|
||||
8
42/media/lua/shared/Translate/DE/Tooltip_DE.txt
Normal file
8
42/media/lua/shared/Translate/DE/Tooltip_DE.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Tooltip_DE = {
|
||||
Tooltip_Surgery_CantCauterize = "Du kannst die Wunde nicht kauterisieren",
|
||||
Tooltip_Surgery_And = " und "
|
||||
Tooltip_Surgery_TempTooLow = "Die Temperatur ist immer noch zu niedrig",
|
||||
Tooltip_Surgery_Coward = "Du hast nicht den Mut dazu",
|
||||
Tooltip_Surgery_LimbNotFree = "Zuerst musst du die Prothese abnehmen",
|
||||
|
||||
}
|
||||
11
42/media/lua/shared/Translate/DE/UI_DE.txt
Normal file
11
42/media/lua/shared/Translate/DE/UI_DE.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
UI_DE = {
|
||||
UI_trait_Amputee_Hand = "Amputierte linke Hand",
|
||||
UI_trait_Amputee_Hand_desc = "",
|
||||
UI_trait_Amputee_ForeArm = "Amputierter linker Unterarm",
|
||||
UI_trait_Amputee_ForeArm_desc = "",
|
||||
UI_trait_Amputee_UpperArm = "Amputierter linker Oberarm",
|
||||
UI_trait_Amputee_UpperArm_desc = "",
|
||||
UI_trait_Insensitive = "Unempfindlich",
|
||||
UI_trait_Insensitive_desc = "",
|
||||
UI_Say_CantEquip = "Ich kann das so nicht ausrüsten..."
|
||||
}
|
||||
33
42/media/lua/shared/Translate/EN/ContextMenu_EN.txt
Normal file
33
42/media/lua/shared/Translate/EN/ContextMenu_EN.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
ContextMenu_EN = {
|
||||
ContextMenu_Amputate = "Amputate",
|
||||
ContextMenu_Amputate_Bandage = "Amputate and bandage",
|
||||
ContextMenu_Amputate_Stitch = "Amputate and stitches",
|
||||
ContextMenu_Amputate_Stitch_Bandage = "Amputate, stitches and bandage",
|
||||
|
||||
ContextMenu_Cauterize = "Cauterize",
|
||||
|
||||
ContextMenu_Limb_Hand_L = "Left Hand",
|
||||
ContextMenu_Limb_ForeArm_L = "Left Forearm",
|
||||
ContextMenu_Limb_UpperArm_L = "Left UpperArm"
|
||||
ContextMenu_Limb_Hand_R = "Right Hand",
|
||||
ContextMenu_Limb_ForeArm_R = "Right Forearm",
|
||||
ContextMenu_Limb_UpperArm_R = "Right UpperArm",
|
||||
|
||||
ContextMenu_InstallProstRight = "Install prosthesis on right arm",
|
||||
ContextMenu_InstallProstLeft = "Install prosthesis on left arm",
|
||||
|
||||
ContextMenu_PutTourniquetArmLeft = "Put tourniquet on left arm",
|
||||
ContextMenu_PutTourniquetLegL = "Put tourniquet on left leg",
|
||||
ContextMenu_PutTourniquetArmRight = "Put tourniquet on right arm",
|
||||
ContextMenu_PutTourniquetLegR = "Put tourniquet on right leg",
|
||||
|
||||
|
||||
ContextMenu_CleanWound = "Clean Wound",
|
||||
|
||||
|
||||
|
||||
ContextMenu_Admin_TOC = "TOC",
|
||||
ContextMenu_Admin_ResetTOC = "Reset Amputations",
|
||||
ContextMenu_Admin_ForceAmputation = "Force Amputation",
|
||||
|
||||
}
|
||||
25
42/media/lua/shared/Translate/EN/IG_UI_EN.txt
Normal file
25
42/media/lua/shared/Translate/EN/IG_UI_EN.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
IG_UI_EN = {
|
||||
IGUI_Yes = "Yes",
|
||||
IGUI_No = "No",
|
||||
|
||||
IGUI_perks_Amputations = "Amputations",
|
||||
IGUI_perks_Side_R = "Right Side",
|
||||
IGUI_perks_Right Side_Description = "Familiarity with amputations on the right side of your body",
|
||||
IGUI_perks_Side_L = "Left Side",
|
||||
IGUI_perks_Left Side_Description = "Familiarity with amputations on the left side of your body",
|
||||
IGUI_perks_Prosthesis = "Prosthesis Familiarity",
|
||||
IGUI_perks_Prosthesis Familiarity_Description = "Familiarity with prosthetic limbs",
|
||||
|
||||
IGUI_ItemCat_Prosthesis = "Prosthesis",
|
||||
IGUI_ItemCat_Surgery = "Surgery",
|
||||
IGUI_ItemCat_Amputation = "Amputation"
|
||||
|
||||
IGUI_HealthPanel_Cicatrization = "Cicatrization",
|
||||
IGUI_HealthPanel_Cicatrized = "Cicatrized",
|
||||
IGUI_HealthPanel_Cauterized = "Cauterized",
|
||||
IGUI_HealthPanel_WoundDirtyness = "Wound Dirtyness",
|
||||
IGUI_HealthPanel_ProstEquipped = "Prosthesis Equipped",
|
||||
|
||||
IGUI_Confirmation_Amputate = " <CENTRE> Do you really want to amputate that limb?"
|
||||
|
||||
}
|
||||
11
42/media/lua/shared/Translate/EN/ItemName_EN.txt
Normal file
11
42/media/lua/shared/Translate/EN/ItemName_EN.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
ItemName_EN = {
|
||||
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_L = "Tourniquet",
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_R = "Tourniquet",
|
||||
|
||||
ItemName_TOC.Prost_NormalArm_L = "Prosthetic Arm",
|
||||
ItemName_TOC.Prost_NormalArm_R = "Prosthetic Arm",
|
||||
|
||||
ItemName_TOC.Prost_HookArm_L = "Prosthetic Arm - Hook",
|
||||
ItemName_TOC.Prost_HookArm_R = "Prosthetic Arm - Hook",
|
||||
}
|
||||
4
42/media/lua/shared/Translate/EN/Recipes_EN.txt
Normal file
4
42/media/lua/shared/Translate/EN/Recipes_EN.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Recipes_EN = {
|
||||
Recipe_Craft_Prosthetic_Arm = "Craft Prosthetic Arm",
|
||||
Recipe_Craft_Prosthetic_Hook = "Craft Prosthetic Hook",
|
||||
}
|
||||
10
42/media/lua/shared/Translate/EN/Sandbox_EN.txt
Normal file
10
42/media/lua/shared/Translate/EN/Sandbox_EN.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Sandbox_EN = {
|
||||
Sandbox_TOC = "The Only Cure",
|
||||
Sandbox_TOC_CicatrizationSpeed = "Cicatrization Speed",
|
||||
Sandbox_TOC_WoundDirtynessMultiplier = "Wound Dirtyness Multiplier",
|
||||
Sandbox_TOC_SurgeonAbilityImportance = "Relevance of surgeon doctor ability",
|
||||
Sandbox_TOC_EnableZombieAmputations = "Enable Zombie amputations",
|
||||
Sandbox_TOC_ZombieAmputationDamageThreshold = "Zombie amputations damage treshold",
|
||||
Sandbox_TOC_ZombieAmputationDamageChance = "Zombie amputations damage chance",
|
||||
|
||||
}
|
||||
10
42/media/lua/shared/Translate/EN/Tooltip_EN.txt
Normal file
10
42/media/lua/shared/Translate/EN/Tooltip_EN.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Tooltip_EN = {
|
||||
|
||||
Tooltip_Surgery_CantCauterize = "You can't cauterize the wound",
|
||||
|
||||
Tooltip_Surgery_And = " and "
|
||||
Tooltip_Surgery_TempTooLow = "The temperature is still too low",
|
||||
Tooltip_Surgery_Coward = "You don't have the guts to do it",
|
||||
Tooltip_Surgery_LimbNotFree = "You need to remove the prosthesis first",
|
||||
|
||||
}
|
||||
16
42/media/lua/shared/Translate/EN/UI_EN.txt
Normal file
16
42/media/lua/shared/Translate/EN/UI_EN.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
UI_EN = {
|
||||
UI_trait_Amputee_Hand = "Amputated Left Hand",
|
||||
UI_trait_Amputee_Hand_desc = "",
|
||||
|
||||
UI_trait_Amputee_ForeArm = "Amputated Left Forearm",
|
||||
UI_trait_Amputee_ForeArm_desc = "",
|
||||
|
||||
UI_trait_Amputee_UpperArm = "Amputated Left Upper arm",
|
||||
UI_trait_Amputee_UpperArm_desc = "",
|
||||
|
||||
UI_trait_Insensitive = "Insensitive",
|
||||
UI_trait_Insensitive_desc = "",
|
||||
|
||||
|
||||
UI_Say_CantEquip = "I can't equip it like this..."
|
||||
}
|
||||
29
42/media/lua/shared/Translate/FR/ContextMenu_FR.txt
Normal file
29
42/media/lua/shared/Translate/FR/ContextMenu_FR.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
ContextMenu_FR = {
|
||||
ContextMenu_Amputate = "Amputer",
|
||||
ContextMenu_Amputate_Bandage = "Amputer et bander",
|
||||
ContextMenu_Amputate_Stitch = "Amputer et suturer",
|
||||
ContextMenu_Amputate_Stitch_Bandage = "Amputer, suturer et bander",
|
||||
|
||||
ContextMenu_Cauterize = "Cautériser",
|
||||
|
||||
ContextMenu_Limb_Hand_L = "Main gauche",
|
||||
ContextMenu_Limb_ForeArm_L = "Avant-bras gauche",
|
||||
ContextMenu_Limb_UpperArm_L = "Bras supérieur gauche",
|
||||
ContextMenu_Limb_Hand_R = "Main droite",
|
||||
ContextMenu_Limb_ForeArm_R = "Avant-bras droit",
|
||||
ContextMenu_Limb_UpperArm_R = "Bras supérieur droit",
|
||||
|
||||
ContextMenu_InstallProstRight = "Installer une prothèse sur le bras droit",
|
||||
ContextMenu_InstallProstLeft = "Installer une prothèse sur le bras gauche",
|
||||
|
||||
ContextMenu_PutTourniquetArmLeft = "Mettre un garrot sur le bras gauche",
|
||||
ContextMenu_PutTourniquetLegL = "Mettre un garrot sur la jambe gauche",
|
||||
ContextMenu_PutTourniquetArmRight = "Mettre un garrot sur le bras droit",
|
||||
ContextMenu_PutTourniquetLegR = "Mettre un garrot sur la jambe droite",
|
||||
|
||||
ContextMenu_CleanWound = "Nettoyer la plaie",
|
||||
|
||||
ContextMenu_Admin_TOC = "TOC",
|
||||
ContextMenu_Admin_ResetTOC = "Réinitialiser les amputations",
|
||||
ContextMenu_Admin_ForceAmputation = "Forcer l'amputation",
|
||||
}
|
||||
21
42/media/lua/shared/Translate/FR/IG_UI_FR.txt
Normal file
21
42/media/lua/shared/Translate/FR/IG_UI_FR.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
IG_UI_FR = {
|
||||
IGUI_Yes = "Oui",
|
||||
IGUI_No = "Non",
|
||||
|
||||
IGUI_perks_Amputations = "Amputations",
|
||||
IGUI_perks_Side_R = "Côté droit",
|
||||
IGUI_perks_Side_L = "Côté gauche",
|
||||
IGUI_perks_Prosthesis = "Prothèse",
|
||||
IGUI_perks_ProstFamiliarity = "Familiarité",
|
||||
|
||||
IGUI_ItemCat_Prosthesis = "Prothèse",
|
||||
IGUI_ItemCat_Surgery = "Chirurgie",
|
||||
IGUI_ItemCat_Amputation = "Amputation",
|
||||
|
||||
IGUI_HealthPanel_Cicatrization = "Cicatrisation",
|
||||
IGUI_HealthPanel_Cicatrized = "Cicatrisé",
|
||||
IGUI_HealthPanel_Cauterized = "Cautérisé",
|
||||
IGUI_HealthPanel_WoundDirtyness = "Saleté de la plaie",
|
||||
IGUI_HealthPanel_ProstEquipped = "Prothèse équipée",
|
||||
|
||||
}
|
||||
11
42/media/lua/shared/Translate/FR/ItemName_FR.txt
Normal file
11
42/media/lua/shared/Translate/FR/ItemName_FR.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
ItemName_FR = {
|
||||
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_L = "Garrot",
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_R = "Garrot",
|
||||
|
||||
ItemName_TOC.Prost_NormalArm_L = "Bras prothétique",
|
||||
ItemName_TOC.Prost_NormalArm_R = "Bras prothétique",
|
||||
|
||||
ItemName_TOC.Prost_HookArm_L = "Bras prothétique - Crochet",
|
||||
ItemName_TOC.Prost_HookArm_R = "Bras prothétique - Crochet",
|
||||
}
|
||||
5
42/media/lua/shared/Translate/FR/Recipes_FR.txt
Normal file
5
42/media/lua/shared/Translate/FR/Recipes_FR.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Recipes_FR = {
|
||||
Recipe_Craft_Prosthetic_Arm = "Fabriquer un bras prothétique",
|
||||
Recipe_Craft_Prosthetic_Hook = "Fabriquer un crochet prothétique",
|
||||
|
||||
}
|
||||
10
42/media/lua/shared/Translate/FR/Sandbox_FR.txt
Normal file
10
42/media/lua/shared/Translate/FR/Sandbox_FR.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Sandbox_FR = {
|
||||
Sandbox_TOC = "Le Seul Remède",
|
||||
Sandbox_TOC_CicatrizationSpeed = "Vitesse de cicatrisation",
|
||||
Sandbox_TOC_WoundDirtynessMultiplier = "Multiplicateur de saleté de la plaie",
|
||||
Sandbox_TOC_SurgeonAbilityImportance = "Importance de la compétence du chirurgien",
|
||||
Sandbox_TOC_EnableZombieAmputations = "Activer les amputations de zombies",
|
||||
Sandbox_TOC_ZombieAmputationDamageThreshold = "Seuil de dégâts pour amputations de zombies",
|
||||
Sandbox_TOC_ZombieAmputationDamageChance = "Probabilité d'amputations de zombies",
|
||||
|
||||
}
|
||||
10
42/media/lua/shared/Translate/FR/Tooltip_FR.txt
Normal file
10
42/media/lua/shared/Translate/FR/Tooltip_FR.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Tooltip_FR = {
|
||||
|
||||
Tooltip_Surgery_CantCauterize = "Vous ne pouvez pas cautériser la plaie",
|
||||
|
||||
Tooltip_Surgery_And = " et ",
|
||||
Tooltip_Surgery_TempTooLow = "La température est encore trop basse",
|
||||
Tooltip_Surgery_Coward = "Vous n'avez pas le courage de le faire",
|
||||
Tooltip_Surgery_LimbNotFree = "Vous devez d'abord retirer la prothèse",
|
||||
|
||||
}
|
||||
16
42/media/lua/shared/Translate/FR/UI_FR.txt
Normal file
16
42/media/lua/shared/Translate/FR/UI_FR.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
UI_FR = {
|
||||
UI_trait_Amputee_Hand = "Main gauche amputée",
|
||||
UI_trait_Amputee_Hand_desc = "",
|
||||
|
||||
UI_trait_Amputee_ForeArm = "Avant-bras gauche amputé",
|
||||
UI_trait_Amputee_ForeArm_desc = "",
|
||||
|
||||
UI_trait_Amputee_UpperArm = "Bras supérieur gauche amputé",
|
||||
UI_trait_Amputee_UpperArm_desc = "",
|
||||
|
||||
UI_trait_Insensitive = "Insensible",
|
||||
UI_trait_Insensitive_desc = "",
|
||||
|
||||
UI_Say_CantEquip = "Je ne peux pas l'équiper comme ça..."
|
||||
|
||||
}
|
||||
33
42/media/lua/shared/Translate/IT/ContextMenu_IT.txt
Normal file
33
42/media/lua/shared/Translate/IT/ContextMenu_IT.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
ContextMenu_IT = {
|
||||
ContextMenu_Amputate = "Amputa",
|
||||
ContextMenu_Amputate_Bandage = "Amputa e fascia",
|
||||
ContextMenu_Amputate_Stitch = "Amputa e metti i punti",
|
||||
ContextMenu_Amputate_Stitch_Bandage = "Amputate, metti i punti e fascia",
|
||||
|
||||
ContextMenu_Cauterize = "Cauterizza",
|
||||
|
||||
ContextMenu_Limb_Hand_L = "Mano Sinistra",
|
||||
ContextMenu_Limb_ForeArm_L = "Avambraccio Sinistro",
|
||||
ContextMenu_Limb_UpperArm_L = "Braccio Superiore Sinistro",
|
||||
ContextMenu_Limb_Hand_R = "Mano Destra",
|
||||
ContextMenu_Limb_ForeArm_R = "Avambraccio Destro",
|
||||
ContextMenu_Limb_UpperArm_R = "Braccio Superiore Destro",
|
||||
|
||||
ContextMenu_InstallProstRight = "Installa protesi sul braccio destro",
|
||||
ContextMenu_InstallProstLeft = "Installa protesi sul braccio sinistro",
|
||||
|
||||
ContextMenu_PutTourniquetArmLeft = "Metti laccio emostatico sul braccio sinistro",
|
||||
ContextMenu_PutTourniquetLegL = "Metti laccio emostatico sulla gamba sinistra",
|
||||
ContextMenu_PutTourniquetArmRight = "Metti laccio emostatico sul braccio destro",
|
||||
ContextMenu_PutTourniquetLegR = "Metti laccio emostatico sulla gamba destra",
|
||||
|
||||
|
||||
ContextMenu_CleanWound = "Pulisci ferita",
|
||||
|
||||
|
||||
|
||||
ContextMenu_Admin_TOC = "TOC",
|
||||
ContextMenu_Admin_ResetTOC = "Reset Amputations",
|
||||
ContextMenu_Admin_ForceAmputation = "Force Amputation",
|
||||
|
||||
}
|
||||
21
42/media/lua/shared/Translate/IT/IG_UI_IT.txt
Normal file
21
42/media/lua/shared/Translate/IT/IG_UI_IT.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
IG_UI_IT = {
|
||||
IGUI_Yes = "Si",
|
||||
IGUI_No = "No",
|
||||
|
||||
IGUI_perks_Amputations = "Amputazioni",
|
||||
IGUI_perks_Side_R = "Parte destra",
|
||||
IGUI_perks_Side_L = "Parte sinistra",
|
||||
IGUI_perks_Prosthesis = "Protesi",
|
||||
IGUI_perks_ProstFamiliarity= "Familiarità",
|
||||
|
||||
IGUI_ItemCat_Prosthesis = "Protesi",
|
||||
IGUI_ItemCat_Surgery = "Operazioni mediche",
|
||||
IGUI_ItemCat_Amputation = "Amputazione"
|
||||
|
||||
IGUI_HealthPanel_Cicatrization = "Cicatrizzazione",
|
||||
IGUI_HealthPanel_Cicatrized = "Cicatrizzata",
|
||||
IGUI_HealthPanel_Cauterized = "Cauterizzata",
|
||||
IGUI_HealthPanel_WoundDirtyness = "Sporcizia della ferita",
|
||||
IGUI_HealthPanel_ProstEquipped = "Protesi installata",
|
||||
|
||||
}
|
||||
11
42/media/lua/shared/Translate/IT/ItemName_IT.txt
Normal file
11
42/media/lua/shared/Translate/IT/ItemName_IT.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
ItemName_IT = {
|
||||
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_L = "Laccio emostatico",
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_R = "Laccio emostatico",
|
||||
|
||||
ItemName_TOC.Prost_NormalArm_L = "Braccio Prostetico",
|
||||
ItemName_TOC.Prost_NormalArm_R = "Braccio Prostetico",
|
||||
|
||||
ItemName_TOC.Prost_HookArm_L = "Braccio prostetico - Uncino",
|
||||
ItemName_TOC.Prost_HookArm_R = "Braccio prostetico - Uncino",
|
||||
}
|
||||
4
42/media/lua/shared/Translate/IT/Recipes_IT.txt
Normal file
4
42/media/lua/shared/Translate/IT/Recipes_IT.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Recipes_IT = {
|
||||
Recipe_Craft_Prosthetic_Arm = "Costruisci un braccio prostetico",
|
||||
Recipe_Craft_Prosthetic_Hook = "Costruisci un braccio prostetico con uncino",
|
||||
}
|
||||
7
42/media/lua/shared/Translate/IT/Sandbox_IT.txt
Normal file
7
42/media/lua/shared/Translate/IT/Sandbox_IT.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Sandbox_IT = {
|
||||
Sandbox_TOC = "The Only Cure",
|
||||
Sandbox_TOC_CicatrizationSpeed = "Velocità cicatrizzazione",
|
||||
Sandbox_TOC_WoundDirtynessMultiplier = "Moltiplicatore sporcizia ferita",
|
||||
Sandbox_TOC_SurgeonAbilityImportance = "Importanza abilità medico",
|
||||
|
||||
}
|
||||
10
42/media/lua/shared/Translate/IT/Tooltip_IT.txt
Normal file
10
42/media/lua/shared/Translate/IT/Tooltip_IT.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Tooltip_IT = {
|
||||
|
||||
Tooltip_Surgery_CantCauterize = "Non puoi cauterizzare la ferita",
|
||||
|
||||
Tooltip_Surgery_And = " e "
|
||||
Tooltip_Surgery_TempTooLow = "La temperatura è troppo bassa",
|
||||
Tooltip_Surgery_Coward = "Non sei abbastanza coraggioso",
|
||||
Tooltip_Surgery_LimbNotFree = "Devi rimuovere la protesi",
|
||||
|
||||
}
|
||||
16
42/media/lua/shared/Translate/IT/UI_IT.txt
Normal file
16
42/media/lua/shared/Translate/IT/UI_IT.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
UI_IT = {
|
||||
UI_trait_Amputee_Hand = "Mano Sinistra Amputata",
|
||||
UI_trait_Amputee_Hand_desc = "",
|
||||
|
||||
UI_trait_Amputee_ForeArm = "Avambraccio Sinistro Amputato",
|
||||
UI_trait_Amputee_ForeArm_desc = "",
|
||||
|
||||
UI_trait_Amputee_UpperArm = "Parte superiore del Braccio Sinistro Amputato",
|
||||
UI_trait_Amputee_UpperArm_desc = "",
|
||||
|
||||
UI_trait_Insensitive = "Insensibile",
|
||||
UI_trait_Insensitive_desc = "",
|
||||
|
||||
|
||||
UI_Say_CantEquip = "Non posso equipaggiarlo..."
|
||||
}
|
||||
BIN
42/media/lua/shared/Translate/KO/ContextMenu_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/ContextMenu_KO.txt
Normal file
Binary file not shown.
BIN
42/media/lua/shared/Translate/KO/IG_UI_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/IG_UI_KO.txt
Normal file
Binary file not shown.
BIN
42/media/lua/shared/Translate/KO/ItemName_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/ItemName_KO.txt
Normal file
Binary file not shown.
BIN
42/media/lua/shared/Translate/KO/Recipes_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/Recipes_KO.txt
Normal file
Binary file not shown.
BIN
42/media/lua/shared/Translate/KO/Sandbox_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/Sandbox_KO.txt
Normal file
Binary file not shown.
BIN
42/media/lua/shared/Translate/KO/Tooltip_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/Tooltip_KO.txt
Normal file
Binary file not shown.
BIN
42/media/lua/shared/Translate/KO/UI_KO.txt
Normal file
BIN
42/media/lua/shared/Translate/KO/UI_KO.txt
Normal file
Binary file not shown.
33
42/media/lua/shared/Translate/RU/ContextMenu_RU.txt
Normal file
33
42/media/lua/shared/Translate/RU/ContextMenu_RU.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
ContextMenu_RU = {
|
||||
ContextMenu_Amputate = "Ампутировать",
|
||||
ContextMenu_Amputate_Bandage = "Ампутировать и перевязать",
|
||||
ContextMenu_Amputate_Stitch = "Ампутировать и наложить швы",
|
||||
ContextMenu_Amputate_Stitch_Bandage = "Ампутировать, наложить швы и перевязать",
|
||||
|
||||
ContextMenu_Cauterize = "Прижечь",
|
||||
|
||||
ContextMenu_Limb_Hand_L = "Левая рука",
|
||||
ContextMenu_Limb_ForeArm_L = "Левая предплечье",
|
||||
ContextMenu_Limb_UpperArm_L = "Левое плечо"
|
||||
ContextMenu_Limb_Hand_R = "Правая рука",
|
||||
ContextMenu_Limb_ForeArm_R = "Правая предплечье",
|
||||
ContextMenu_Limb_UpperArm_R = "Правая плечо",
|
||||
|
||||
ContextMenu_InstallProstRight = "Установить протез на правую руку",
|
||||
ContextMenu_InstallProstLeft = "Установить протез на левую руку",
|
||||
|
||||
ContextMenu_PutTourniquetArmLeft = "Наложить жгут на левую руку",
|
||||
ContextMenu_PutTourniquetLegL = "Наложить жгут на левую ногу",
|
||||
ContextMenu_PutTourniquetArmRight = "Наложить жгут на правую руку",
|
||||
ContextMenu_PutTourniquetLegR = "Наложить жгут на правую ногу",
|
||||
|
||||
|
||||
ContextMenu_CleanWound = "Очистить рану",
|
||||
|
||||
|
||||
|
||||
ContextMenu_Admin_TOC = "TOC",
|
||||
ContextMenu_Admin_ResetTOC = "Сбросить ампутации",
|
||||
ContextMenu_Admin_ForceAmputation = "Моментально ампутировать",
|
||||
|
||||
}
|
||||
18
42/media/lua/shared/Translate/RU/IG_UI_RU.txt
Normal file
18
42/media/lua/shared/Translate/RU/IG_UI_RU.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
IG_UI_RU = {
|
||||
IGUI_perks_Amputations = "Ампутации",
|
||||
IGUI_perks_Side_R = "Правая сторона",
|
||||
IGUI_perks_Side_L = "Левая сторона",
|
||||
IGUI_perks_Prosthesis = "Протез",
|
||||
IGUI_perks_ProstFamiliarity= "Приспособленность",
|
||||
|
||||
IGUI_ItemCat_Prosthesis = "Протез",
|
||||
IGUI_ItemCat_Surgery = "Хирургия",
|
||||
IGUI_ItemCat_Amputation = "Ампутация"
|
||||
|
||||
IGUI_HealthPanel_Cicatrization = "Заживление",
|
||||
IGUI_HealthPanel_Cicatrized = "Заживлено",
|
||||
IGUI_HealthPanel_Cauterized = "Прижженно",
|
||||
IGUI_HealthPanel_WoundDirtyness = "Загрезнённая рана",
|
||||
IGUI_HealthPanel_ProstEquipped = "Протез экипирован",
|
||||
|
||||
}
|
||||
11
42/media/lua/shared/Translate/RU/ItemName_RU.txt
Normal file
11
42/media/lua/shared/Translate/RU/ItemName_RU.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
ItemName_RU = {
|
||||
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_L = "Жгут",
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_R = "Жгут",
|
||||
|
||||
ItemName_TOC.Prost_NormalArm_L = "Протез руки",
|
||||
ItemName_TOC.Prost_NormalArm_R = "Протез руки",
|
||||
|
||||
ItemName_TOC.Prost_HookArm_L = "Протез руки - Крюк",
|
||||
ItemName_TOC.Prost_HookArm_R = "Протез руки - Крюк",
|
||||
}
|
||||
4
42/media/lua/shared/Translate/RU/Recipes_RU.txt
Normal file
4
42/media/lua/shared/Translate/RU/Recipes_RU.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Recipes_RU = {
|
||||
Recipe_Craft_Prosthetic_Arm = "Изготовить протез руки",
|
||||
Recipe_Craft_Prosthetic_Hook = "Изготовить протез ввиде крючка",
|
||||
}
|
||||
7
42/media/lua/shared/Translate/RU/Sandbox_RU.txt
Normal file
7
42/media/lua/shared/Translate/RU/Sandbox_RU.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Sandbox_RU = {
|
||||
Sandbox_TOC = "Спасенье в Отсечении",
|
||||
Sandbox_TOC_CicatrizationSpeed = "Скорость заживления",
|
||||
Sandbox_TOC_WoundDirtynessMultiplier = "Множитель загрязнения ран",
|
||||
Sandbox_TOC_SurgeonAbilityImportance = "Значимость способностей врача-хирурга",
|
||||
|
||||
}
|
||||
10
42/media/lua/shared/Translate/RU/Tooltip_RU.txt
Normal file
10
42/media/lua/shared/Translate/RU/Tooltip_RU.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Tooltip_RU = {
|
||||
|
||||
Tooltip_Surgery_CantCauterize = "Нельзя прижигать рану",
|
||||
|
||||
Tooltip_Surgery_And = " и "
|
||||
Tooltip_Surgery_TempTooLow = "Температура все еще слишком низкая",
|
||||
Tooltip_Surgery_Coward = "У тебя не хватит смелости сделать это",
|
||||
Tooltip_Surgery_LimbNotFree = "Сначала нужно снять протез",
|
||||
|
||||
}
|
||||
16
42/media/lua/shared/Translate/RU/UI_RU.txt
Normal file
16
42/media/lua/shared/Translate/RU/UI_RU.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
UI_RU = {
|
||||
UI_trait_Amputee_Hand = "Ампутированная левая рука",
|
||||
UI_trait_Amputee_Hand_desc = "Вы начинаете с ампутированной левой рукой.",
|
||||
|
||||
UI_trait_Amputee_ForeArm = "Ампутированное левое предплечье",
|
||||
UI_trait_Amputee_ForeArm_desc = "Вы начинаете с ампутированным левым предплечьем.",
|
||||
|
||||
UI_trait_Amputee_UpperArm = "Ампутированное левое плечо",
|
||||
UI_trait_Amputee_UpperArm_desc = "Вы начинаете с ампутированнвм левым плечём.",
|
||||
|
||||
UI_trait_Insensitive = "Нечувствительный",
|
||||
UI_trait_Insensitive_desc = "",
|
||||
|
||||
|
||||
UI_Say_CantEquip = "Я не могу его так экипировать..."
|
||||
}
|
||||
31
42/media/lua/shared/Translate/TR/ContextMenu_TR.txt
Normal file
31
42/media/lua/shared/Translate/TR/ContextMenu_TR.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
ContextMenu_TR = {
|
||||
ContextMenu_Amputate = "Ampute Et",
|
||||
ContextMenu_Amputate_Bandage = "Ampute Et ve Bandajla",
|
||||
ContextMenu_Amputate_Stitch = "Ampute Et ve Dikiþ At",
|
||||
ContextMenu_Amputate_Stitch_Bandage = "Ampute Et, Dikiþ At ve Bandajla",
|
||||
|
||||
ContextMenu_Cauterize = "Daðla",
|
||||
|
||||
ContextMenu_Limb_Hand_L = "Sol El",
|
||||
ContextMenu_Limb_ForeArm_L = "Sol Ön Kol",
|
||||
ContextMenu_Limb_UpperArm_L = "Sol Üst Kol",
|
||||
ContextMenu_Limb_Hand_R = "Sað El",
|
||||
ContextMenu_Limb_ForeArm_R = "Sað Ön Kol",
|
||||
ContextMenu_Limb_UpperArm_R = "Sað Üst Kol",
|
||||
|
||||
ContextMenu_InstallProstRight = "Sað kola protez tak",
|
||||
ContextMenu_InstallProstLeft = "Sol kola protez tak",
|
||||
|
||||
ContextMenu_PutTourniquetArmLeft = "Sol kola turnike tak",
|
||||
ContextMenu_PutTourniquetLegL = "Sol bacaðýna turnike tak",
|
||||
ContextMenu_PutTourniquetArmRight = "Sað kola turnike tak",
|
||||
ContextMenu_PutTourniquetLegR = "Sað bacaðýna turnike tak",
|
||||
|
||||
|
||||
ContextMenu_CleanWound = "Yarayý Temizle",
|
||||
|
||||
|
||||
ContextMenu_Admin_TOC = "TOC",
|
||||
ContextMenu_Admin_ResetTOC = "Amputasyonlarý Sýfýrla",
|
||||
ContextMenu_Admin_ForceAmputation = "Zorla Amputasyon Yap",
|
||||
}
|
||||
19
42/media/lua/shared/Translate/TR/IG_UI_TR.txt
Normal file
19
42/media/lua/shared/Translate/TR/IG_UI_TR.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
IG_UI_TR = {
|
||||
IGUI_perks_Amputations = "Amputasyonlar",
|
||||
IGUI_perks_Side_R = "Sağ Taraf",
|
||||
IGUI_perks_Side_L = "Sol Taraf",
|
||||
IGUI_perks_Prosthesis = "Protez",
|
||||
IGUI_perks_ProstFamiliarity = "Aşinalık",
|
||||
|
||||
IGUI_ItemCat_Prosthesis = "Protez",
|
||||
IGUI_ItemCat_Surgery = "Cerrahi",
|
||||
IGUI_ItemCat_Amputation = "Amputasyon",
|
||||
|
||||
IGUI_HealthPanel_Cicatrization = "Yara İyileşmesi",
|
||||
IGUI_HealthPanel_Cicatrized = "İyileşti",
|
||||
IGUI_HealthPanel_Cauterized = "Dağlandı",
|
||||
IGUI_HealthPanel_WoundDirtyness = "Yara Kirliliği",
|
||||
IGUI_HealthPanel_ProstEquipped = "Protez Takılı",
|
||||
|
||||
IGUI_Confirmation_Amputate = " <CENTRE> Bu uzvu gerçekten ampute etmek istiyor musunuz?"
|
||||
}
|
||||
11
42/media/lua/shared/Translate/TR/ItemName_TR.txt
Normal file
11
42/media/lua/shared/Translate/TR/ItemName_TR.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
ItemName_TR = {
|
||||
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_L = "Turnike",
|
||||
ItemName_TOC.Surg_Arm_Tourniquet_R = "Turnike",
|
||||
|
||||
ItemName_TOC.Prost_NormalArm_L = "Protez Kol",
|
||||
ItemName_TOC.Prost_NormalArm_R = "Protez Kol",
|
||||
|
||||
ItemName_TOC.Prost_HookArm_L = "Protez Kol - Kanca",
|
||||
ItemName_TOC.Prost_HookArm_R = "Protez Kol - Kanca",
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user