Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions Defs/Stats/Stats_ThermalVision.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Defs>

<!-- ================================== Pawn's stat =======================================-->

<StatDef>
<defName>ThermalVisionEfficiency</defName>
<label>thermal vision efficiency</label>
<description>A measure of the creature's overall ability to overcome the effects of blind smoke and bad weather for the purpose of making ranged attacks based on apparel, implants, and their natural abilities.</description>
<category>PawnCombat</category>
<defaultBaseValue>0</defaultBaseValue>
<displayPriorityInCategory>70</displayPriorityInCategory>
<toStringStyle>PercentZero</toStringStyle>
<showIfUndefined>true</showIfUndefined>
<minValue>0</minValue>
<maxValue>1.0</maxValue>
<parts>
<li Class="CombatExtended.StatPart_StatMaxima">
<apparelStat>ThermalVisionEfficiency_Apparel</apparelStat>
<sumApparelsStat>false</sumApparelsStat>
<weaponStat>ThermalVisionEfficiency_Weapon</weaponStat>
<sumImplantsStat>true</sumImplantsStat>
<implantStat>ThermalVisionEfficiency_Implant</implantStat>
<priority>1000</priority>
</li>
</parts>
</StatDef>

<!-- ================================== Bases - (Parts only) =======================================-->

<StatDef Name="BaseThermalVisionPart" Abstract="true">
<minValue>0</minValue>
<maxValue>1.0</maxValue>
<hideAtValue>0</hideAtValue>
<defaultBaseValue>0</defaultBaseValue>
<toStringStyle>PercentZero</toStringStyle>
<showIfUndefined>false</showIfUndefined>
</StatDef>

<!-- ================================== Implants =======================================-->

<StatDef ParentName="BaseThermalVisionPart">
<defName>ThermalVisionEfficiency_Implant</defName>
<label>implant thermal vision efficiency</label>
<description>The effect of artifical implants on a creature's ability to overcome the effects of blind smoke and bad weather for the purpose of making ranged attacks.</description>
<category>PawnCombat</category>
</StatDef>

<!-- ================================== Apparel/Equipment - base =======================================-->

<StatDef Name="EquipmentThermalVisionBase" ParentName="BaseThermalVisionPart" Abstract="true">
<parts>
<li Class="StatPart_Quality"> <!-- Since this reduces environment penalty, item stat maxes out at 100%. -->
<factorAwful>0.70</factorAwful>
<factorPoor>0.85</factorPoor>
<factorNormal>1</factorNormal>
<factorGood>1.05</factorGood>
<factorExcellent>1.1</factorExcellent>
<factorMasterwork>1.15</factorMasterwork>
<factorLegendary>1.25</factorLegendary>
</li>
</parts>
</StatDef>

<!-- ================================== Apparel/Equipment =======================================-->

<StatDef ParentName="EquipmentThermalVisionBase">
<defName>ThermalVisionEfficiency_Weapon</defName>
<label>weapon thermal vision efficiency</label>
<description>The effect of a weapon's optics on the wielder's ability to overcome the effects of blind smoke and bad weather for the purpose of firing accurately.</description>
<category>Weapon</category>
<parts>
<li Class="CombatExtended.StatPart_Attachments" />
</parts>
</StatDef>

<StatDef ParentName="EquipmentThermalVisionBase">
<defName>ThermalVisionEfficiency_Apparel</defName>
<label>apparel thermal vision efficiency</label>
<description>The effect of apparel items on a creature's ability to overcome the effects of blind smoke and bad weather for the purpose of making ranged attacks.</description>
<category>Apparel</category>
</StatDef>

</Defs>
84 changes: 84 additions & 0 deletions Defs/Stats/Stats_VisibilityConcealment.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Defs>

<!-- ================================== Pawn's stat =======================================-->

<StatDef>
<defName>VisibilityConcealmentEfficiency</defName>
<label>concealment efficiency</label>
<description>A measure of the creature's overall ability to conceal themselves and blend into surroundings, increasing visibility error against them based on apparel, implants, and their natural abilities.</description>
<category>PawnCombat</category>
<defaultBaseValue>1</defaultBaseValue>
<displayPriorityInCategory>70</displayPriorityInCategory>
<toStringStyle>PercentZero</toStringStyle>
<showIfUndefined>true</showIfUndefined>
<minValue>0</minValue>
<maxValue>10.0</maxValue>
<parts>
<li Class="CombatExtended.StatPart_StatMaxima">
<apparelStat>VisibilityConcealmentEfficiency_Apparel</apparelStat>
<sumApparelsStat>false</sumApparelsStat>
<weaponStat>VisibilityConcealmentEfficiency_Weapon</weaponStat>
<sumImplantsStat>true</sumImplantsStat>
<implantStat>VisibilityConcealmentEfficiency_Implant</implantStat>
<priority>1000</priority>
</li>
</parts>
</StatDef>

<!-- ================================== Bases - (Parts only) =======================================-->

<StatDef Name="BaseVisibilityConcealmentPart" Abstract="true">
<minValue>0</minValue>
<maxValue>10.0</maxValue>
<hideAtValue>1</hideAtValue>
<defaultBaseValue>1</defaultBaseValue>
<toStringStyle>PercentZero</toStringStyle>
<showIfUndefined>false</showIfUndefined>
</StatDef>

<!-- ================================== Implants =======================================-->

<StatDef ParentName="BaseVisibilityConcealmentPart">
<defName>VisibilityConcealmentEfficiency_Implant</defName>
<label>implant concealment efficiency</label>
<description>The effect of artifical implants on a creature's ability to conceal themselves and blend into surroundings, increasing visibility error against them.</description>
<category>PawnCombat</category>
</StatDef>

<!-- ================================== Apparel/Equipment - base =======================================-->

<StatDef Name="EquipmentVisibilityConcealmentBase" ParentName="BaseVisibilityConcealmentPart" Abstract="true">
<parts>
<li Class="StatPart_Quality">
<factorAwful>0.70</factorAwful>
<factorPoor>0.85</factorPoor>
<factorNormal>1</factorNormal>
<factorGood>1.05</factorGood>
<factorExcellent>1.1</factorExcellent>
<factorMasterwork>1.15</factorMasterwork>
<factorLegendary>1.25</factorLegendary>
</li>
</parts>
</StatDef>

<!-- ================================== Apparel/Equipment =======================================-->

<StatDef ParentName="EquipmentVisibilityConcealmentBase">
<defName>VisibilityConcealmentEfficiency_Weapon</defName>
<label>weapon concealment efficiency</label>
<description>The effect of a weapon's camouflage on the wielder's ability to conceal themselves and blend into surroundings, increasing visibility error against them.</description>
<category>Weapon</category>
<parts>
<li Class="CombatExtended.StatPart_Attachments" />
</parts>
</StatDef>

<StatDef ParentName="EquipmentVisibilityConcealmentBase">
<defName>VisibilityConcealmentEfficiency_Apparel</defName>
<label>apparel concealment efficiency</label>
<description>The effect of apparel items on a creature's ability to conceal themselves and blend into surroundings, increasing visibility error against them.</description>
<category>Apparel</category>
</StatDef>

</Defs>
1 change: 1 addition & 0 deletions Defs/ThingDefs_Misc/Apparel_Headgear.xml
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@
<WornBulk>1</WornBulk>
<EquipDelay>0.5</EquipDelay>
<NightVisionEfficiency_Apparel>0.6</NightVisionEfficiency_Apparel>
<ThermalVisionEfficiency_Apparel>0.6</ThermalVisionEfficiency_Apparel>
<ArmorRating_Sharp>0.04</ArmorRating_Sharp> <!-- A little bit of armor to prevent triggering a warning when shot. -->
<ArmorRating_Blunt>0.01</ArmorRating_Blunt>
</statBases>
Expand Down
1 change: 1 addition & 0 deletions Languages/English/Keyed/Keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
<CE_ChanceFactor>Chance factor</CE_ChanceFactor>
<CE_LimbParryBonusChance>Non-human parry bonus: + {0}%</CE_LimbParryBonusChance>
<CE_LimbParryBonus>Attacking Limb(s): +{0}% ({1} intact limb(s))</CE_LimbParryBonus>
<CE_VisibilityTimeDelay>Visibility delay</CE_VisibilityTimeDelay>

<!-- Alerts -->
<CE_ColonistHasShieldAndTwoHandedWeapon>Colonist has shield and two-handed weapon</CE_ColonistHasShieldAndTwoHandedWeapon>
Expand Down
5 changes: 5 additions & 0 deletions Languages/English/Keyed/ModMenu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@
<CE_Settings_FasterRepeatShots_Desc>When enabled, subsequent shots at the same, or nearby, targets are faster.</CE_Settings_FasterRepeatShots_Desc>
<CE_Settings_FasterRepeatShots_Title>Faster subsequent shots</CE_Settings_FasterRepeatShots_Title>

<CE_Settings_VisibilityWarmupPenalty_Desc>When enabled, shooters will take more time to aim at targets in low visibility conditions like darkness, blind smoke and bad weather.</CE_Settings_VisibilityWarmupPenalty_Desc>
<CE_Settings_VisibilityWarmupPenalty_Title>Slower low visibility shots</CE_Settings_VisibilityWarmupPenalty_Title>
<CE_Settings_VisibilityWarmupSlider_Desc>Changes how much weapon warmup time will be affected by the visibility penalty</CE_Settings_VisibilityWarmupSlider_Desc>
<CE_Settings_VisibilityWarmupSlider_Title>Visibility penalty multiplier</CE_Settings_VisibilityWarmupSlider_Title>

<CE_Settings_MidBurstRetarget_Desc>When enabled, shooters will switch to a new target when their primary target is downed mid-burst.</CE_Settings_MidBurstRetarget_Desc>
<CE_Settings_MidBurstRetarget_Title>Retarget mid burst</CE_Settings_MidBurstRetarget_Title>

Expand Down
2 changes: 2 additions & 0 deletions Source/CombatExtended/CombatExtended/DefOfs/CE_StatDefOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ static CE_StatDefOf()
public static StatDef BodyPartBluntArmor;
public static StatDef AverageSharpArmor;
public static StatDef NightVisionEfficiency;
public static StatDef ThermalVisionEfficiency;
public static StatDef VisibilityConcealmentEfficiency;

public static StatDef SmokeSensitivity;

Expand Down
11 changes: 11 additions & 0 deletions Source/CombatExtended/CombatExtended/ModSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public class Settings : ModSettings, ISettingsCE

private bool midBurstRetarget = true;
private bool fasterRepeatShots = true;
private bool visibilityWarmupPenalty = true;
private float visibilityPenaltyMultiplier = 10f;

private float explosionPenMultiplier = 1.0f;
private float explosionFalloffFactor = 1.0f;
Expand Down Expand Up @@ -140,6 +142,8 @@ public class Settings : ModSettings, ISettingsCE
public bool FragmentsFromWalls => fragmentsFromWalls;

public bool FasterRepeatShots => fasterRepeatShots;
public bool VisibilityWarmupPenalty => visibilityWarmupPenalty;
public float VisibilityPenaltyMultiplier => visibilityPenaltyMultiplier;
public bool MidBurstRetarget => midBurstRetarget;

public float ExplosionPenMultiplier => explosionPenMultiplier;
Expand Down Expand Up @@ -225,6 +229,7 @@ public override void ExposeData()

Scribe_Values.Look(ref fragmentsFromWalls, "fragmentsFromWalls", false);
Scribe_Values.Look(ref fasterRepeatShots, "fasterRepeatShots", false);
Scribe_Values.Look(ref visibilityWarmupPenalty, "visibilityWarmupPenalty", true);
Scribe_Values.Look(ref midBurstRetarget, "midBurstRetarget", true);
Scribe_Values.Look(ref explosionPenMultiplier, "explosionPenMultiplier", 1.0f);
Scribe_Values.Look(ref explosionFalloffFactor, "explosionFalloffFactor", 1.0f);
Expand All @@ -234,6 +239,7 @@ public override void ExposeData()
lastAmmoSystemStatus = enableAmmoSystem; // Store this now so we can monitor for changes

Scribe_Values.Look(ref medicineSearchRadius, "medicineSearchRadius", 5f);
Scribe_Values.Look(ref visibilityPenaltyMultiplier, "visibilityPenaltyMultiplier", 10f);
}
public void DoWindowContents(Listing_Standard list)
{
Expand Down Expand Up @@ -275,6 +281,9 @@ private void DoSettingsWindowContents_Mechanics(Listing_Standard list)
left.CheckboxLabeled("CE_Settings_SmokeEffects_Title".Translate(), ref smokeEffects, "CE_Settings_SmokeEffects_Desc".Translate());
left.CheckboxLabeled("CE_Settings_TurretsBreakShields_Title".Translate(), ref turretsBreakShields, "CE_Settings_TurretsBreakShields_Desc".Translate());
left.CheckboxLabeled("CE_Settings_FasterRepeatShots_Title".Translate(), ref fasterRepeatShots, "CE_Settings_FasterRepeatShots_Desc".Translate());
left.CheckboxLabeled("CE_Settings_VisibilityWarmupPenalty_Title".Translate(), ref visibilityWarmupPenalty, "CE_Settings_VisibilityWarmupPenalty_Desc".Translate());
visibilityPenaltyMultiplier = left.SliderLabeled("CE_Settings_VisibilityWarmupSlider_Title".Translate() + ": " + visibilityPenaltyMultiplier.ToString("F0"), visibilityPenaltyMultiplier, 1f, 100f, tooltip: "CE_Settings_VisibilityWarmupSlider_Desc".Translate(), labelPct: 0.6f);
left.Gap();
left.CheckboxLabeled("CE_Settings_MidBurstRetarget_Title".Translate(), ref midBurstRetarget, "CE_Settings_MidBurstRetarget_Desc".Translate());
left.CheckboxLabeled("CE_Settings_EnableArcOfFire_Title".Translate(), ref enableArcOfFire, "CE_Settings_EnableArcOfFire_Desc".Translate());
left.CheckboxLabeled("CE_Settings_EnableCIWS".Translate(), ref enableCIWS, "CE_Settings_EnableCIWS_Desc".Translate());
Expand Down Expand Up @@ -456,6 +465,8 @@ private void ResetToDefault_Mechanics()
smokeEffects = true;
turretsBreakShields = true;
fasterRepeatShots = true;
visibilityWarmupPenalty = true;
visibilityPenaltyMultiplier = 10f;
midBurstRetarget = true;
enableCIWS = true;
fragmentsFromWalls = false;
Expand Down
8 changes: 8 additions & 0 deletions Source/CombatExtended/CombatExtended/ShiftVecReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ public float visibilityShift
se = 0.02f;
}
visibilityShiftInt = enviromentShift * (shotDist / 50 / se) * (2 - aimingAccuracy);
if (targetPawn != null)
{
enviromentShiftInt *= targetPawn.GetStatValue(CE_StatDefOf.VisibilityConcealmentEfficiency);
}
}
return visibilityShiftInt;
}
Expand Down Expand Up @@ -216,6 +220,10 @@ public string GetTextReadout()
stringBuilder.AppendLine(" " + $"DEBUG: lightingShift\t\t{lightingShift}");
}

if (visibilityShift > 0 && Controller.settings.VisibilityWarmupPenalty)
{
stringBuilder.AppendLine(" " + "CE_VisibilityTimeDelay".Translate() + ":\t" + GenText.ToStringByStyle(((int)(visibilityShift * Controller.settings.VisibilityPenaltyMultiplier)).TicksToSeconds(), ToStringStyle.FloatTwo) + " " + "LetterSecond".Translate());
}
if (lightingShift > 0)
{
stringBuilder.AppendLine(" " + "Darkness".Translate() + "\t" + AsPercent(lightingShift));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,9 +652,10 @@ public virtual ShiftVecReport ShiftVecReportFor(LocalTargetInfo target, IntVec3
report.maxRange = EffectiveRange;
report.lightingShift = CE_Utility.GetLightingShift(Shooter, LightingTracker.CombatGlowAtFor(caster.Position, targetCell));

float environmentPenaltyMultiplier = (1.0f - caster.GetStatValue(CE_StatDefOf.ThermalVisionEfficiency));
if (!caster.Position.Roofed(caster.Map) || !targetCell.Roofed(caster.Map)) //Change to more accurate algorithm?
{
report.weatherShift = 1 - caster.Map.weatherManager.CurWeatherAccuracyMultiplier;
report.weatherShift = (1 - caster.Map.weatherManager.CurWeatherAccuracyMultiplier) * environmentPenaltyMultiplier;
}
report.shotSpeed = ShotSpeed;
report.swayDegrees = SwayAmplitude;
Expand All @@ -666,7 +667,7 @@ public virtual ShiftVecReport ShiftVecReportFor(LocalTargetInfo target, IntVec3

GetHighestCoverAndSmokeForTarget(target, out cover, out smokeDensity, out roofed);
report.cover = cover;
report.smokeDensity = smokeDensity;
report.smokeDensity = smokeDensity * environmentPenaltyMultiplier;
report.roofed = roofed;
return report;
}
Expand Down Expand Up @@ -703,9 +704,10 @@ public virtual ShiftVecReport ShiftVecReportFor(GlobalTargetInfo target)
float spreadmult = projectilePropsCE != null ? projectilePropsCE.spreadMult : 0f;
report.spreadDegrees = (EquipmentSource?.GetStatValue(CE_StatDefOf.ShotSpread) ?? 0) * spreadmult;
report.cover = null;
float environmentPenaltyMultiplier = (1.0f - caster.GetStatValue(CE_StatDefOf.ThermalVisionEfficiency));
if (target.Map != null)
{
report.weatherShift = (1f - target.Map.weatherManager.CurWeatherAccuracyMultiplier) * 1.5f + (1 - caster.Map.weatherManager.CurWeatherAccuracyMultiplier) * 0.5f;
report.weatherShift = (1f - target.Map.weatherManager.CurWeatherAccuracyMultiplier) * 1.5f + (1 - caster.Map.weatherManager.CurWeatherAccuracyMultiplier) * 0.5f * environmentPenaltyMultiplier;
report.lightingShift = 1f;
report.smokeDensity = (/*target.Cell.GetGas(target.Map)?.def.gas.accuracyPenalty*/1f/* ?? 0f*/) * 10f;
}
Expand Down Expand Up @@ -1007,14 +1009,35 @@ public virtual void RecalculateWarmupTicks()
{
}

public virtual void ApplyVisibilityWarmupPenalty(LocalTargetInfo destTarg)
{
if (Controller.settings.VisibilityWarmupPenalty && verbProps.requireLineOfSight)
{
var report = ShiftVecReportFor(destTarg);
#if DEBUG
if (Controller.settings.DebugVerbose)
{
Log.Message(
$"CE: Warmup: {this.BurstWarmupTicksLeft} ticks + {report.visibilityShift * Controller.settings.VisibilityPenaltyMultiplier} ticks visibility penalty");
}
#endif

this.BurstWarmupTicksLeft += (int)(report.visibilityShift * Controller.settings.VisibilityPenaltyMultiplier);
}
}

public override bool TryStartCastOn(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, bool canHitNonTargetPawns = true, bool preventFriendlyFire = false, bool nonInterruptingSelfCast = false)
{
bool startedCasting = base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
if (startedCasting)
{
if (this.repeating && this.verbProps.warmupTime > 0f) // now warming up
if (this.verbProps.warmupTime > 0f) // now warming up
{
this.RecalculateWarmupTicks();
if (this.repeating)
{
this.RecalculateWarmupTicks();
}
ApplyVisibilityWarmupPenalty(castTarg);
}
}
return startedCasting;
Expand Down