Antal1987
Warlord
By request of some forum's participants I'm sharing code of the function which calculates corruption and waste.
First of all, that function is multipurpose. It can compute commercial corruption or production waste depending on 3-rd parameter (Corruption_Type: 0 - Commerce, 1 - Production). 2-nd parameter takes origin value of economic component (total commerce or total production).
It returns an integer value, calculated from the origin value of the same economic type. It represents resulting corruption value of commece/production depending on corruption type.
The function was decompiled by IDA and Hex-Rays plugin. That's why it has many semantic differences and weird schemes
Well, here is the code:
It also has a call to function class_Leader::f3(class Leader * this). Here is the code:
What is _this->field_30 I've no idea...
In summary I can tell the only thing: it's really complicated
But it can be fixed in very simple way. I can just make it return 0 right at the begining.
First of all, that function is multipurpose. It can compute commercial corruption or production waste depending on 3-rd parameter (Corruption_Type: 0 - Commerce, 1 - Production). 2-nd parameter takes origin value of economic component (total commerce or total production).
It returns an integer value, calculated from the origin value of the same economic type. It represents resulting corruption value of commece/production depending on corruption type.
The function was decompiled by IDA and Hex-Rays plugin. That's why it has many semantic differences and weird schemes
Well, here is the code:
Code:
// Corruption_Type:
// 0 - Commerce Corruption
// 1 - Production Loss
int __thiscall class_City::Calculate_Corruption(class_City *this, int Origin_Value, char Corruption_Type)
{
int _Origin_Value; // esi@1
int result; // eax@2
int v5; // eax@5
int _CapitalID_1; // ecx@5
void *v7; // ecx@8
int _Reduce_Corruption_Value; // ebx@12
int _ImprovementID; // esi@12
int v10; // edi@13
int v11; // eax@16
int _Reduce_Corruption_Value2; // ebp@19
int v13; // esi@21
__int64 v14; // qax@21
int v15; // esi@21
int _Max_Distance1; // ebx@24
int _ImprovementID2; // ebp@24
struct_Base_List_Item *_Cities; // esi@25
int _ImprovementType_Offset; // ecx@25
int _Impr_GovID; // eax@26
int _CityID1; // eax@30
void *v22; // eax@33
class_City *_Wonder_City; // eax@34
int _CityID2; // eax@36
void *v25; // eax@39
int _Small_Wonder_Distance; // eax@45
int _Corruption_And_Waste2; // ebp@48
int v28; // eax@48
int _Reduce_Distance_Value; // esi@48
int _Capital_City_ID; // eax@51
int _CivID; // ST0C_4@52
class_City *_Capital_City_2; // eax@52
int v33; // eax@54
int v34; // ecx@65
__int64 _Cities_Count; // qax@68
void *v36; // eax@73
class_City *_City2; // ebp@74
int v38; // esi@77
int v39; // eax@77
int v40; // ecx@77
int v41; // eax@77
int v42; // edi@78
__int64 v43; // qax@80
int _Distance_2; // ecx@80
int v45; // eax@82
int v46; // eax@83
int v47; // ecx@85
int v48; // esi@85
class_City *v49; // edi@87
int v50; // eax@87
int v51; // edx@87
int v52; // ecx@97
int v53; // esi@97
int v54; // eax@99
int v55; // edx@99
int v56; // ecx@109
int v57; // eax@111
int v58; // eax@116
int v59; // eax@117
int v60; // ecx@119
signed int v61; // eax@121
int v62; // ecx@126
signed int v63; // eax@128
int v64; // ecx@133
signed int v65; // eax@135
int v66; // eax@141
int _Citizens_Corruption; // edi@143
int v68; // ecx@143
int v69; // eax@143
int v70; // esi@143
class_Citizen_Info *v71; // ebx@144
class_Citizen_Body *v72; // edx@148
class_Citizen *v73; // edx@149
int v74; // eax@154
signed int _Total_Corruption; // ecx@156
class_City *_City; // [sp+8h] [bp-20h]@1
int _Reduce_Corruption_Value3; // [sp+Ch] [bp-1Ch]@19
int v78; // [sp+10h] [bp-18h]@25
int _Ratio2; // [sp+10h] [bp-18h]@68
class_City *_Capital1; // [sp+14h] [bp-14h]@9
int v81; // [sp+18h] [bp-10h]@21
int _Civ_GovID; // [sp+1Ch] [bp-Ch]@11
int _Corruption_And_Waste; // [sp+20h] [bp-8h]@11
int _Ratio1; // [sp+20h] [bp-8h]@67
int _Distance_Capital; // [sp+24h] [bp-4h]@24
int Corruption_Typea; // [sp+30h] [bp+8h]@69
_Origin_Value = Origin_Value;
_City = this;
if ( Origin_Value <= 0 )
return 0;
if ( Corruption_Type && (this->Body.Status & 1) == 1 )
return _Origin_Value;
v5 = LOBYTE(this->Body.CivID);
_CapitalID_1 = Civilizations[v5].CapitalID;
if ( !Cities.Items
|| _CapitalID_1 < 0
|| _CapitalID_1 > Cities.LastIndex
|| (v7 = Cities.Items[_CapitalID_1].Object) == 0
|| (_Capital1 = (v7 - 28), v7 == 28) )
return 0;
_Civ_GovID = Civilizations[v5].GovenmentType;
_Corruption_And_Waste = BIC_Data.Governments[_Civ_GovID].CurruptionAndWaste;
if ( BIC_Data.Governments[_Civ_GovID].CurruptionAndWaste == CWT_Catastrophic )
return _Origin_Value;
_Reduce_Corruption_Value = 0;
_ImprovementID = 0;
if ( BIC_Data.ImprovementsCount > 0 )
{
v10 = 0;
do
{
if ( class_City::Has_Improvement(_City, _ImprovementID, 1) )
{
if ( !class_City::Check_Improvement_Obsolete(_City, _ImprovementID) )
{
v11 = BIC_Data.Improvements[v10].ImprovementFlags;
if ( BYTE1(v11) & ITF_B1_Reduces_Corruption )
++_Reduce_Corruption_Value;
}
}
++_ImprovementID;
++v10;
}
while ( _ImprovementID < BIC_Data.ImprovementsCount );
}
_Reduce_Corruption_Value2 = _Reduce_Corruption_Value;
_Reduce_Corruption_Value3 = _Reduce_Corruption_Value;
if ( _City->Body.ID == Civilizations[LOBYTE(_City->Body.CivID)].CapitalID )
{
_Reduce_Corruption_Value2 = _Reduce_Corruption_Value + 10;
_Reduce_Corruption_Value3 = _Reduce_Corruption_Value + 10;
}
v13 = class_Leader::f3(&Civilizations[LOBYTE(_City->Body.CivID)]);
v14 = _Reduce_Corruption_Value2 * BIC_Data.WorldSizes[BIC_Data.Map.World.World_Size].OptimalCityCount;
v15 = (((BYTE4(v14) & 3) + v14) >> 2) + v13;
v81 = v15;
if ( Corruption_Type && (_City->Body.Status & 2) == 2 )
v81 = BIC_Data.WorldSizes[BIC_Data.Map.World.World_Size].OptimalCityCount / 4 + v15;
_Max_Distance1 = class_Map::Get_Distance(
&BIC_Data.Map,
_Capital1->Body.X,
_Capital1->Body.Y,
_City->Body.X,
_City->Body.Y);
_ImprovementID2 = 0;
_Distance_Capital = _Max_Distance1;
if ( BIC_Data.ImprovementsCount > 0 )
{
_Cities = Cities.Items;
_ImprovementType_Offset = 0;
v78 = 0;
do
{
_Impr_GovID = *(&BIC_Data.Improvements->GovernmentID + _ImprovementType_Offset);
if ( (_Impr_GovID == _Civ_GovID || _Impr_GovID == -1)
&& *(&BIC_Data.Improvements->SmallWonderFlags + _ImprovementType_Offset) & ITSW_Reduces_Corruption )
{ // Check if Impr is Small Wonder
if ( (*(&BIC_Data.Improvements->Characterictics + _ImprovementType_Offset) & ITC_Small_Wonder) == ITC_Small_Wonder )
{
_CityID1 = Civilizations[LOBYTE(_City->Body.CivID)].Small_Wonders[_ImprovementID2];
if ( _Cities )
{
if ( _CityID1 >= 0 )
{
if ( _CityID1 <= Cities.LastIndex )
{
v22 = _Cities[_CityID1].Object;
if ( v22 )
{
_Wonder_City = (v22 - 28);
LABEL_42:
if ( _Wonder_City )
{
if ( _Wonder_City == _City )
_Reduce_Corruption_Value3 += 7;// Hard coded value for corruption reduring
_Small_Wonder_Distance = class_Map::Get_Distance(
&BIC_Data.Map,
_Wonder_City->Body.X,
_Wonder_City->Body.Y,
_City->Body.X,
_City->Body.Y);
_Cities = Cities.Items;
if ( _Small_Wonder_Distance < _Max_Distance1 )
_Max_Distance1 = _Small_Wonder_Distance;
}
goto LABEL_47;
}
}
}
}
}
else
{ // Check if Impr is Wonder
if ( (*(&BIC_Data.Improvements->Characterictics + _ImprovementType_Offset) & ITC_Wonder) == ITC_Wonder )
{
_CityID2 = class_Game::Get_Wonder_City_ID(&Game, _ImprovementID2);
_Cities = Cities.Items;
if ( Cities.Items )
{
if ( _CityID2 >= 0 )
{
if ( _CityID2 <= Cities.LastIndex )
{
v25 = Cities.Items[_CityID2].Object;
if ( v25 )
{
_Wonder_City = (v25 - 28);
if ( _Wonder_City )
{
if ( LOBYTE(_Wonder_City->Body.CivID) == LOBYTE(_City->Body.CivID) )
goto LABEL_42;
}
}
}
}
}
}
}
}
LABEL_47:
++_ImprovementID2;
_ImprovementType_Offset = v78 + 272;
v78 += 272;
}
while ( _ImprovementID2 < BIC_Data.ImprovementsCount );
}
_Corruption_And_Waste2 = _Corruption_And_Waste;
v28 = (BIC_Data.Map.Width + BIC_Data.Map.Height) / 4;
_Reduce_Distance_Value = (BIC_Data.Map.Width + BIC_Data.Map.Height) / 4;
switch ( _Corruption_And_Waste )
{
case CWT_Minimal:
v28 = 3 * _Max_Distance1;
goto LABEL_50;
case CWT_Communal:
LABEL_50:
_Reduce_Distance_Value = v28 / 4;
break;
default:
break;
case CWT_Nuisance:
case CWT_Problematic:
_Reduce_Distance_Value = _Max_Distance1;
break;
case CWT_Rampant:
_Reduce_Distance_Value = 3 * _Max_Distance1 / 2;
break;
}
_Capital_City_ID = Civilizations[LOBYTE(_City->Body.CivID)].CapitalID;
if ( _Capital_City_ID == -1
|| (_CivID = LOBYTE(_City->Body.CivID),
_Capital_City_2 = class_Base_List::Get_Item(&Cities, _Capital_City_ID),
!class_Trade_Net::Check_City_Connected_To_Target_City(&Trade_Net, _City, _Capital_City_2, _CivID)) )
_Reduce_Distance_Value = 5 * _Reduce_Distance_Value / 4;
v33 = (BIC_Data.Map.Height + BIC_Data.Map.Width) / 4;
if ( v33 >= 2 )
{
if ( _Reduce_Distance_Value >= 2 )
{
if ( _Reduce_Distance_Value > v33 )
_Reduce_Distance_Value = (BIC_Data.Map.Height + BIC_Data.Map.Width) / 4;
}
else
{
_Reduce_Distance_Value = 2;
}
}
else
{
_Reduce_Distance_Value = 2;
}
if ( Corruption_Type && (_City->Body.Status & 2) == 2 )
_Reduce_Distance_Value = (_Reduce_Distance_Value + 1) / 2;
v34 = _Reduce_Corruption_Value3;
if ( _Reduce_Corruption_Value3 > 0 )
{
do
{
--v34;
_Reduce_Distance_Value = (_Reduce_Distance_Value + 1) / 2;
}
while ( v34 );
}
_Ratio1 = Origin_Value * _Reduce_Distance_Value;
if ( _Corruption_And_Waste2 == CWT_Communal )
{
_Cities_Count = Civilizations[LOBYTE(_City->Body.CivID)].Cities_Count;
_Ratio2 = (_Cities_Count - HIDWORD(_Cities_Count)) >> 1;
goto LABEL_141;
}
_Ratio2 = 0;
Corruption_Typea = 0;
if ( Cities.LastIndex >= 0 )
{
while ( 1 )
{
if ( !Cities.Items
|| Corruption_Typea < 0
|| Corruption_Typea > Cities.LastIndex
|| (v36 = Cities.Items[Corruption_Typea].Object) == 0
|| (_City2 = (v36 - 28), v36 == 28)
|| LOBYTE(_City2->Body.CivID) != LOBYTE(_City->Body.CivID)
|| _City2 == _City )
goto LABEL_140;
v38 = abs(class_Map::Get_DX(&BIC_Data.Map, _Capital1->Body.X, _City2->Body.X));
v39 = class_Map::Get_DY(&BIC_Data.Map, _Capital1->Body.Y, _City2->Body.Y);
v40 = v38;
v41 = abs(v39);
if ( v38 > v41 || (v40 = v41, v42 = v38, v38 >= v41) )
v42 = v41;
v43 = (v38 + v41) / 2 - v42 + 1;
_Distance_2 = v40 - ((v43 - HIDWORD(v43)) >> 1);
if ( _Distance_2 < _Distance_Capital )
break;
if ( _Distance_2 == _Distance_Capital )
{
v45 = _City2->Body.Found_Date.BaseTimeUnit;
if ( v45 )
{
v46 = v45 - 1;
if ( v46 )
{
if ( v46 == 1 )
{
v47 = _City2->Body.Found_Date.Year;
v48 = _City2->Body.Found_Date.Year;
if ( !v47 )
v48 = 1;
v49 = _City;
v50 = _City->Body.Found_Date.Year;
v51 = _City->Body.Found_Date.Year;
if ( !v50 )
v51 = 1;
if ( v48 == v51 )
break;
if ( !v47 )
v47 = 1;
if ( !v50 )
v50 = 1;
if ( v47 == v50 && _City2->Body.Found_Date.Week + 1 == _City->Body.Found_Date.Week + 1 )
break;
}
else
{
v49 = _City;
}
}
else
{
v52 = _City2->Body.Found_Date.Year;
v53 = _City2->Body.Found_Date.Year;
if ( !v52 )
v53 = 1;
v49 = _City;
v54 = _City->Body.Found_Date.Year;
v55 = _City->Body.Found_Date.Year;
if ( !v54 )
v55 = 1;
if ( v53 < v55 )
break;
if ( !v52 )
v52 = 1;
if ( !v54 )
v54 = 1;
if ( v52 == v54 && _City2->Body.Found_Date.Month + 1 < _City->Body.Found_Date.Month + 1 )
break;
}
}
else
{
v56 = _City2->Body.Found_Date.Year;
if ( !_City2->Body.Found_Date.Year )
v56 = 1;
v49 = _City;
v57 = _City->Body.Found_Date.Year;
if ( !v57 )
v57 = 1;
if ( v56 < v57 )
break;
}
v58 = _City2->Body.Found_Date.BaseTimeUnit;
if ( v58 )
{
v59 = v58 - 1;
if ( v59 )
{
if ( v59 != 1 )
goto LABEL_140;
v60 = _City2->Body.Found_Date.Year;
if ( !_City2->Body.Found_Date.Year )
v60 = 1;
v61 = v49->Body.Found_Date.Year;
if ( !v61 )
v61 = 1;
if ( v60 != v61 || _City2->Body.Found_Date.Week + 1 != v49->Body.Found_Date.Week + 1 )
goto LABEL_140;
}
else
{
v62 = _City2->Body.Found_Date.Year;
if ( !_City2->Body.Found_Date.Year )
v62 = 1;
v63 = v49->Body.Found_Date.Year;
if ( !v63 )
v63 = 1;
if ( v62 != v63 || _City2->Body.Found_Date.Month + 1 != v49->Body.Found_Date.Month + 1 )
goto LABEL_140;
}
}
else
{
v64 = _City2->Body.Found_Date.Year;
if ( !_City2->Body.Found_Date.Year )
v64 = 1;
v65 = v49->Body.Found_Date.Year;
if ( !v65 )
v65 = 1;
if ( !(v64 == v65) )
goto LABEL_140;
}
if ( _City2->Body.ID < v49->Body.ID )
break;
}
LABEL_140:
++Corruption_Typea;
if ( Corruption_Typea > Cities.LastIndex )
goto LABEL_141;
}
++_Ratio2;
goto LABEL_140;
}
LABEL_141:
v66 = _Ratio2;
if ( _Ratio2 >= v81 )
v66 = 2 * _Ratio2 - v81;
_Citizens_Corruption = 0;
v68 = 0;
v69 = (v81 * (BIC_Data.Map.Width + BIC_Data.Map.Height) / 4 / 2
+ v81 * _Ratio1
+ (Origin_Value * v66 + 1) / 2 * (BIC_Data.Map.Width + BIC_Data.Map.Height) / 4)
/ (v81
* (BIC_Data.Map.Width + BIC_Data.Map.Height)
/ 4);
v70 = _City->Body.Citizens.LastIndex;
if ( v70 >= 0 )
{
v71 = _City->Body.Citizens.Items;
do
{
if ( v71 )
{
if ( v68 >= 0 )
{
if ( v68 <= _City->Body.Citizens.LastIndex )
{
v72 = v71[v68].Body;
if ( v72 )
{
v73 = (v72 - 28);
if ( v73 )
{
if ( !LOBYTE(v73->TileIndex) )
_Citizens_Corruption += BIC_Data.CitizenTypes[v73->WorkerType].Corruption;
}
}
}
}
}
++v68;
}
while ( v68 <= v70 );
}
if ( _Citizens_Corruption < v69 )
v74 = v69 - _Citizens_Corruption;
else
v74 = 0;
_Origin_Value = v74
* BIC_Data.DifficultyLevels[Civilizations[LOBYTE(_City->Body.CivID)].field_30].Corruption_Level
/ 100;
_Total_Corruption = Origin_Value * (((9 - _Reduce_Corruption_Value3 < 0) - 1) & (9 - _Reduce_Corruption_Value3));
if ( _Total_Corruption / 10 < 0 )
return 0;
if ( _Origin_Value < 0 )
return 0;
result = _Total_Corruption / 10;
if ( _Origin_Value <= _Total_Corruption / 10 )
return _Origin_Value;
return result;
}
It also has a call to function class_Leader::f3(class Leader * this). Here is the code:
Code:
int __thiscall class_Leader::f3(class_Leader *this)
{
class_Leader *_this; // ebx@1
int _Optimal_City_Count; // ebp@1
int _Ratio; // edi@1
int _Ratio2; // eax@9
signed int _Ratio3; // ecx@15
int result; // eax@15
_this = this;
_Optimal_City_Count = BIC_Data.WorldSizes[BIC_Data.Map.World.World_Size].OptimalCityCount;
_Ratio = 3
* BIC_Data.WorldSizes[BIC_Data.Map.World.World_Size].OptimalCityCount
* class_Leader::Count_Small_Wonders_With_Flag(this, ITSW_Reduces_Corruption, 0)
/ (BIC_Data.Governments[this->GovenmentType].CurruptionAndWaste != CWT_Communal ? 8 : 1)
+ BIC_Data.WorldSizes[BIC_Data.Map.World.World_Size].OptimalCityCount;
if ( BIC_Data.Races[_this->RaceID].vtable->CheckBonus(&BIC_Data.Races[_this->RaceID], RB_Commercial) )
_Ratio += _Optimal_City_Count / 4;
switch ( BIC_Data.Governments[_this->GovenmentType].CurruptionAndWaste )
{
case CWT_Minimal:
case CWT_Nuisance:
_Ratio += _Optimal_City_Count / 8;
break;
case CWT_Problematic:
_Ratio += _Optimal_City_Count / 16;
break;
case CWT_Communal:
_Ratio += 2 * _Optimal_City_Count;
break;
default:
break;
}
if ( !(Global_Civ_Flags2 & (1 << _this->ID)) )
{
if ( Game_Difficulty_Level <= 4 )
{
if ( Game_Difficulty_Level <= 3 )
{
if ( Game_Difficulty_Level <= 2 )
goto LABEL_15;
_Ratio2 = _Optimal_City_Count / 8;
}
else
{
_Ratio2 = _Optimal_City_Count / 4;
}
}
else
{
_Ratio2 = _Optimal_City_Count / 2;
}
_Ratio += _Ratio2;
}
LABEL_15:
_Ratio3 = _Ratio * BIC_Data.DifficultyLevels[_this->field_30].Optimal_Cities;
result = 1;
if ( _Ratio3 / 100 >= 1 )
result = _Ratio3 / 100;
return result;
}
What is _this->field_30 I've no idea...
In summary I can tell the only thing: it's really complicated
But it can be fixed in very simple way. I can just make it return 0 right at the begining.