@@ -66,11 +66,24 @@ void CCustomOutfit::Load(LPCSTR section)
66
66
m_HitTypeProtection[ALife::eHitTypeTelepatic] = pSettings->r_float (section, " telepatic_protection" );
67
67
m_HitTypeProtection[ALife::eHitTypeChemicalBurn] = pSettings->r_float (section, " chemical_burn_protection" );
68
68
m_HitTypeProtection[ALife::eHitTypeExplosion] = pSettings->r_float (section, " explosion_protection" );
69
- m_HitTypeProtection[ALife::eHitTypeFireWound] = 0 . f ; // pSettings->r_float (section,"fire_wound_protection");
69
+ m_HitTypeProtection[ALife::eHitTypeFireWound] = pSettings->read_if_exists < float > (section, " fire_wound_protection" , 0 . 0f );
70
70
m_HitTypeProtection[ALife::eHitTypePhysicStrike] = pSettings->read_if_exists <float >(
71
71
section, " physic_strike_protection" , m_HitTypeProtection[ALife::eHitTypeStrike]);
72
72
m_HitTypeProtection[ALife::eHitTypeLightBurn] = m_HitTypeProtection[ALife::eHitTypeBurn];
73
- m_boneProtection->m_fHitFracActor = pSettings->read_if_exists <float >(section, " hit_fraction_actor" , 0 .1f );
73
+
74
+ if (pSettings->line_exist (section, " hit_fraction_actor" ))
75
+ {
76
+ m_boneProtection->m_fHitFrac = pSettings->r_float (section, " hit_fraction_actor" );
77
+
78
+ // Since hit_fraction_actor exists both in CS and COP, but fire_wound_protection was removed in COP,
79
+ // We can use this hacky solution to determine which damage formula to use.
80
+ // It not robust for mods, because they can have fire_wound_protection in configs, despite that
81
+ // original COP engine doesn't read it.
82
+ if (pSettings->line_exist (section, " fire_wound_protection" ))
83
+ m_boneProtection->m_hitFracType = SBoneProtections::HitFractionActorCS;
84
+ else
85
+ m_boneProtection->m_hitFracType = SBoneProtections::HitFractionActorCOP;
86
+ }
74
87
75
88
if (pSettings->line_exist (section, " nightvision_sect" ))
76
89
m_NightVisionSect = pSettings->r_string (section, " nightvision_sect" );
@@ -124,14 +137,23 @@ void CCustomOutfit::Hit(float hit_power, ALife::EHitType hit_type)
124
137
125
138
float CCustomOutfit::GetDefHitTypeProtection (ALife::EHitType hit_type) const
126
139
{
127
- return m_HitTypeProtection[hit_type] * GetCondition ();
140
+ const float base = m_HitTypeProtection[hit_type] * GetCondition ();
141
+
142
+ if (m_boneProtection->m_hitFracType == SBoneProtections::HitFraction)
143
+ return 1 .0f - base; // SOC
144
+
145
+ return base; // CS/COP
128
146
}
129
147
130
148
float CCustomOutfit::GetHitTypeProtection (ALife::EHitType hit_type, s16 element) const
131
149
{
132
- float fBase = m_HitTypeProtection[hit_type] * GetCondition ();
133
- float bone = m_boneProtection->getBoneProtection (element);
134
- return fBase * bone;
150
+ const float base = m_HitTypeProtection[hit_type] * GetCondition ();
151
+ const float bone = m_boneProtection->getBoneProtection (element);
152
+
153
+ if (m_boneProtection->m_hitFracType == SBoneProtections::HitFraction)
154
+ return 1 .0f - base * bone; // SOC
155
+
156
+ return base * bone; // CS/COP
135
157
}
136
158
137
159
float CCustomOutfit::GetBoneArmor (s16 element) const
@@ -142,51 +164,131 @@ float CCustomOutfit::GetBoneArmor(s16 element) const
142
164
float CCustomOutfit::HitThroughArmor (float hit_power, s16 element, float ap, bool & add_wound, ALife::EHitType hit_type)
143
165
{
144
166
float NewHitPower = hit_power;
145
- if (hit_type == ALife::eHitTypeFireWound)
146
- {
147
- float ba = GetBoneArmor (element);
148
- if (ba < 0 .0f )
149
- return NewHitPower;
150
167
151
- float BoneArmor = ba * GetCondition ();
152
- if (/* !fis_zero(ba, EPS) && */ (ap > BoneArmor))
168
+ switch (m_boneProtection->m_hitFracType )
169
+ {
170
+ default :
171
+ case SBoneProtections::HitFractionActorCOP:
172
+ {
173
+ if (hit_type == ALife::eHitTypeFireWound)
153
174
{
154
- // пуля пробила бронь
155
- if (!IsGameTypeSingle ())
175
+ const float ba = GetBoneArmor (element);
176
+ if (ba < 0 .0f )
177
+ return NewHitPower;
178
+
179
+ float BoneArmor = ba * GetCondition ();
180
+ if (/* !fis_zero(ba, EPS) &&*/ ap > BoneArmor)
156
181
{
157
- float hit_fraction = (ap - BoneArmor) / ap;
158
- if (hit_fraction < m_boneProtection->m_fHitFracActor )
159
- hit_fraction = m_boneProtection->m_fHitFracActor ;
182
+ // пуля пробила бронь
183
+ if (!IsGameTypeSingle ())
184
+ {
185
+ float hit_fraction = (ap - BoneArmor) / ap;
186
+ if (hit_fraction < m_boneProtection->m_fHitFrac )
187
+ hit_fraction = m_boneProtection->m_fHitFrac ;
188
+
189
+ NewHitPower *= hit_fraction;
190
+ NewHitPower *= m_boneProtection->getBoneProtection (element);
191
+ }
160
192
161
- NewHitPower *= hit_fraction;
162
- NewHitPower *= m_boneProtection->getBoneProtection (element);
193
+ VERIFY (NewHitPower >= 0 .0f );
163
194
}
195
+ else
196
+ {
197
+ // пуля НЕ пробила бронь
198
+ NewHitPower *= m_boneProtection->m_fHitFrac ;
199
+ add_wound = false ; // раны нет
200
+ }
201
+ }
202
+ else
203
+ {
204
+ float one = 0 .1f ;
205
+ if (hit_type == ALife::eHitTypeStrike ||
206
+ hit_type == ALife::eHitTypeWound ||
207
+ hit_type == ALife::eHitTypeWound_2 ||
208
+ hit_type == ALife::eHitTypeExplosion)
209
+ {
210
+ one = 1 .0f ;
211
+ }
212
+ const float protect = GetDefHitTypeProtection (hit_type);
213
+ NewHitPower -= protect * one;
164
214
165
- VERIFY (NewHitPower >= 0 .0f );
215
+ if (NewHitPower < 0 .f )
216
+ NewHitPower = 0 .f ;
217
+ }
218
+
219
+ // увеличить изношенность костюма
220
+ Hit (hit_power, hit_type);
221
+ break ;
222
+ }
223
+ case SBoneProtections::HitFractionActorCS:
224
+ {
225
+ if (hit_type == ALife::eHitTypeFireWound)
226
+ {
227
+ const float BoneArmor = m_boneProtection->getBoneArmor (element) * GetCondition ();
228
+
229
+ if (ap > EPS && ap > BoneArmor)
230
+ {
231
+ // пуля пробила бронь
232
+ const float d_ap = ap - BoneArmor;
233
+ NewHitPower *= (d_ap / ap);
234
+
235
+ if (NewHitPower < m_boneProtection->m_fHitFrac )
236
+ NewHitPower = m_boneProtection->m_fHitFrac ;
237
+
238
+ if (!IsGameTypeSingle ())
239
+ {
240
+ NewHitPower *= m_boneProtection->getBoneProtection (element);
241
+ }
242
+
243
+ if (NewHitPower < 0 .0f )
244
+ NewHitPower = 0 .0f ;
245
+ }
246
+ else
247
+ {
248
+ // пуля НЕ пробила бронь
249
+ NewHitPower *= m_boneProtection->m_fHitFrac ;
250
+ add_wound = false ; // раны нет
251
+ }
166
252
}
167
253
else
168
254
{
169
- // пуля НЕ пробила бронь
170
- NewHitPower *= m_boneProtection->m_fHitFracActor ;
171
- add_wound = false ; // раны нет
255
+ float one = 0 .1f ;
256
+ if (hit_type == ALife::eHitTypeWound ||
257
+ hit_type == ALife::eHitTypeWound_2 ||
258
+ hit_type == ALife::eHitTypeExplosion)
259
+ {
260
+ one = 1 .0f ;
261
+ }
262
+
263
+ const float protect = GetHitTypeProtection (hit_type, element);
264
+ NewHitPower -= protect * one;
265
+ if (NewHitPower < 0 .0f )
266
+ NewHitPower = 0 .0f ;
172
267
}
268
+
269
+ // увеличить изношенность костюма
270
+ Hit (NewHitPower, hit_type);
271
+ break ;
173
272
}
174
- else
273
+ case SBoneProtections::HitFraction:
175
274
{
176
- float one = 0 .1f ;
177
- if (hit_type == ALife::eHitTypeStrike || hit_type == ALife::eHitTypeWound ||
178
- hit_type == ALife::eHitTypeWound_2 || hit_type == ALife::eHitTypeExplosion)
275
+ if (hit_type == ALife::eHitTypeFireWound)
179
276
{
180
- one = 1 .0f ;
277
+ const float BoneArmor = m_boneProtection->getBoneArmor (element) * GetCondition () * (1 - ap);
278
+ NewHitPower -= BoneArmor;
279
+ if (NewHitPower < hit_power * m_boneProtection->m_fHitFrac )
280
+ NewHitPower = hit_power * m_boneProtection->m_fHitFrac ;
281
+ }
282
+ else
283
+ {
284
+ NewHitPower *= GetHitTypeProtection (hit_type, element);
181
285
}
182
- float protect = GetDefHitTypeProtection (hit_type);
183
- NewHitPower -= protect * one;
184
286
185
- if (NewHitPower < 0 .f )
186
- NewHitPower = 0 .f ;
287
+ // увеличить изношенность костюма
288
+ Hit (hit_power, hit_type);
289
+ break ;
187
290
}
188
- // увеличить изношенность костюма
189
- Hit (hit_power, hit_type);
291
+ } // switch (m_boneProtection->m_hitFracType)
190
292
191
293
return NewHitPower;
192
294
}
@@ -285,6 +387,21 @@ u32 CCustomOutfit::ef_equipment_type() const
285
387
return m_ef_equipment_type;
286
388
}
287
389
390
+ float CCustomOutfit::GetPowerLoss () const
391
+ {
392
+ // Hit fraction and power loss are unrelated,
393
+ // but it's the only way we can distinguish between SOC/CS and COP.
394
+ // Sorry.
395
+ if (m_boneProtection->m_hitFracType != SBoneProtections::HitFractionActorCOP)
396
+ {
397
+ if (m_fPowerLoss < 1 && GetCondition () <= 0 )
398
+ {
399
+ return 1 .0f ;
400
+ }
401
+ }
402
+ return m_fPowerLoss;
403
+ };
404
+
288
405
bool CCustomOutfit::install_upgrade_impl (LPCSTR section, bool test)
289
406
{
290
407
bool result = inherited::install_upgrade_impl (section, test);
@@ -326,10 +443,13 @@ bool CCustomOutfit::install_upgrade_impl(LPCSTR section, bool test)
326
443
result2 = process_if_exists_set (section, " bones_koeff_protection_add" , &CInifile::r_string, str, test);
327
444
if (result2 && !test)
328
445
AddBonesProtection (str);
329
-
330
446
result |= result2;
331
- result |=
332
- process_if_exists (section, " hit_fraction_actor" , &CInifile::r_float, m_boneProtection->m_fHitFracActor , test);
447
+
448
+ if (m_boneProtection->m_hitFracType == SBoneProtections::HitFractionActorCS ||
449
+ m_boneProtection->m_hitFracType == SBoneProtections::HitFractionActorCOP)
450
+ {
451
+ result |= process_if_exists (section, " hit_fraction_actor" , &CInifile::r_float, m_boneProtection->m_fHitFrac , test);
452
+ }
333
453
334
454
result |= process_if_exists (section, " additional_inventory_weight" , &CInifile::r_float, m_additional_weight, test);
335
455
result |=
0 commit comments