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 @@ true false + + + 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 + 1 true 0.0 + 3.2 PercentZero -
  • +
  • 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 + 1 true 0.0 + 3.2 PercentZero + 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 @@ 50 True - 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/MoveSpeed 5 + 0.12 + 0.27 @@ -48,6 +50,8 @@ */ThingDef[defName="Gazelle"]/statBases/MoveSpeed 6.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/MoveSpeed 5.5 - - - - - */ThingDef[defName="Rhinoceros"]/statBases - + 0.08 + 0.52 0.13 0.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.13 0.15 + 0.17 + 0.19 @@ -103,6 +105,8 @@ */ThingDef[defName="PolarBear"]/statBases 4.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/MoveSpeed 5 + 0.24 + 0.09 @@ -82,6 +84,8 @@ */ThingDef[defName="Emu"]/statBases/MoveSpeed 4.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/MoveSpeed 2.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/MoveSpeed 5 + 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.41 0.10 0.125 @@ -91,6 +95,8 @@ */ThingDef[defName="Thrumbo"]/statBases + 0.06 + 0.76 0.2 0.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/MoveSpeed 4.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/MoveSpeed 3.7 + 0.21 + 0.02 @@ -64,6 +66,8 @@ */ThingDef[defName="Spelopede"]/statBases/MoveSpeed 3.7 + 0.08 + 0.12 @@ -110,6 +114,8 @@ */ThingDef[defName="Megaspider"]/statBases/MoveSpeed 4 + 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/MoveSpeed 2.4 + 0.53 + 0.0 @@ -73,6 +75,8 @@ */ThingDef[defName="Alphabeaver"]/statBases/MoveSpeed 5 + 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/MoveSpeed 2.84 + 0.74 + 0.0 @@ -234,6 +248,8 @@ */ThingDef[defName="Boomrat"]/statBases/MoveSpeed 3.0 + 0.54 + 0.01 @@ -320,6 +336,8 @@ */ThingDef[defName="Raccoon"]/statBases/MoveSpeed 3 + 0.32 + 0.01 @@ -384,6 +402,8 @@ */ThingDef[defName="Rat"]/statBases/MoveSpeed 2.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/MoveSpeed 7 + 0.39 + 0.14 @@ -82,6 +84,8 @@ */ThingDef[defName="Ibex"]/statBases/MoveSpeed 4.4 + 0.20 + 0.08 @@ -148,6 +152,8 @@ */ThingDef[defName="Elk"]/statBases/MoveSpeed 7.24 + 0.23 + 0.34 @@ -214,6 +220,8 @@ */ThingDef[defName="Caribou"]/statBases/MoveSpeed 7.84 + 0.43 + 0.22 @@ -280,6 +288,8 @@ */ThingDef[defName="WildBoar"]/statBases/MoveSpeed 4.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/MoveSpeed 3.84 + 0.31 + 0.02 @@ -58,6 +60,8 @@ */ThingDef[defName="Monkey"]/statBases/MoveSpeed 5 + 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.075 0.125 + 0.26 + 0.20 @@ -106,6 +108,8 @@ */ThingDef[@Name="ThingBaseWolf"]/statBases/MoveSpeed 6.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 @@ 400 80 0.9 + 0.01 + 0.15 @@ -65,7 +67,7 @@ */ThingDef[defName="Mechanoid_Centipede"]/statBases/ArmorRating_Sharp - 0.9 + 1 @@ -109,6 +111,8 @@ 50 20 0.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