@@ -17,114 +17,183 @@ public override string GetStatDrawEntryLabel(StatDef stat, float value, ToString
1717
1818 public override string GetExplanationUnfinalized ( StatRequest req , ToStringNumberSense numberSense )
1919 {
20- var tools = ( req . Def as ThingDef ) ? . tools ;
21-
22- if ( tools . NullOrEmpty ( ) )
20+ if ( req . Def is not ThingDef thingDef )
2321 {
2422 return base . GetExplanationUnfinalized ( req , numberSense ) ;
2523 }
24+
25+ var pawn = GetCurrentWielder ( req ) ;
26+
27+ var skillFactor = GetSkillFactor ( pawn ) ;
28+ var otherFactors = GetOtherFactors ( pawn ) ;
29+
2630 var stringBuilder = new StringBuilder ( ) ;
27- var penetrationFactor = GetPenetrationFactor ( req ) ;
28- var skillFactor = GetSkillFactor ( req ) ;
29- stringBuilder . AppendLine ( "CE_WeaponPenetrationFactor" . Translate ( ) + ": " + penetrationFactor . ToStringByStyle ( ToStringStyle . PercentZero ) ) ;
31+
3032 if ( Mathf . Abs ( skillFactor - 1f ) > 0.001f )
3133 {
3234 stringBuilder . AppendLine ( "CE_WeaponPenetrationSkillFactor" . Translate ( ) + ": " + skillFactor . ToStringByStyle ( ToStringStyle . PercentZero ) ) ;
3335 }
3436
3537 stringBuilder . AppendLine ( ) ;
3638
37- foreach ( ToolCE tool in tools )
39+ if ( req . Thing is Pawn )
3840 {
39- var maneuvers = DefDatabase < ManeuverDef > . AllDefsListForReading . Where ( d => tool . capacities . Contains ( d . requiredCapacity ) ) ;
40- var maneuverString = "(" ;
41- foreach ( var maneuver in maneuvers )
42- {
43- maneuverString += maneuver . ToString ( ) + "/" ;
44- }
45- maneuverString = maneuverString . TrimmedToLength ( maneuverString . Length - 1 ) + ")" ;
46- stringBuilder . AppendLine ( " " + "Tool" . Translate ( ) + ": " + tool . ToString ( ) + " " + maneuverString ) ;
47- var otherFactors = GetOtherFactors ( req ) . Aggregate ( 1f , ( x , y ) => x * y ) ;
48- if ( Mathf . Abs ( otherFactors - 1f ) > 0.001f )
41+ var meleeVerbs = pawn . meleeVerbs . GetUpdatedAvailableVerbsList ( terrainTools : false ) ;
42+ var cumulativeWeights = meleeVerbs . Sum ( verbEntry => verbEntry . GetSelectionWeight ( null ) ) ;
43+ foreach ( var verbEntry in meleeVerbs )
4944 {
50- stringBuilder . AppendLine ( " " + "CE_WeaponPenetrationOtherFactors" . Translate ( ) + ": " + otherFactors . ToStringByStyle ( ToStringStyle . PercentZero ) ) ;
51- }
45+ var penetrationFactor =
46+ verbEntry . verb . EquipmentSource ? . GetStatValue ( CE_StatDefOf . MeleePenetrationFactor ) ?? 1f ;
47+ var chance = verbEntry . GetSelectionWeight ( null ) / cumulativeWeights ;
5248
53- stringBuilder . Append ( string . Format ( " {0}: {1} x {2}" ,
54- "CE_DescSharpPenetration" . Translate ( ) ,
55- tool . armorPenetrationSharp . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
56- penetrationFactor . ToStringByStyle ( ToStringStyle . FloatMaxThree ) ) ) ;
57- if ( Mathf . Abs ( skillFactor - 1f ) > 0.001f )
58- {
59- stringBuilder . Append ( string . Format ( " x {0}" , skillFactor . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
49+ if ( chance > 0 )
50+ {
51+ ShowExplanationForVerb (
52+ stringBuilder ,
53+ verbEntry . verb . tool ,
54+ verbEntry . verb . maneuver ,
55+ skillFactor ,
56+ otherFactors ,
57+ penetrationFactor ,
58+ chance
59+ ) ;
60+ }
6061 }
61- if ( Mathf . Abs ( otherFactors - 1f ) > 0.001f )
62+ }
63+ else
64+ {
65+ var penetrationFactor = GetPenetrationFactor ( req ) ;
66+ var meleeVerbPropsWithSource = AllMeleeVerbPropsWithSource ( thingDef ) ;
67+ var cumulativeWeights = meleeVerbPropsWithSource . Sum ( vps => AdjustedMeleeSelectionWeight ( vps , pawn , req ) ) ;
68+ foreach ( var vps in meleeVerbPropsWithSource )
6269 {
63- stringBuilder . Append ( string . Format ( " x {0}" , otherFactors . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
70+ var chance = AdjustedMeleeSelectionWeight ( vps , pawn , req ) / cumulativeWeights ;
71+ ShowExplanationForVerb (
72+ stringBuilder ,
73+ vps . tool ,
74+ vps . maneuver ,
75+ skillFactor ,
76+ otherFactors ,
77+ penetrationFactor ,
78+ chance
79+ ) ;
6480 }
65- stringBuilder . AppendLine ( string . Format ( " = {0} {1}" ,
66- ( tool . armorPenetrationSharp * penetrationFactor * skillFactor * otherFactors ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
67- "CE_mmRHA" . Translate ( ) ) ) ;
81+ }
6882
83+ return stringBuilder . ToString ( ) ;
84+ }
6985
70- stringBuilder . Append ( string . Format ( " {0}: {1} x {2}" ,
71- "CE_DescBluntPenetration" . Translate ( ) ,
72- tool . armorPenetrationBlunt . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
73- penetrationFactor . ToStringByStyle ( ToStringStyle . FloatMaxThree ) ) ) ;
74- if ( Mathf . Abs ( skillFactor - 1f ) > 0.001f )
75- {
76- stringBuilder . Append ( string . Format ( " x {0}" , skillFactor . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
77- }
78- if ( Mathf . Abs ( otherFactors - 1f ) > 0.001f )
79- {
80- stringBuilder . Append ( string . Format ( " x {0}" , otherFactors . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
81- }
82- stringBuilder . AppendLine ( string . Format ( " = {0} {1}" ,
83- ( tool . armorPenetrationBlunt * penetrationFactor * skillFactor * otherFactors ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
84- "CE_MPa" . Translate ( ) ) ) ;
85- stringBuilder . AppendLine ( ) ;
86+ private void ShowExplanationForVerb ( StringBuilder stringBuilder , Tool verbTool , ManeuverDef maneuver ,
87+ float skillFactor ,
88+ float otherFactors ,
89+ float penetrationFactor ,
90+ float chance )
91+ {
92+ if ( verbTool is not ToolCE tool )
93+ {
94+ return ;
8695 }
87- return stringBuilder . ToString ( ) ;
96+
97+ var maneuverString = "(" + maneuver + ")" ;
98+ stringBuilder . AppendLine ( " " + "Tool" . Translate ( ) + ": " + tool . ToString ( ) + " " + maneuverString ) ;
99+
100+
101+ stringBuilder . AppendLine ( " " + "CE_WeaponPenetrationFactor" . Translate ( ) + ": " + penetrationFactor . ToStringByStyle ( ToStringStyle . PercentZero ) ) ;
102+
103+ if ( Mathf . Abs ( otherFactors - 1f ) > 0.001f )
104+ {
105+ stringBuilder . AppendLine ( " " + "CE_WeaponPenetrationOtherFactors" . Translate ( ) + ": " + otherFactors . ToStringByStyle ( ToStringStyle . PercentZero ) ) ;
106+ }
107+
108+ stringBuilder . Append ( string . Format ( " {0}: {1} x {2}" ,
109+ "CE_DescSharpPenetration" . Translate ( ) ,
110+ tool . armorPenetrationSharp . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
111+ penetrationFactor . ToStringByStyle ( ToStringStyle . FloatMaxThree ) ) ) ;
112+ if ( Mathf . Abs ( skillFactor - 1f ) > 0.001f )
113+ {
114+ stringBuilder . Append ( string . Format ( " x {0}" , skillFactor . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
115+ }
116+ if ( Mathf . Abs ( otherFactors - 1f ) > 0.001f )
117+ {
118+ stringBuilder . Append ( string . Format ( " x {0}" , otherFactors . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
119+ }
120+ stringBuilder . AppendLine ( string . Format ( " = {0} {1}" ,
121+ ( tool . armorPenetrationSharp * penetrationFactor * skillFactor * otherFactors ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
122+ "CE_mmRHA" . Translate ( ) ) ) ;
123+
124+
125+ stringBuilder . Append ( string . Format ( " {0}: {1} x {2}" ,
126+ "CE_DescBluntPenetration" . Translate ( ) ,
127+ tool . armorPenetrationBlunt . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
128+ penetrationFactor . ToStringByStyle ( ToStringStyle . FloatMaxThree ) ) ) ;
129+ if ( Mathf . Abs ( skillFactor - 1f ) > 0.001f )
130+ {
131+ stringBuilder . Append ( string . Format ( " x {0}" , skillFactor . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
132+ }
133+ if ( Mathf . Abs ( otherFactors - 1f ) > 0.001f )
134+ {
135+ stringBuilder . Append ( string . Format ( " x {0}" , otherFactors . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ) ;
136+ }
137+ stringBuilder . AppendLine ( string . Format ( " = {0} {1}" ,
138+ ( tool . armorPenetrationBlunt * penetrationFactor * skillFactor * otherFactors ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ,
139+ "CE_MPa" . Translate ( ) ) ) ;
140+ stringBuilder . AppendLine ( " " + "CE_ChanceFactor" . Translate ( ) + ": " + chance . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) ) ;
141+ stringBuilder . AppendLine ( ) ;
88142 }
89143
90144 public override string GetExplanationFinalizePart ( StatRequest req , ToStringNumberSense numberSense , float finalVal )
91145 {
92146 return "StatsReport_FinalValue" . Translate ( ) + ": " + GetFinalDisplayValue ( req ) ;
93147 }
94148
95- private string GetFinalDisplayValue ( StatRequest optionalReq )
149+ private string GetFinalDisplayValue ( StatRequest req )
96150 {
97- var tools = ( optionalReq . Def as ThingDef ) ? . tools ;
98- if ( tools . NullOrEmpty ( ) )
99- {
100- return "" ;
101- }
102- if ( tools . Any ( x => ! ( x is ToolCE ) ) )
151+ if ( req . Def is not ThingDef thingDef )
103152 {
104- Log . Error ( $ "Trying to get stat MeleeArmorPenetration from { optionalReq . Def . defName } which has no support for Combat Extended.") ;
105153 return "" ;
106154 }
107155
108- float totalSelectionWeight = 0f ;
109- foreach ( Tool tool in tools )
156+ var pawn = GetCurrentWielder ( req ) ;
157+ var otherFactors = GetOtherFactors ( pawn ) ;
158+ var skillFactor = GetSkillFactor ( pawn ) ;
159+
160+ float totalAveragePenSharp ;
161+ float totalAveragePenBlunt ;
162+
163+ if ( req . Thing is Pawn )
110164 {
111- totalSelectionWeight += tool . chanceFactor ;
165+ var meleeVerbs = pawn . meleeVerbs . GetUpdatedAvailableVerbsList ( terrainTools : false ) ;
166+
167+ totalAveragePenSharp = meleeVerbs . AverageWeighted (
168+ verbEntry => verbEntry . GetSelectionWeight ( null ) ,
169+ verbEntry => verbEntry . verb . tool is ToolCE tool ? tool . armorPenetrationSharp * otherFactors * verbEntry . verb . EquipmentSource ? . GetStatValue ( CE_StatDefOf . MeleePenetrationFactor ) ?? 1f : 0f
170+ ) ;
171+ totalAveragePenBlunt = meleeVerbs . AverageWeighted (
172+ verbEntry => verbEntry . GetSelectionWeight ( null ) ,
173+ verbEntry => verbEntry . verb . tool is ToolCE tool ? tool . armorPenetrationBlunt * otherFactors * verbEntry . verb . EquipmentSource ? . GetStatValue ( CE_StatDefOf . MeleePenetrationFactor ) ?? 1f : 0f
174+ ) ;
112175 }
113- float totalAveragePenSharp = 0f ;
114- float totalAveragePenBlunt = 0f ;
115- foreach ( ToolCE tool in tools )
176+ else
116177 {
117- var weightFactor = tool . chanceFactor / totalSelectionWeight ;
118- var otherFactors = GetOtherFactors ( optionalReq ) . Aggregate ( 1f , ( x , y ) => x * y ) ;
119- totalAveragePenSharp += weightFactor * tool . armorPenetrationSharp * otherFactors ;
120- totalAveragePenBlunt += weightFactor * tool . armorPenetrationBlunt * otherFactors ;
178+ var verbPropsWithSource = AllMeleeVerbPropsWithSource ( thingDef ) ;
179+ totalAveragePenSharp = verbPropsWithSource . AverageWeighted (
180+ vps => AdjustedMeleeSelectionWeight ( vps , pawn , req ) ,
181+ vps => vps . tool is ToolCE tool ? tool . armorPenetrationSharp * otherFactors : 0f
182+ ) ;
183+ totalAveragePenBlunt = verbPropsWithSource . AverageWeighted (
184+ vps => AdjustedMeleeSelectionWeight ( vps , pawn , req ) ,
185+ vps => vps . tool is ToolCE tool ? tool . armorPenetrationBlunt * otherFactors : 0f
186+ ) ;
187+
188+ var penetrationFactor = GetPenetrationFactor ( req ) ;
189+
190+ totalAveragePenSharp *= penetrationFactor ;
191+ totalAveragePenBlunt *= penetrationFactor ;
121192 }
122- var penetrationFactor = GetPenetrationFactor ( optionalReq ) ;
123- var skillFactor = GetSkillFactor ( optionalReq ) ;
124193
125- return ( totalAveragePenSharp * penetrationFactor * skillFactor ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) + " " + "CE_mmRHA" . Translate ( )
194+ return ( totalAveragePenSharp * skillFactor ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) + " " + "CE_mmRHA" . Translate ( )
126195 + ", "
127- + ( totalAveragePenBlunt * penetrationFactor * skillFactor ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) + " " + "CE_MPa" . Translate ( ) ;
196+ + ( totalAveragePenBlunt * skillFactor ) . ToStringByStyle ( ToStringStyle . FloatMaxTwo ) + " " + "CE_MPa" . Translate ( ) ;
128197 }
129198
130199 private float GetPenetrationFactor ( StatRequest req )
@@ -144,30 +213,23 @@ private float GetPenetrationFactor(StatRequest req)
144213 }
145214 public const float skillFactorPerLevel = ( 25f / 19f ) / 100f ;
146215 public const float powerForOtherFactors = 0.75f ;
147- private float GetSkillFactor ( StatRequest req )
216+ private float GetSkillFactor ( Pawn pawn )
148217 {
149218 var skillFactor = 1f ;
150- if ( req . Thing is Pawn pawn && pawn . skills != null )
219+ if ( pawn ? . skills != null )
151220 {
152221 skillFactor += skillFactorPerLevel * ( pawn . skills . GetSkill ( SkillDefOf . Melee ) . Level - 1 ) ;
153222 }
154- else
155- {
156- var thingHolder = ( req . Thing ? . ParentHolder as Pawn_EquipmentTracker ) ? . pawn ;
157- if ( thingHolder != null && thingHolder . skills != null )
158- {
159- skillFactor += skillFactorPerLevel * ( thingHolder . skills . GetSkill ( SkillDefOf . Melee ) . Level - 1 ) ;
160- }
161- }
162223 return skillFactor ;
163224 }
164- private IEnumerable < float > GetOtherFactors ( StatRequest req )
225+ private float GetOtherFactors ( Pawn pawn )
165226 {
166- var pawn = req . Thing as Pawn ?? ( req . Thing ? . ParentHolder as Pawn_EquipmentTracker ) ? . pawn ;
167227 if ( pawn != null )
168228 {
169- yield return Mathf . Pow ( pawn . ageTracker . CurLifeStage . meleeDamageFactor , powerForOtherFactors ) ;
170- yield return Mathf . Pow ( pawn . GetStatValue ( StatDefOf . MeleeDamageFactor , true , - 1 ) , powerForOtherFactors ) ;
229+ return Mathf . Pow ( pawn . ageTracker . CurLifeStage . meleeDamageFactor , powerForOtherFactors ) *
230+ Mathf . Pow ( pawn . GetStatValue ( StatDefOf . MeleeDamageFactor , true , - 1 ) , powerForOtherFactors ) ;
171231 }
232+
233+ return 1f ;
172234 }
173235}
0 commit comments