diff --git a/Assemblies/CombatExtended.dll b/Assemblies/CombatExtended.dll
index f7d87cf991..95ecd3fd82 100644
Binary files a/Assemblies/CombatExtended.dll and b/Assemblies/CombatExtended.dll differ
diff --git a/Defs/JobDefs/Jobs_CE.xml b/Defs/JobDefs/Jobs_CE.xml
index ef7ce8a352..d3f3408262 100644
--- a/Defs/JobDefs/Jobs_CE.xml
+++ b/Defs/JobDefs/Jobs_CE.xml
@@ -33,6 +33,17 @@
truefalse
+
+
+ WaitKnockdown
+ CombatExtended.JobDriver_WaitKnockdown
+ Knocked down.
+ false
+ false
+ true
+ false
+ Never
+ ReloadTurret
diff --git a/Defs/Stats/Stats_Pawns_Combat.xml b/Defs/Stats/Stats_Pawns_Combat.xml
index 143e4e074f..8ea2147190 100644
--- a/Defs/Stats/Stats_Pawns_Combat.xml
+++ b/Defs/Stats/Stats_Pawns_Combat.xml
@@ -97,40 +97,20 @@
MeleeCritChance
-
- Base chance to critically hit a target in melee.
+
+ Base chance to critically hit a target in melee.\n\nThe final chance depends on the opponent's critical skill and equal opponents will always have a 10% chance to crit.PawnCombat
- 0
- 0.25
+ 99
+ 1true0.0
+ 3.2PercentZero
-
+
Melee
-
-
0.20
-
0.5
-
0.80
-
0.9
-
1.00
-
1.1
-
1.20
-
1.266
-
1.332
-
1.4
-
1.466
-
1.532
-
1.6
-
1.65
-
1.7
-
1.75
-
1.8
-
1.84
-
1.88
-
1.92
-
1.96
-
+ 0.1
+ 0.01
@@ -140,103 +120,82 @@
Sight
- 0.4
+ 0.7
+ 1
+
+
+ Manipulation
+ 1
+
+
+
(0.0, 0.0)
+
(0.3, 0.3)
+
(0.6, 0.45)
+
(1.2, 0.6)
+
(2.4, 0.75)
+
(3.2, 0.8)
+
+
-
MeleeParryChance
-
- Base chance to parry a melee attack.
+
+ Base chance to parry a melee attack. When a parry is performed the equipped weapon or shield will take damage instead of the wielder. If the parrying pawn passes a critical chance check they will automatically riposte their attacker.\n\nThe final chance depends on the opponent's parry skill and equal opponents will always have a 20% chance to crit.PawnCombat
- 0
- 0.25
+ 99
+ 1true0.0
+ 3.2PercentZero
+ 0
-
+
Melee
-
-
0.20
-
0.5
-
0.80
-
0.9
-
1.00
-
1.1
-
1.20
-
1.266
-
1.332
-
1.4
-
1.466
-
1.532
-
1.6
-
1.65
-
1.7
-
1.75
-
1.8
-
1.84
-
1.88
-
1.92
-
1.96
-
+ 0.2
+ 0.005
@@ -246,9 +205,24 @@
Sight
- 0.4
+ 0.7
+ 1
+
+
+ Manipulation
+ 1
+
+
+
(0.0, 0.0)
+
(0.3, 0.3)
+
(0.6, 0.45)
+
(1.2, 0.6)
+
(2.4, 0.75)
+
(3.2, 0.8)
+
+
diff --git a/Defs/ThingDefs_Misc/Apparel_Shield.xml b/Defs/ThingDefs_Misc/Apparel_Shield.xml
index adf87540aa..3fa7b89c66 100644
--- a/Defs/ThingDefs_Misc/Apparel_Shield.xml
+++ b/Defs/ThingDefs_Misc/Apparel_Shield.xml
@@ -56,6 +56,8 @@
-0.05-0.05-0.25
+ -0.05
+ 1.0
@@ -103,6 +105,8 @@
-0.2-0.2-0.5
+ -0.2
+ 1.0
diff --git a/Defs/Tutor/Concepts_NotedOpportunistic.xml b/Defs/Tutor/Concepts_NotedOpportunistic.xml
index c94cdc3aa9..a0fa52c577 100644
--- a/Defs/Tutor/Concepts_NotedOpportunistic.xml
+++ b/Defs/Tutor/Concepts_NotedOpportunistic.xml
@@ -91,7 +91,7 @@
50True
- Combat Extended replaces the vanilla percentage-based aiming system with a new physics-based system. Projectiles follow a ballistic flight path and use hitboxes for collision detection. Several factors determine how close a bullet will fly near it's target:\n\n-Visibility: Darkness and bad weather make it harder to see the target. Randomly shifts point of aim in circle around the target.\n-Movement: A shooter has to lead a moving target. Lead error means the shooter might aim too far forward or back in the direction of movement. Influenced by shooter's aiming accuracy.\n-Range: A shooter needs to correctly estimate how far away the target is. Range error means the shooter will aim as if the target was x cells closer/further than it actually is. Influenced by shooter's aiming accuracy.\n-Sway: Weapons will sway in the hands of the shooter. Heavier and one-handed weapons sway more than others. Influenced by shooter's weapon handling, weapon's sway stat. Reduced by aimed shot mode.\n-Recoil: Every shot adds to the recoil penalty, making successive burst shots less accurate. Influenced by weapon's recoil factor, shooter's weapon handling.\n-Weapon spread: Bullets randomly deviate in a cone (e.g. shotgun pellets). Influenced by weapon's shot spread, projectile's spread modifier.\n-Cover height: Cover obscures parts of the target's hitbox and reduces the hittable area. It can completely block line of sight for smaller targets (e.g. squirrels behind sandbags).\n-Body size: Larger targets have larger hitboxes.\n-Stance: Downed or hunkering pawns are harder to hit.\n\nYou can get a detailed breakdown by selecting a shooter and hovering the mouse over a target. Given measurements are the maximum deviation in cells/degrees and target/cover hitbox dimensions in cells.
+ Combat Extended uses a new physics-based projectile system. Projectiles follow a ballistic flight path and use hitboxes for collision detection. Several factors determine how close a bullet will fly near it's target:\n\n-Visibility: Darkness, bad weather and smoke make it harder to see the target.\n-Movement: shooter has to lead a moving target. Lead error means the shooter might aim too far forward or back in the direction of movement.\n-Range: shooter needs to correctly estimate how far away the target is. Range error means the shooter will aim as if target was x cells closer/further than it actually is.\n-Sway: Weapons will sway in the hands of the shooter. Reduced by aimed shot mode (reduction depends on skill and sights efficiency).\n-Recoil: Shots within a burst gradually become less accurate\n-Weapon spread: Bullets randomly deviate in a cone (e.g. shotgun pellets).\n-Cover height: Cover obscures parts of the target's hitbox. Can block line of sight for smaller targets (e.g. squirrels behind sandbags).\n-Body size\n-Stance: Downed or hunkering pawns are harder to hit.\n\nYou can get a detailed breakdown by selecting a shooter and hovering the mouse over a target. Given measurements are the maximum deviation in cells/degrees and target/cover hitbox dimensions in cells.
diff --git a/Patches/Core/ThingDefs_Misc/Weapons_Melee.xml b/Patches/Core/ThingDefs_Misc/Weapons_Melee.xml
index 5e898d5b6c..21e30738ee 100644
--- a/Patches/Core/ThingDefs_Misc/Weapons_Melee.xml
+++ b/Patches/Core/ThingDefs_Misc/Weapons_Melee.xml
@@ -36,6 +36,16 @@
+
+ */ThingDef[defName="MeleeWeapon_Shiv"]
+
+
+ 0.1
+ 0.1
+
+
+
+
*/ThingDef[defName="MeleeWeapon_Shiv"]/verbs
@@ -101,6 +111,16 @@
+
+ */ThingDef[defName="MeleeWeapon_Knife"]
+
+
+ 0.25
+ 0.25
+
+
+
+
*/ThingDef[defName="MeleeWeapon_Knife"]/verbs
@@ -166,6 +186,16 @@
+
+ */ThingDef[defName="MeleeWeapon_Club"]
+
+
+ 0.5
+ 0.25
+
+
+
+
*/ThingDef[defName="MeleeWeapon_Club"]/verbs
@@ -231,6 +261,16 @@
+
+ */ThingDef[defName="MeleeWeapon_Mace"]
+
+
+ 0.65
+ 0.4
+
+
+
+
*/ThingDef[defName="MeleeWeapon_Mace"]/verbs
@@ -295,6 +335,16 @@
+
+ */ThingDef[defName="MeleeWeapon_Gladius"]
+
+
+ 0.5
+ 0.65
+
+
+
+
*/ThingDef[defName="MeleeWeapon_Gladius"]/verbs
@@ -359,6 +409,17 @@
+
+ */ThingDef[defName="MeleeWeapon_Spear"]
+
+
+ 0.5
+ 0.5
+ 0.25
+
+
+
+
*/ThingDef[defName="MeleeWeapon_Spear"]/verbs
@@ -390,6 +451,16 @@
+
+ */ThingDef[defName="MeleeWeapon_LongSword"]
+
+
+ 1
+ 0.75
+
+
+
+
*/ThingDef[defName="MeleeWeapon_LongSword"]/statBases
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Arid.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Arid.xml
index 8cd7c736ba..ed2665a434 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Arid.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Arid.xml
@@ -7,6 +7,8 @@
*/ThingDef[defName="Muffalo"]/statBases/MoveSpeed5
+ 0.12
+ 0.27
@@ -48,6 +50,8 @@
*/ThingDef[defName="Gazelle"]/statBases/MoveSpeed6.2
+ 0.28
+ 0.10
@@ -100,6 +104,14 @@
+
+ */ThingDef[defName="Iguana"]/statBases
+
+ 0.23
+ 0.02
+
+
+
*/ThingDef[defName="Iguana"]/verbs
@@ -161,12 +173,8 @@
*/ThingDef[defName="Rhinoceros"]/statBases/MoveSpeed5.5
-
-
-
-
- */ThingDef[defName="Rhinoceros"]/statBases
-
+ 0.08
+ 0.520.130.15
@@ -236,6 +244,14 @@
+
+ */ThingDef[defName="Dromedary"]/statBases
+
+ 0.07
+ 0.13
+
+
+
*/ThingDef[defName="Dromedary"]/verbs
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Bears.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Bears.xml
index 2749e8058d..15cb9aea92 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Bears.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Bears.xml
@@ -24,6 +24,8 @@
0.130.15
+ 0.17
+ 0.19
@@ -103,6 +105,8 @@
*/ThingDef[defName="PolarBear"]/statBases4.0
+ 0.09
+ 0.18
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_BigCat.xml b/Patches/Core/ThingDefs_Races/Races_Animal_BigCat.xml
index ef6599d367..4e6ed780da 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_BigCat.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_BigCat.xml
@@ -12,6 +12,14 @@
+
+ */ThingDef[@Name="BigCatThingBase"]/statBases
+
+ 0.34
+ 0.12
+
+
+
*/ThingDef[@Name="BigCatThingBase"]/verbs
@@ -95,6 +103,14 @@
+
+ */ThingDef[defName="Lynx"]/statBases
+
+ 0.52
+ 0.07
+
+
+
*/ThingDef[defName="Lynx"]/verbs
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Birds.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Birds.xml
index 64e4039de1..49604152c5 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Birds.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Birds.xml
@@ -18,6 +18,8 @@
*/ThingDef[defName="Cassowary"]/statBases/MoveSpeed5
+ 0.24
+ 0.09
@@ -82,6 +84,8 @@
*/ThingDef[defName="Emu"]/statBases/MoveSpeed4.8
+ 0.32
+ 0.06
@@ -142,6 +146,14 @@
+
+ */ThingDef[defName="Ostrich"]/statBases
+
+ 0.25
+ 0.16
+
+
+
*/ThingDef[defName="Ostrich"]/verbs
@@ -199,6 +211,14 @@
+
+ */ThingDef[defName="Turkey"]/statBases
+
+ 0.44
+ 0.02
+
+
+
*/ThingDef[defName="Turkey"]/verbs
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Farm.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Farm.xml
index e8edcac1ef..af6bee1f83 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Farm.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Farm.xml
@@ -3,6 +3,14 @@
+
+ */ThingDef[defName="Chicken"]/statBases
+
+ 0.42
+ 0.0
+
+
+
*/ThingDef[defName="Chicken"]/verbs
@@ -48,6 +56,8 @@
*/ThingDef[defName="Pig"]/statBases/MoveSpeed2.6
+ 0.07
+ 0.06
@@ -85,6 +95,14 @@
+
+ */ThingDef[defName="Cow"]/statBases
+
+ 0.08
+ 0.13
+
+
+
*/ThingDef[defName="Cow"]/verbs
@@ -119,6 +137,14 @@
+
+ */ThingDef[defName="Alpaca"]/statBases
+
+ 0.2
+ 0.06
+
+
+
*/ThingDef[defName="Alpaca"]/verbs
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Giant.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Giant.xml
index 67ef34ec81..5e4a493920 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Giant.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Giant.xml
@@ -7,14 +7,16 @@
*/ThingDef[defName="Elephant"]/statBases/MoveSpeed5
+ 0.06
+ 0.79
+ 0.10
+ 0.125*/ThingDef[defName="Elephant"]/statBases
- 0.10
- 0.125
@@ -48,6 +50,8 @@
*/ThingDef[defName="Megasloth"]/statBases
+ 0.04
+ 0.410.100.125
@@ -91,6 +95,8 @@
*/ThingDef[defName="Thrumbo"]/statBases
+ 0.06
+ 0.760.20.3
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Hares.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Hares.xml
index f46868db62..4e5e9c72e8 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Hares.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Hares.xml
@@ -7,6 +7,8 @@
*/ThingDef[@Name="BaseHare"]/statBases/MoveSpeed4.8
+ 0.5
+ 0.02
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Insect.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Insect.xml
index 483ed205bd..18b8983a41 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Insect.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Insect.xml
@@ -18,6 +18,8 @@
*/ThingDef[defName="Megascarab"]/statBases/MoveSpeed3.7
+ 0.21
+ 0.02
@@ -64,6 +66,8 @@
*/ThingDef[defName="Spelopede"]/statBases/MoveSpeed3.7
+ 0.08
+ 0.12
@@ -110,6 +114,8 @@
*/ThingDef[defName="Megaspider"]/statBases/MoveSpeed4
+ 0.06
+ 0.25
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Pet.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Pet.xml
index 39f8187098..3052d684d4 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Pet.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Pet.xml
@@ -3,6 +3,14 @@
+
+ */ThingDef[defName="YorkshireTerrier"]/statBases
+
+ 0.39
+ 0.01
+
+
+
*/ThingDef[defName="YorkshireTerrier"]/verbs
@@ -53,6 +61,14 @@
+
+ */ThingDef[defName="Husky"]/statBases
+
+ 0.37
+ 0.05
+
+
+
*/ThingDef[defName="Husky"]/verbs
@@ -110,6 +126,14 @@
+
+ */ThingDef[defName="LabradorRetriever"]/statBases
+
+ 0.29
+ 0.06
+
+
+
*/ThingDef[defName="LabradorRetriever"]/verbs
@@ -167,6 +191,14 @@
+
+ */ThingDef[defName="Cat"]/statBases
+
+ 0.45
+ 0.02
+
+
+
*/ThingDef[defName="Cat"]/verbs
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Rodentlike.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Rodentlike.xml
index db5acb7fec..cf9fb88c1d 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Rodentlike.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Rodentlike.xml
@@ -16,6 +16,8 @@
*/ThingDef[defName="Squirrel"]/statBases/MoveSpeed2.4
+ 0.53
+ 0.0
@@ -73,6 +75,8 @@
*/ThingDef[defName="Alphabeaver"]/statBases/MoveSpeed5
+ 0.15
+ 0.05
@@ -119,6 +123,14 @@
+
+ */ThingDef[defName="Capybara"]/statBases
+
+ 0.17
+ 0.05
+
+
+
*/ThingDef[defName="Capybara"]/verbs
@@ -173,6 +185,8 @@
*/ThingDef[defName="Chinchilla"]/statBases/MoveSpeed2.84
+ 0.74
+ 0.0
@@ -234,6 +248,8 @@
*/ThingDef[defName="Boomrat"]/statBases/MoveSpeed3.0
+ 0.54
+ 0.01
@@ -320,6 +336,8 @@
*/ThingDef[defName="Raccoon"]/statBases/MoveSpeed3
+ 0.32
+ 0.01
@@ -384,6 +402,8 @@
*/ThingDef[defName="Rat"]/statBases/MoveSpeed2.3
+ 0.58
+ 0.0
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Temperate.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Temperate.xml
index a8bfc473a2..4481bd1aec 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Temperate.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Temperate.xml
@@ -16,6 +16,8 @@
*/ThingDef[defName="Deer"]/statBases/MoveSpeed7
+ 0.39
+ 0.14
@@ -82,6 +84,8 @@
*/ThingDef[defName="Ibex"]/statBases/MoveSpeed4.4
+ 0.20
+ 0.08
@@ -148,6 +152,8 @@
*/ThingDef[defName="Elk"]/statBases/MoveSpeed7.24
+ 0.23
+ 0.34
@@ -214,6 +220,8 @@
*/ThingDef[defName="Caribou"]/statBases/MoveSpeed7.84
+ 0.43
+ 0.22
@@ -280,6 +288,8 @@
*/ThingDef[defName="WildBoar"]/statBases/MoveSpeed4.0
+ 0.16
+ 0.08
@@ -327,7 +337,9 @@
*/ThingDef[defName="Tortoise"]/statBases/MoveSpeed
- 4.0
+ 1.0
+ 0.02
+ 0.01
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_Tropical.xml b/Patches/Core/ThingDefs_Races/Races_Animal_Tropical.xml
index bcb1789961..7852f6e534 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_Tropical.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_Tropical.xml
@@ -16,6 +16,8 @@
*/ThingDef[defName="Cobra"]/statBases/MoveSpeed3.84
+ 0.31
+ 0.02
@@ -58,6 +60,8 @@
*/ThingDef[defName="Monkey"]/statBases/MoveSpeed5
+ 0.45
+ 0.03
@@ -103,6 +107,14 @@
+
+ */ThingDef[defName="Boomalope"]/statBases
+
+ 0.05
+ 0.07
+
+
+
*/ThingDef[defName="Boomalope"]/verbs
diff --git a/Patches/Core/ThingDefs_Races/Races_Animal_WildCanines.xml b/Patches/Core/ThingDefs_Races/Races_Animal_WildCanines.xml
index 4057280013..f76956233d 100644
--- a/Patches/Core/ThingDefs_Races/Races_Animal_WildCanines.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Animal_WildCanines.xml
@@ -24,6 +24,8 @@
0.0750.125
+ 0.26
+ 0.20
@@ -106,6 +108,8 @@
*/ThingDef[@Name="ThingBaseWolf"]/statBases/MoveSpeed6.25
+ 0.42
+ 0.09
diff --git a/Patches/Core/ThingDefs_Races/Races_Mechanoid.xml b/Patches/Core/ThingDefs_Races/Races_Mechanoid.xml
index 1e434b1b56..30e460282e 100644
--- a/Patches/Core/ThingDefs_Races/Races_Mechanoid.xml
+++ b/Patches/Core/ThingDefs_Races/Races_Mechanoid.xml
@@ -52,6 +52,8 @@
400800.9
+ 0.01
+ 0.15
@@ -65,7 +67,7 @@
*/ThingDef[defName="Mechanoid_Centipede"]/statBases/ArmorRating_Sharp
- 0.9
+ 1
@@ -109,6 +111,8 @@
50200.9
+ 0.21
+ 0.22
diff --git a/Source/CombatExtended/CombatExtended.csproj b/Source/CombatExtended/CombatExtended.csproj
index eca236ea64..8b201e0b5e 100644
--- a/Source/CombatExtended/CombatExtended.csproj
+++ b/Source/CombatExtended/CombatExtended.csproj
@@ -111,8 +111,10 @@
+
+
@@ -134,6 +136,7 @@
+
@@ -222,6 +225,7 @@
+
diff --git a/Source/CombatExtended/CombatExtended/CritDefGenerator.cs b/Source/CombatExtended/CombatExtended/CritDefGenerator.cs
new file mode 100644
index 0000000000..839cd704c9
--- /dev/null
+++ b/Source/CombatExtended/CombatExtended/CritDefGenerator.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using UnityEngine;
+
+namespace CombatExtended
+{
+ public static class CritDefGenerator
+ {
+ public static IEnumerable ImpliedCritDefs()
+ {
+ foreach(DamageDef current in from def in DefDatabase.AllDefs where def.externalViolence select def)
+ {
+ var critDef = new DamageDef() {
+ defName = current.defName + "_Critical",
+ workerClass = current.workerClass,
+ externalViolence = true,
+ impactSoundType = current.impactSoundType,
+ spreadOut = current.spreadOut,
+ harmAllLayersUntilOutside = current.harmAllLayersUntilOutside,
+ hasChanceToAdditionallyDamageInnerSolidParts = current.hasChanceToAdditionallyDamageInnerSolidParts,
+ hediff = current.hediff,
+ hediffSkin = current.hediffSkin,
+ hediffSolid = current.hediffSolid
+ };
+ yield return critDef;
+ }
+ }
+ }
+}
diff --git a/Source/CombatExtended/CombatExtended/DefOfs/CE_DamageArmorCategoryDefOf.cs b/Source/CombatExtended/CombatExtended/DefOfs/CE_DamageArmorCategoryDefOf.cs
new file mode 100644
index 0000000000..e9c3534305
--- /dev/null
+++ b/Source/CombatExtended/CombatExtended/DefOfs/CE_DamageArmorCategoryDefOf.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using UnityEngine;
+
+namespace CombatExtended
+{
+ [DefOf]
+ public class CE_DamageArmorCategoryDefOf
+ {
+ public static DamageArmorCategoryDef Blunt;
+ }
+}
diff --git a/Source/CombatExtended/CombatExtended/DefOfs/CE_JobDefOf.cs b/Source/CombatExtended/CombatExtended/DefOfs/CE_JobDefOf.cs
index c87cb4dd32..547d8c8e63 100644
--- a/Source/CombatExtended/CombatExtended/DefOfs/CE_JobDefOf.cs
+++ b/Source/CombatExtended/CombatExtended/DefOfs/CE_JobDefOf.cs
@@ -17,5 +17,6 @@ public static class CE_JobDefOf
public static JobDef HunkerDown;
public static JobDef RunForCover;
public static JobDef Stabilize;
+ public static JobDef WaitKnockdown;
}
}
diff --git a/Source/CombatExtended/CombatExtended/Jobs/JobDriver_WaitKnockdown.cs b/Source/CombatExtended/CombatExtended/Jobs/JobDriver_WaitKnockdown.cs
new file mode 100644
index 0000000000..7815ed8575
--- /dev/null
+++ b/Source/CombatExtended/CombatExtended/Jobs/JobDriver_WaitKnockdown.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using UnityEngine;
+
+namespace CombatExtended
+{
+ public class JobDriver_WaitKnockdown : JobDriver_Wait
+ {
+ public override PawnPosture Posture
+ {
+ get
+ {
+ return PawnPosture.LayingAny;
+ }
+ }
+ }
+}
diff --git a/Source/CombatExtended/CombatExtended/Jobs/JobGiver_TakeAndEquip.cs b/Source/CombatExtended/CombatExtended/Jobs/JobGiver_TakeAndEquip.cs
index be078e9b13..e47b62f4a2 100644
--- a/Source/CombatExtended/CombatExtended/Jobs/JobGiver_TakeAndEquip.cs
+++ b/Source/CombatExtended/CombatExtended/Jobs/JobGiver_TakeAndEquip.cs
@@ -16,8 +16,8 @@ private enum WorkPriority
Unloading,
LowAmmo,
Weapon,
- Ammo,
- Apparel
+ Ammo
+ //Apparel
}
private WorkPriority GetPriorityWork(Pawn pawn)
@@ -85,7 +85,7 @@ private WorkPriority GetPriorityWork(Pawn pawn)
}
}
}
-
+ /*
if (!pawn.Faction.IsPlayer && pawn.equipment.Primary != null
&& !PawnUtility.EnemiesAreNearby(pawn, 30, true)
|| (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Torso)
@@ -93,8 +93,9 @@ private WorkPriority GetPriorityWork(Pawn pawn)
{
return WorkPriority.Apparel;
}
+ */
- else return WorkPriority.None;
+ return WorkPriority.None;
}
public override float GetPriority(Pawn pawn)
@@ -107,7 +108,7 @@ public override float GetPriority(Pawn pawn)
else if (priority == WorkPriority.LowAmmo) return 9f;
else if (priority == WorkPriority.Weapon) return 8f;
else if (priority == WorkPriority.Ammo) return 6f;
- else if (priority == WorkPriority.Apparel) return 5f;
+ //else if (priority == WorkPriority.Apparel) return 5f;
else if(priority == WorkPriority.None) return 0f;
TimeAssignmentDef assignment = (pawn.timetable != null) ? pawn.timetable.CurrentAssignment : TimeAssignmentDefOf.Anything;
@@ -420,7 +421,7 @@ select t
}
}
}
-
+ /*
if (!pawn.Faction.IsPlayer && pawn.apparel != null && GetPriorityWork(pawn) == WorkPriority.Apparel)
{
if (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Torso))
@@ -453,7 +454,6 @@ select t
}
}
}
- /*
if (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.FullHead))
{
Apparel apparel3 = this.FindGarmentCoveringPart(pawn, BodyPartGroupDefOf.FullHead);
@@ -470,13 +470,14 @@ select t
}
}
}
- */
}
+ */
return null;
}
return null;
}
+ /*
private static Job GotoForce(Pawn pawn, LocalTargetInfo target, PathEndMode pathEndMode)
{
using (PawnPath pawnPath = pawn.Map.pathFinder.FindPath(pawn.Position, target, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.PassAllDestroyableThings, false), pathEndMode))
@@ -511,6 +512,7 @@ private static Job GotoForce(Pawn pawn, LocalTargetInfo target, PathEndMode path
return MeleeOrWaitJob(pawn, thing, cellBeforeBlocker);
}
}
+ */
private static bool Unload(Pawn pawn)
{
@@ -540,6 +542,7 @@ private static Job MeleeOrWaitJob(Pawn pawn, Thing blocker, IntVec3 cellBeforeBl
};
}
+ /*
private Apparel FindGarmentCoveringPart(Pawn pawn, BodyPartGroupDef bodyPartGroupDef)
{
Room room = pawn.GetRoom();
@@ -562,5 +565,6 @@ select t
}
return null;
}
+ */
}
}
diff --git a/Source/CombatExtended/CombatExtended/Verbs/Verb_MeleeAttackCE.cs b/Source/CombatExtended/CombatExtended/Verbs/Verb_MeleeAttackCE.cs
index ee112c43e1..496f85556d 100644
--- a/Source/CombatExtended/CombatExtended/Verbs/Verb_MeleeAttackCE.cs
+++ b/Source/CombatExtended/CombatExtended/Verbs/Verb_MeleeAttackCE.cs
@@ -4,6 +4,7 @@
using UnityEngine;
using RimWorld;
using Verse;
+using Verse.AI;
using Verse.Sound;
namespace CombatExtended
@@ -25,7 +26,44 @@ public class Verb_MeleeAttackCE : Verb_MeleeAttack
private const int TargetCooldown = 50;
private const float DefaultHitChance = 0.6f;
private const float ShieldBlockChance = 0.75f; // If we have a shield equipped, this is the chance a parry will be a shield block
- private const float CritFactor = 1.5f; // Criticals will do normal damage times this
+ private const int KnockdownDuration = 120; // Animal knockdown lasts for this long
+
+ // XP variables
+ private const float HitXP = 200; // Vanilla is 250
+ private const float DodgeXP = 50;
+ private const float ParryXP = 50;
+ private const float CritXP = 100;
+
+ /* Base stats
+ *
+ * These are the baseline stats we want for crit/dodge/parry for pawns of equal skill. These need to be the same as set in the base factors set in the
+ * stat defs. Ideally we would access them from the defs but the relevant values are all set to private and there is no real way to get at them that I
+ * can see.
+ *
+ * -NIA
+ */
+
+ private const float BaseCritChance = 0.1f;
+ private const float BaseDodgeChance = 0.1f;
+ private const float BaseParryChance = 0.2f;
+
+ #endregion
+
+ #region Properties
+
+ DamageDef CritDamageDef
+ {
+ get
+ {
+ if (CasterPawn.def.race.Animal)
+ return verbProps.meleeDamageDef;
+ if (verbProps.meleeDamageDef.armorCategory == CE_DamageArmorCategoryDefOf.Blunt)
+ {
+ return DamageDefOf.Stun;
+ }
+ return DefDatabase.GetNamed(verbProps.meleeDamageDef.defName + "_Critical");
+ }
+ }
#endregion
@@ -59,7 +97,7 @@ protected override bool TryCastShot()
bool targetImmobile = IsTargetImmobile(currentTarget);
if (!targetImmobile && casterPawn.skills != null)
{
- casterPawn.skills.Learn(SkillDefOf.Melee, 250f, false);
+ casterPawn.skills.Learn(SkillDefOf.Melee, HitXP, false);
}
// Hit calculations
@@ -71,18 +109,19 @@ protected override bool TryCastShot()
if (hitRoll < GetHitChance(targetThing))
{
// Check for dodge
- if (!targetImmobile && !surpriseAttack && hitRoll < targetThing.GetStatValue(CE_StatDefOf.MeleeDodgeChance))
+ if (!targetImmobile && !surpriseAttack && hitRoll < GetDodgeChanceAgainst(casterPawn, defender))
{
// Attack is evaded
moteText = "Dodged";
result = false;
soundDef = SoundMiss();
+ defender.skills?.Learn(SkillDefOf.Melee, DodgeXP, false);
}
else
{
// Attack connects, calculate resolution
var resultRoll = Rand.Value;
- var parryChance = targetThing.GetStatValue(CE_StatDefOf.MeleeParryChance);
+ var parryChance = GetParryChanceAgainst(casterPawn, defender);
if (!surpriseAttack && defender != null && CanDoParry(defender) && resultRoll < parryChance)
{
// Attack is parried
@@ -91,17 +130,19 @@ protected override bool TryCastShot()
Thing parryThing = isShieldBlock ? shield
: defender.equipment?.Primary != null ? defender.equipment.Primary : defender;
- if (resultRoll < parryChance * targetThing.GetStatValue(CE_StatDefOf.MeleeCritChance))
+ if (resultRoll < parryChance * GetCritChanceAgainst(defender, casterPawn))
{
// Do a riposte
DoParry(defender, parryThing, true);
moteText = "Riposted";
+ defender.skills?.Learn(SkillDefOf.Melee, CritXP + ParryXP, false);
}
else
{
// Do a parry
DoParry(defender, parryThing);
moteText = "Parried";
+ defender.skills?.Learn(SkillDefOf.Melee, ParryXP, false);
}
result = false;
@@ -110,7 +151,7 @@ protected override bool TryCastShot()
else
{
// Attack connects
- if (!surpriseAttack && resultRoll < (1 - casterPawn.GetStatValue(CE_StatDefOf.MeleeCritChance)))
+ if (!surpriseAttack && resultRoll < (1 - GetCritChanceAgainst(casterPawn, defender)))
{
// Do a regular hit as per vanilla
ApplyMeleeDamageToTarget(currentTarget);
@@ -120,6 +161,7 @@ protected override bool TryCastShot()
// Do a critical hit
ApplyMeleeDamageToTarget(currentTarget, true);
moteText = "Critical hit";
+ casterPawn.skills?.Learn(SkillDefOf.Melee, CritXP, false);
}
result = true;
soundDef = targetThing.def.category == ThingCategory.Building ? SoundHitBuilding() : SoundHitPawn();
@@ -159,10 +201,11 @@ protected override bool TryCastShot()
///
/// The target damage is to be applied to
/// Collection with primary DamageInfo, followed by secondary types
- private IEnumerable DamageInfosToApply(LocalTargetInfo target)
+ private IEnumerable DamageInfosToApply(LocalTargetInfo target, bool isCrit = false)
{
float damAmount = (float)this.verbProps.AdjustedMeleeDamageAmount(this, base.CasterPawn, this.ownerEquipment);
- DamageDef damDef = this.verbProps.meleeDamageDef;
+ var critDamDef = CritDamageDef;
+ DamageDef damDef = isCrit && critDamDef != DamageDefOf.Stun ? critDamDef : verbProps.meleeDamageDef;
BodyPartGroupDef bodyPartGroupDef = null;
HediffDef hediffDef = null;
if (base.CasterIsPawn)
@@ -199,6 +242,8 @@ private IEnumerable DamageInfosToApply(LocalTargetInfo target)
mainDinfo.SetWeaponHediff(hediffDef);
mainDinfo.SetAngle(direction);
yield return mainDinfo;
+
+ // Apply secondary damage on surprise attack
if (this.surpriseAttack && this.verbProps.surpriseAttack != null && this.verbProps.surpriseAttack.extraMeleeDamages != null)
{
List extraDamages = this.verbProps.surpriseAttack.extraMeleeDamages;
@@ -215,6 +260,18 @@ private IEnumerable DamageInfosToApply(LocalTargetInfo target)
yield return extraDinfo;
}
}
+
+ // Apply critical damage
+ if (isCrit && critDamDef == DamageDefOf.Stun)
+ {
+ var critAmount = GenMath.RoundRandom(mainDinfo.Amount * 0.25f);
+ var critDinfo = new DamageInfo(critDamDef, critAmount, -1, caster, null, source);
+ critDinfo.SetBodyRegion(bodyRegion, BodyPartDepth.Outside);
+ critDinfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
+ critDinfo.SetWeaponHediff(hediffDef);
+ critDinfo.SetAngle(direction);
+ yield return critDinfo;
+ }
}
// unmodified
@@ -255,15 +312,25 @@ private bool IsTargetImmobile(LocalTargetInfo target)
/// Whether we should apply critical damage
private void ApplyMeleeDamageToTarget(LocalTargetInfo target, bool isCrit = false)
{
- foreach (DamageInfo current in DamageInfosToApply(target))
+ foreach (DamageInfo current in DamageInfosToApply(target, isCrit))
{
if (target.ThingDestroyed)
{
- break;
+ return;
}
- if (isCrit) current.SetAmount(Mathf.CeilToInt(current.Amount * CritFactor)); // Apply crit factor
target.Thing.TakeDamage(current);
}
+ // Apply animal knockdown
+ if (isCrit && CasterPawn.def.race.Animal)
+ {
+ var pawn = target.Thing as Pawn;
+ if (pawn != null)
+ {
+ //pawn.stances?.stunner.StunFor(KnockdownDuration);
+ pawn.stances.SetStance(new Stance_Cooldown(KnockdownDuration, pawn, null));
+ pawn.jobs?.StartJob(new Job(CE_JobDefOf.WaitKnockdown) { expiryInterval = KnockdownDuration }, JobCondition.InterruptForced, null, false, false);
+ }
+ }
}
///
@@ -277,7 +344,7 @@ private bool CanDoParry(Pawn pawn)
|| pawn.Dead
|| !pawn.RaceProps.Humanlike
|| pawn.story.WorkTagIsDisabled(WorkTags.Violent)
- || pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)
+ || !pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)
|| IsTargetImmobile(pawn))
{
return false;
@@ -419,6 +486,43 @@ private SoundDef SoundMiss()
return SoundDefOf.Pawn_Melee_Punch_Miss;
}
+ #region Stat calculations
+
+ private static float GetCritChanceAgainst(Pawn attacker, Pawn defender)
+ {
+ if (attacker == null || defender == null)
+ return 0;
+ var stat = CE_StatDefOf.MeleeCritChance;
+ var offSkill = attacker.GetStatValue(stat);
+ var defSkill = defender.GetStatValue(stat);
+ var chance = Mathf.Clamp01(BaseCritChance + offSkill - defSkill);
+ return chance;
+ }
+
+ private static float GetParryChanceAgainst(Pawn attacker, Pawn defender)
+ {
+ if (attacker == null || defender == null)
+ return 0;
+ var stat = CE_StatDefOf.MeleeParryChance;
+ var offSkill = attacker.GetStatValue(stat);
+ var defSkill = defender.GetStatValue(stat);
+ var chance = Mathf.Clamp01(BaseParryChance + defSkill - offSkill);
+ return chance;
+ }
+
+ private static float GetDodgeChanceAgainst(Pawn attacker, Pawn defender)
+ {
+ if (attacker == null || defender == null)
+ return 0;
+ var stat = StatDefOf.MeleeDodgeChance;
+ var offSkill = attacker.GetStatValue(stat);
+ var defSkill = defender.GetStatValue(stat);
+ var chance = Mathf.Clamp01(BaseDodgeChance + defSkill - offSkill);
+ return chance;
+ }
+
+ #endregion
+
#endregion
}
}
diff --git a/Source/CombatExtended/Harmony/Harmony-DefGenerator.cs b/Source/CombatExtended/Harmony/Harmony-DefGenerator.cs
new file mode 100644
index 0000000000..93f272825b
--- /dev/null
+++ b/Source/CombatExtended/Harmony/Harmony-DefGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using UnityEngine;
+using Harmony;
+
+namespace CombatExtended.Harmony
+{
+ [HarmonyPatch(typeof(DefGenerator), "GenerateImpliedDefs_PreResolve")]
+ static class Harmony_DefGenerator
+ {
+ public static void Postfix()
+ {
+ var enumerable = CritDefGenerator.ImpliedCritDefs().ToArray();
+ foreach (DamageDef current in enumerable)
+ {
+ current.PostLoad();
+ DefDatabase.Add(current);
+ }
+ }
+ }
+}
diff --git a/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_a.png b/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_a.png
new file mode 100644
index 0000000000..bf6b90eb60
Binary files /dev/null and b/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_a.png differ
diff --git a/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_b.png b/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_b.png
new file mode 100644
index 0000000000..c5add2eb25
Binary files /dev/null and b/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_b.png differ
diff --git a/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_c.png b/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_c.png
new file mode 100644
index 0000000000..c8b7a4e362
Binary files /dev/null and b/Textures/Things/Ammo/HandGrenades/Firefoam/Firefoam_c.png differ
diff --git a/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_a.png b/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_a.png
new file mode 100644
index 0000000000..e3797ee5fa
Binary files /dev/null and b/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_a.png differ
diff --git a/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_b.png b/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_b.png
new file mode 100644
index 0000000000..be005ef1ec
Binary files /dev/null and b/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_b.png differ
diff --git a/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_c.png b/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_c.png
new file mode 100644
index 0000000000..874dd6ebfa
Binary files /dev/null and b/Textures/Things/Ammo/HandGrenades/Smoke/Smoke_c.png differ