Skip to content

Commit bd871c6

Browse files
committed
Track body parts shot and side of unit shot
1 parent 1ca048a commit bd871c6

6 files changed

Lines changed: 109 additions & 12 deletions

File tree

bin/data/Ruleset/Commendations.rul

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ extraStrings:
289289
STR_MEDAL_NIKE_CROSS_DESCRIPTION: "Given to a soldier who single handedly killed every alien in a mission."
290290
STR_MEDAL_MERCY_CROSS_NAME: "Mercy Cross"
291291
STR_MEDAL_MERCY_CROSS_DESCRIPTION: "Given to a soldier who single handedly stunned every alien in a mission."
292+
STR_MEDAL_HEADSHOT_NAME: "Head Hunter"
293+
STR_MEDAL_HEADSHOT_DESCRIPTION: "Given to a soldier with a steady hand who has landed multiple headshots."
292294
STR_AWARD_0: "First award"
293295
STR_AWARD_1: "Second award"
294296
STR_AWARD_2: "Third award"
@@ -427,8 +429,10 @@ extraStrings:
427429
STR_MEDAL_ALIEN_BASE_ASSAULT_DESCRIPTION: "Given to a soldier who has been part of a successful alien base assault mission."
428430
STR_MEDAL_NIKE_CROSS_NAME: "Nike Cross"
429431
STR_MEDAL_NIKE_CROSS_DESCRIPTION: "Given to a soldier who single handedly killed every alien in a mission."
430-
STR_MEDAL_MERCY_CROSS_NAME: "Nike Cross"
431-
STR_MEDAL_MERCY_CROSS_DESCRIPTION: "Given to a soldier who single handedly killed every alien in a mission."
432+
STR_MEDAL_MERCY_CROSS_NAME: "Mercy Cross"
433+
STR_MEDAL_MERCY_CROSS_DESCRIPTION: "Given to a soldier who single handedly stunned every alien in a mission."
434+
STR_MEDAL_HEADSHOT_NAME: "Head Hunter"
435+
STR_MEDAL_HEADSHOT_DESCRIPTION: "Given to a soldier with a steady hand who has landed multiple headshots."
432436
STR_AWARD_0: "First award"
433437
STR_AWARD_1: "Second award"
434438
STR_AWARD_2: "Third award"
@@ -931,6 +935,7 @@ extraStrings:
931935
# totalValientCrux
932936
# totalTrapKills
933937
# isDead
938+
# totalHeadShots
934939
# The following criteria use a hardcoded noun for the name/description.
935940
# They are INCOMPATIBLE with eachother. If used together,
936941
# the commendation will be given out repeatedly.
@@ -1159,6 +1164,11 @@ commendations:
11591164
sprite: 32
11601165
criteria:
11611166
totalAllAliensStunned: [1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
1167+
- type: STR_MEDAL_HEADSHOT_NAME
1168+
description: STR_MEDAL_HEADSHOT_DESCRIPTION
1169+
sprite: 32
1170+
criteria:
1171+
totalHeadShots: [3, 6, 9, 9, 9, 9, 12, 12, 12, 12]
11621172
ufopaedia:
11631173
- id: STR_MEDAL_MILITARY_CROSS_NAME
11641174
type_id: 7
@@ -1398,6 +1408,13 @@ ufopaedia:
13981408
text: STR_MEDAL_MERCY_CROSS_MEDAL_UFOPEDIA
13991409
text_width: 164
14001410
listOrder: 6033
1411+
- id: STR_MEDAL_HEADSHOT_NAME
1412+
type_id: 7
1413+
section: STR_HEAVY_WEAPONS_PLATFORMS
1414+
image_id: NIKE_CROSS
1415+
text: STR_MEDAL_HEADSHOT_MEDAL_UFOPEDIA
1416+
text_width: 164
1417+
listOrder: 6033
14011418
# entries below move the HWPs to the Craft Section of the UFOPedia
14021419
- id: STR_TANK_CANNON
14031420
section: STR_XCOM_CRAFT_ARMAMENT

src/Battlescape/BattlescapeGame.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ void BattlescapeGame::checkForCasualties(BattleItem *murderweapon, BattleUnit *m
656656
{
657657
if (murderer->getGeoscapeSoldier() && murderer->getFaction() == FACTION_PLAYER)
658658
{
659-
murderer->getStatistics()->kills.push_back(new BattleUnitKills(killStatRank, killStatRace, killStatWeapon, killStatWeaponAmmo, victim->getFaction(), STATUS_DEAD, killStatMission, killStatTurn ));
659+
murderer->getStatistics()->kills.push_back(new BattleUnitKills(killStatRank, killStatRace, killStatWeapon, killStatWeaponAmmo, victim->getFaction(), STATUS_DEAD, killStatMission, killStatTurn, victim->getFatalShotSide(), victim->getFatalShotBodyPart() ));
660660
victim->setMurdererId(murderer->getId());
661661
}
662662
murderer->addKillCount();
@@ -745,7 +745,7 @@ void BattlescapeGame::checkForCasualties(BattleItem *murderweapon, BattleUnit *m
745745
{
746746
if (murderer && murderer->getGeoscapeSoldier() && murderer->getFaction() == FACTION_PLAYER)
747747
{
748-
murderer->getStatistics()->kills.push_back(new BattleUnitKills(killStatRank, killStatRace, killStatWeapon, killStatWeaponAmmo, victim->getFaction(), STATUS_UNCONSCIOUS, killStatMission, killStatTurn ));
748+
murderer->getStatistics()->kills.push_back(new BattleUnitKills(killStatRank, killStatRace, killStatWeapon, killStatWeaponAmmo, victim->getFaction(), STATUS_UNCONSCIOUS, killStatMission, killStatTurn, victim->getFatalShotSide(), victim->getFatalShotBodyPart() ));
749749
}
750750
if (victim && victim->getGeoscapeSoldier())
751751
{

src/Savegame/BattleUnit.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ BattleUnit::BattleUnit(Soldier *soldier, int depth) :
5757
_expBravery(0), _expReactions(0), _expFiring(0), _expThrowing(0), _expPsiSkill(0), _expPsiStrength(0), _expMelee(0),
5858
_motionPoints(0), _kills(0), _hitByFire(false), _moraleRestored(0), _coverReserve(0), _charging(0),
5959
_turnsSinceSpotted(255), _geoscapeSoldier(soldier), _unitRules(0), _rankInt(-1), _turretType(-1), _hidingForTurn(false), _respawn(false),
60-
_statistics(), _murdererId(0)
60+
_statistics(), _murdererId(0), _fatalShotSide(SIDE_FRONT), _fatalShotBodyPart(BODYPART_HEAD)
6161
{
6262
_name = soldier->getName(true);
6363
_id = soldier->getId();
@@ -149,7 +149,8 @@ BattleUnit::BattleUnit(Unit *unit, UnitFaction faction, int id, Armor *armor, in
149149
_expThrowing(0), _expPsiSkill(0), _expPsiStrength(0), _expMelee(0), _motionPoints(0), _kills(0), _hitByFire(false),
150150
_moraleRestored(0), _coverReserve(0), _charging(0), _turnsSinceSpotted(255),
151151
_armor(armor), _geoscapeSoldier(0), _unitRules(unit), _rankInt(-1),
152-
_turretType(-1), _hidingForTurn(false), _respawn(false), _statistics(), _murdererId(0)
152+
_turretType(-1), _hidingForTurn(false), _respawn(false), _statistics(), _murdererId(0),
153+
_fatalShotSide(SIDE_FRONT), _fatalShotBodyPart(BODYPART_HEAD)
153154
{
154155
_type = unit->getType();
155156
_rank = unit->getRank();
@@ -1070,6 +1071,8 @@ int BattleUnit::damage(const Position &relative, int power, ItemDamageType type,
10701071
}
10711072
}
10721073

1074+
setFatalShotInfo(side, bodypart);
1075+
10731076
return power < 0 ? 0:power;
10741077
}
10751078

@@ -2973,4 +2976,32 @@ int BattleUnit::getMurdererId() const
29732976
return _murdererId;
29742977
}
29752978

2979+
/**
2980+
* Set information on the unit's fatal blow.
2981+
* @param UnitSide unit's side that was shot.
2982+
* @param UnitBodyPart unit's body part that was shot.
2983+
*/
2984+
void BattleUnit::setFatalShotInfo(UnitSide side, UnitBodyPart bodypart)
2985+
{
2986+
_fatalShotSide = side;
2987+
_fatalShotBodyPart = bodypart;
2988+
}
2989+
2990+
/**
2991+
* Get information on the unit's fatal shot's side.
2992+
* @return UnitSide fatal shot's side.
2993+
*/
2994+
UnitSide BattleUnit::getFatalShotSide() const
2995+
{
2996+
return _fatalShotSide;
2997+
}
2998+
2999+
/**
3000+
* Get information on the unit's fatal shot's body part.
3001+
* @return UnitBodyPart fatal shot's body part.
3002+
*/
3003+
UnitBodyPart BattleUnit::getFatalShotBodyPart() const
3004+
{
3005+
return _fatalShotBodyPart;
3006+
}
29763007
}

src/Savegame/BattleUnit.h

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ struct BattleUnitKills
6262
UnitFaction faction;
6363
UnitStatus status;
6464
int mission, turn;
65+
UnitSide side;
66+
UnitBodyPart bodypart;
6567

6668
/// Functions
6769
// Make turn unique across all kills
@@ -86,6 +88,8 @@ struct BattleUnitKills
8688
faction = (UnitFaction)node["faction"].as<int>();
8789
mission = node["mission"].as<int>(mission);
8890
turn = node["turn"].as<int>(turn);
91+
side = (UnitSide)node["side"].as<int>();
92+
bodypart = (UnitBodyPart)node["bodypart"].as<int>();
8993
}
9094
// Save
9195
YAML::Node save() const
@@ -99,9 +103,11 @@ struct BattleUnitKills
99103
node["faction"] = (int)faction;
100104
node["mission"] = mission;
101105
node["turn"] = turn;
106+
node["side"] = (int)side;
107+
node["bodypart"] = (int)bodypart;
102108
return node;
103109
}
104-
// Convert victim State to string
110+
// Convert victim State to string.
105111
std::string getUnitStatusString() const
106112
{
107113
switch (status)
@@ -111,7 +117,7 @@ struct BattleUnitKills
111117
default: return "status error";
112118
}
113119
}
114-
// Convert victim Faction to string
120+
// Convert victim Faction to string.
115121
std::string getUnitFactionString() const
116122
{
117123
switch (faction)
@@ -122,9 +128,36 @@ struct BattleUnitKills
122128
default: return "faction error";
123129
}
124130
}
131+
// Convert victim Side to string.
132+
std::string getUnitSideString() const
133+
{
134+
switch (side)
135+
{
136+
case SIDE_FRONT: return "SIDE_FRONT";
137+
case SIDE_LEFT: return "SIDE_LEFT";
138+
case SIDE_RIGHT: return "SIDE_RIGHT";
139+
case SIDE_REAR: return "SIDE_REAR";
140+
case SIDE_UNDER: return "SIDE_UNDER";
141+
default: return "side error";
142+
}
143+
}
144+
// Convert victim Body part to string.
145+
std::string getUnitBodyPart() const
146+
{
147+
switch (bodypart)
148+
{
149+
case BODYPART_HEAD: return "BODYPART_HEAD";
150+
case BODYPART_TORSO: return "BODYPART_TORSO";
151+
case BODYPART_RIGHTARM: return "BODYPART_RIGHTARM";
152+
case BODYPART_LEFTARM: return "BODYPART_LEFTARM";
153+
case BODYPART_RIGHTLEG: return "BODYPART_RIGHTLEG";
154+
case BODYPART_LEFTLEG: return "BODYPART_LEFTLEG";
155+
default: return "body part error";
156+
}
157+
}
125158
BattleUnitKills(const YAML::Node& node) { load(node); }
126-
BattleUnitKills(std::string Rank, std::string Race, std::string Weapon, std::string WeaponAmmo, UnitFaction Faction, UnitStatus Status, int Mission, int Turn) :
127-
rank(Rank), race(Race), weapon(Weapon), weaponAmmo(WeaponAmmo), faction(Faction), status(Status), mission(Mission), turn(Turn) { }
159+
BattleUnitKills(std::string Rank, std::string Race, std::string Weapon, std::string WeaponAmmo, UnitFaction Faction, UnitStatus Status, int Mission, int Turn, UnitSide Side, UnitBodyPart BodyPart) :
160+
rank(Rank), race(Race), weapon(Weapon), weaponAmmo(WeaponAmmo), faction(Faction), status(Status), mission(Mission), turn(Turn), side(Side), bodypart(BodyPart) { }
128161
~BattleUnitKills() { }
129162
};
130163

@@ -261,6 +294,8 @@ class BattleUnit
261294
std::string _activeHand;
262295
BattleUnitStatistics* _statistics;
263296
int _murdererId; // used to credit the murderer with the kills that this unit got by blowing up on death
297+
UnitSide _fatalShotSide;
298+
UnitBodyPart _fatalShotBodyPart;
264299

265300
// static data
266301
std::string _type;
@@ -622,6 +657,12 @@ class BattleUnit
622657
void setMurdererId(int id);
623658
/// Get the unit murderer's id.
624659
int getMurdererId() const;
660+
/// Set information on the unit's fatal shot.
661+
void setFatalShotInfo(UnitSide side, UnitBodyPart bodypart);
662+
/// Get information on the unit's fatal shot's side.
663+
UnitSide getFatalShotSide() const;
664+
/// Get information on the unit's fatal shot's body part.
665+
UnitBodyPart getFatalShotBodyPart() const;
625666
};
626667

627668
}

src/Savegame/SoldierDiary.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ void SoldierDiary::load(const YAML::Node& node)
108108
_alienBaseAssaultTotal = node["alienBaseAssaultTotal"].as<int>(_alienBaseAssaultTotal);
109109
_allAliensKilledTotal = node["allAliensKilledTotal"].as<int>(_allAliensKilledTotal);
110110
_allAliensStunnedTotal = node["_allAliensStunnedTotal"].as<int>(_allAliensStunnedTotal);
111+
_headshotTotal = node["_headshotTotal"].as<int>(_headshotTotal);
111112
}
112113
/**
113114
* Saves the diary to a YAML file.
@@ -156,6 +157,7 @@ YAML::Node SoldierDiary::save() const
156157
if (_alienBaseAssaultTotal) node["alienBaseAssaultTotal"] = _alienBaseAssaultTotal;
157158
if (_allAliensKilledTotal) node["allAliensKilledTotal"] = _allAliensKilledTotal;
158159
if (_allAliensStunnedTotal) node["_allAliensStunnedTotal"] = _allAliensStunnedTotal;
160+
if (_headshotTotal) node["_headshotTotal"] = _headshotTotal;
159161
return node;
160162
}
161163
/**
@@ -175,10 +177,14 @@ void SoldierDiary::updateDiary(BattleUnitStatistics *unitStatistics, MissionStat
175177
_stunTotal++;
176178
_killList.push_back(*kill);
177179
if ((*kill)->hostileTurn())
180+
{
178181
if (rules->getItem((*kill)->weapon)->getBattleType() == BT_GRENADE || rules->getItem((*kill)->weapon)->getBattleType() == BT_PROXIMITYGRENADE)
179182
_trapKillTotal++;
180183
else
181184
_reactionFireTotal++;
185+
}
186+
if ((*kill)->getUnitSideString() == "BODYPART_HEAD")
187+
_headshotTotal++;
182188
}
183189
_regionTotal[missionStatistics->region.c_str()]++;
184190
_countryTotal[missionStatistics->country.c_str()]++;
@@ -306,7 +312,8 @@ bool SoldierDiary::manageCommendations(Ruleset *rules)
306312
((*j).first == "totalTrapKills" && _trapKillTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
307313
((*j).first == "totalAlienBaseAssaults" && _alienBaseAssaultTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
308314
((*j).first == "totalAllAliensKilled" && _allAliensKilledTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
309-
((*j).first == "totalAllAliensStunned" && _allAliensStunnedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ))
315+
((*j).first == "totalAllAliensStunned" && _allAliensStunnedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
316+
((*j).first == "totalHeadShots" && _headshotTotal < (*j).second.at(nextCommendationLevel["noNoun"])) )
310317
{
311318
awardCommendationBool = false;
312319
break;

src/Savegame/SoldierDiary.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ class SoldierDiary
7575
int _scoreTotal, _killTotal, _winTotal, _stunTotal, _daysWoundedTotal, _baseDefenseMissionTotal, _totalShotByFriendlyCounter, _totalShotFriendlyCounter, _loneSurvivorTotal,
7676
_terrorMissionTotal, _nightMissionTotal, _nightTerrorMissionTotal, _monthsService, _unconciousTotal, _shotAtCounterTotal, _hitCounterTotal, _ironManTotal,
7777
_importantMissionTotal, _longDistanceHitCounterTotal, _lowAccuracyHitCounterTotal, _shotsFiredCounterTotal, _shotsLandedCounterTotal, _shotAtCounter10in1Mission,
78-
_hitCounter5in1Mission, _reactionFireTotal, _timesWoundedTotal, _valiantCruxTotal, _KIA, _trapKillTotal, _alienBaseAssaultTotal, _allAliensKilledTotal, _allAliensStunnedTotal;
78+
_hitCounter5in1Mission, _reactionFireTotal, _timesWoundedTotal, _valiantCruxTotal, _KIA, _trapKillTotal, _alienBaseAssaultTotal, _allAliensKilledTotal, _allAliensStunnedTotal,
79+
_headshotTotal;
7980
void manageModularCommendations(std::map<std::string, int> &nextCommendationLevel, std::map<std::string, int> &modularCommendations, std::pair<std::string, int> statTotal, int criteria);
8081
void awardCommendation(std::string type, std::string noun = "noNoun");
8182
public:

0 commit comments

Comments
 (0)