hedgewars/uStats.pas
branchqmlfrontend
changeset 12855 1b2b84315d27
parent 12568 494d3e1c4810
child 12918 6deb29364723
--- a/hedgewars/uStats.pas	Thu Aug 11 23:05:14 2016 +0300
+++ b/hedgewars/uStats.pas	Sun Dec 17 00:09:24 2017 +0100
@@ -24,13 +24,19 @@
 
 var TotalRounds: LongInt;
     FinishedTurnsTotal: LongInt;
+    SendGameResultOn : boolean = true;
+    SendRankingStatsOn : boolean = true;
+    SendAchievementsStatsOn : boolean = true;
     SendHealthStatsOn : boolean = true;
 
 procedure initModule;
 procedure freeModule;
 
 procedure AmmoUsed(am: TAmmoType);
+procedure HedgehogPoisoned(Gear: PGear; Attacker: PHedgehog);
+procedure HedgehogSacrificed(Hedgehog: PHedgehog);
 procedure HedgehogDamaged(Gear: PGear; Attacker: PHedgehog; Damage: Longword; killed: boolean);
+procedure TargetHit;
 procedure Skipped;
 procedure TurnReaction;
 procedure SendStats;
@@ -45,9 +51,13 @@
 var DamageClan  : Longword = 0;
     DamageTotal : Longword = 0;
     DamageTurn  : Longword = 0;
+    PoisonTurn  : Longword = 0; // Poisoned enemies per turn
+    PoisonClan  : Longword = 0; // Poisoned own clan members in turn
+    PoisonTotal : Longword = 0; // Poisoned hogs in whole round
     KillsClan   : LongWord = 0;
     Kills       : LongWord = 0;
     KillsTotal  : LongWord = 0;
+    HitTargets  : LongWord = 0; // Target (gtTarget) hits per turn
     AmmoUsedCount : Longword = 0;
     AmmoDamagingUsed : boolean = false;
     SkippedTurns: LongWord = 0;
@@ -55,6 +65,27 @@
     vpHurtSameClan: PVoicepack = nil;
     vpHurtEnemy: PVoicepack = nil;
 
+procedure HedgehogPoisoned(Gear: PGear; Attacker: PHedgehog);
+begin
+    if Attacker^.Team^.Clan = Gear^.HEdgehog^.Team^.Clan then
+        begin
+        vpHurtSameClan:= CurrentHedgehog^.Team^.voicepack;
+        inc(PoisonClan)
+        end
+    else
+        begin
+        vpHurtEnemy:= Gear^.Hedgehog^.Team^.voicepack;
+        inc(PoisonTurn)
+        end;
+    Gear^.Hedgehog^.stats.StepPoisoned:= true;
+    inc(PoisonTotal)
+end;
+
+procedure HedgehogSacrificed(Hedgehog: PHedgehog);
+begin
+    Hedgehog^.stats.Sacrificed:= true
+end;
+
 procedure HedgehogDamaged(Gear: PGear; Attacker: PHedgehog; Damage: Longword; killed: boolean);
 begin
 if Attacker^.Team^.Clan = Gear^.Hedgehog^.Team^.Clan then
@@ -72,6 +103,7 @@
 
 if killed then
     begin
+    Gear^.Hedgehog^.stats.StepDied:= true;
     inc(Attacker^.stats.StepKills);
     inc(Kills);
     inc(KillsTotal);
@@ -91,6 +123,11 @@
 inc(DamageTurn, Damage)
 end;
 
+procedure TargetHit();
+begin
+   inc(HitTargets)
+end;
+
 procedure Skipped;
 begin
 inc(SkippedTurns);
@@ -99,6 +136,7 @@
 
 procedure TurnReaction;
 var i, t: LongInt;
+    killsCheck: LongInt;
     s: ansistring;
 begin
 //TryDo(not bBetweenTurns, 'Engine bug: TurnReaction between turns', true);
@@ -108,19 +146,28 @@
     begin
     s:= ansistring(CurrentHedgehog^.Name);
     inc(CurrentHedgehog^.stats.FinishedTurns);
+    // If the hog sacrificed (=kamikaze/piano) itself, this needs to be taken into accounts for the reactions later
+    if (CurrentHedgehog^.stats.Sacrificed) then
+        killsCheck:= 1
+    else
+        killsCheck:= 0;
 
-    if (CurrentHedgehog^.stats.DamageGiven = DamageTotal) and (DamageTotal > 0) then
+    // First blood (first damage, poison or kill)
+    if ((DamageTotal > 0) or (KillsTotal > 0) or (PoisonTotal > 0)) and ((CurrentHedgehog^.stats.DamageGiven = DamageTotal) and (CurrentHedgehog^.stats.StepKills = KillsTotal) and (PoisonTotal = PoisonTurn + PoisonClan)) then
         AddVoice(sndFirstBlood, CurrentTeam^.voicepack)
 
-    else if CurrentHedgehog^.stats.StepDamageRecv > 0 then
+    // Hog hurts, poisons or kills itself (except sacrifice)
+    else if (CurrentHedgehog^.stats.Sacrificed = false) and ((CurrentHedgehog^.stats.StepDamageRecv > 0) or (CurrentHedgehog^.stats.StepPoisoned) or (CurrentHedgehog^.stats.StepDied)) then
         begin
         AddVoice(sndStupid, PreviousTeam^.voicepack);
-        if CurrentHedgehog^.stats.DamageGiven = CurrentHedgehog^.stats.StepDamageRecv then
+        // Message for hurting itself only (not drowning)
+        if (CurrentHedgehog^.stats.DamageGiven = CurrentHedgehog^.stats.StepDamageRecv) and (CurrentHedgehog^.stats.StepDamageRecv >= 1) then
             AddCaption(FormatA(GetEventString(eidHurtSelf), s), cWhiteColor, capgrpMessage);
         end
 
-    else if DamageClan <> 0 then
-        if DamageTurn > DamageClan then
+    // Hog hurts, poisons or kills own team/clan member. Sacrifice is taken into account
+    else if (DamageClan <> 0) or (KillsClan > killsCheck) or (PoisonClan <> 0) then
+        if (DamageTurn > DamageClan) or (Kills > KillsClan) then
             if random(2) = 0 then
                 AddVoice(sndNutter, CurrentTeam^.voicepack)
             else
@@ -131,23 +178,35 @@
             else
                 AddVoice(sndTraitor, vpHurtSameClan)
 
-    else if CurrentHedgehog^.stats.StepDamageGiven <> 0 then
-        if Kills > 0 then
+    // Hog hurts, kills or poisons enemy
+    else if (CurrentHedgehog^.stats.StepDamageGiven <> 0) or (CurrentHedgehog^.stats.StepKills > killsCheck) or (PoisonTurn <> 0) then
+        if Kills > killsCheck then
             AddVoice(sndEnemyDown, CurrentTeam^.voicepack)
         else
             AddVoice(sndRegret, vpHurtEnemy)
 
-    else if AmmoDamagingUsed then
-        AddVoice(sndMissed, PreviousTeam^.voicepack)
+    // Missed shot
+    // A miss is defined as a shot with a damaging weapon with 0 kills, 0 damage, 0 hogs poisoned and 0 targets hit
+    else if AmmoDamagingUsed and (Kills <= killsCheck) and (PoisonTurn = 0) and (PoisonClan = 0) and (DamageTurn = 0) and (HitTargets = 0) then
+        // Chance to call hedgehog stupid if sacrificed for nothing
+        if CurrentHedgehog^.stats.Sacrificed then
+            if random(2) = 0 then
+                AddVoice(sndMissed, PreviousTeam^.voicepack)
+            else
+                AddVoice(sndStupid, PreviousTeam^.voicepack)
+        else
+            AddVoice(sndMissed, PreviousTeam^.voicepack)
+
+    // Timeout
     else if (AmmoUsedCount > 0) and (not isTurnSkipped) then
         begin end// nothing ?
-    else if isTurnSkipped then
+
+    // Turn skipped
+    else if isTurnSkipped and (not PlacingHogs) then
         begin
-        AddVoice(sndBoring, PreviousTeam^.voicepack);
+        AddVoice(sndCoward, PreviousTeam^.voicepack);
         AddCaption(FormatA(GetEventString(eidTurnSkipped), s), cWhiteColor, capgrpMessage);
         end
-    else if not PlacingHogs then
-        AddVoice(sndCoward, PreviousTeam^.voicepack);
     end;
 
 
@@ -166,7 +225,9 @@
                     MaxStepKills:= StepKills;
                 StepKills:= 0;
                 StepDamageRecv:= 0;
-                StepDamageGiven:= 0
+                StepDamageGiven:= 0;
+                StepPoisoned:= false;
+                StepDied:= false;
                 end;
 
 if SendHealthStatsOn then
@@ -180,6 +241,9 @@
 KillsClan:= 0;
 DamageClan:= 0;
 DamageTurn:= 0;
+HitTargets:= 0;
+PoisonClan:= 0;
+PoisonTurn:= 0;
 AmmoUsedCount:= 0;
 AmmoDamagingUsed:= false;
 isTurnSkipped:= false
@@ -226,7 +290,7 @@
     for t:= 0 to Pred(TeamsCount) do
         with TeamsArray[t]^ do
         begin
-            if not ExtDriven then
+            if (not ExtDriven) and SendRankingStatsOn then
                 SendStat(siTeamStats, GetTeamStatString(TeamsArray[t]));
             for i:= 0 to cMaxHHIndex do
                 begin
@@ -250,8 +314,9 @@
             if Clan^.ClanHealth > 0 then
                 begin
                 winnersClan:= Clan;
-                SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
-                    IntToStr(stats.Kills) + ' ' + TeamName);
+                if SendRankingStatsOn then
+                    SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
+                        IntToStr(stats.Kills) + ' ' + TeamName);
             end;
 
             { determine maximum values of TeamKills, TurnSkips, TeamDamage }
@@ -274,32 +339,37 @@
         end;
 
     { now send player stats for loser teams }
-    for t:= 0 to Pred(TeamsCount) do
-        begin
-        with TeamsArray[t]^ do
+    if SendRankingStatsOn then
+        for t:= 0 to Pred(TeamsCount) do
             begin
-            if Clan^.ClanHealth = 0 then
+            with TeamsArray[t]^ do
                 begin
-                SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
-                    IntToStr(stats.Kills) + ' ' + TeamName);
+                if Clan^.ClanHealth = 0 then
+                    begin
+                    SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
+                        IntToStr(stats.Kills) + ' ' + TeamName);
+                end;
             end;
         end;
-    end;
 
-    if msdhh <> nil then
-        SendStat(siMaxStepDamage, IntToStr(msd) + ' ' + msdhh^.Name + ' (' + msdhh^.Team^.TeamName + ')');
-    if mskcnt = 1 then
-        SendStat(siMaxStepKills, IntToStr(msk) + ' ' + mskhh^.Name + ' (' + mskhh^.Team^.TeamName + ')');
+    // “Achievements” / Details part of stats screen
+    if SendAchievementsStatsOn then
+        begin
+        if msdhh <> nil then
+            SendStat(siMaxStepDamage, IntToStr(msd) + ' ' + msdhh^.Name + ' (' + msdhh^.Team^.TeamName + ')');
+        if mskcnt = 1 then
+            SendStat(siMaxStepKills, IntToStr(msk) + ' ' + mskhh^.Name + ' (' + mskhh^.Team^.TeamName + ')');
 
-    if maxTeamKills > 1 then
-        SendStat(siMaxTeamKills, IntToStr(maxTeamKills) + ' ' + maxTeamKillsName);
-    if maxTurnSkips > 2 then
-        SendStat(siMaxTurnSkips, IntToStr(maxTurnSkips) + ' ' + maxTurnSkipsName);
-    if maxTeamDamage > 30 then
-        SendStat(siMaxTeamDamage, IntToStr(maxTeamDamage) + ' ' + maxTeamDamageName);
+        if maxTeamKills > 1 then
+            SendStat(siMaxTeamKills, IntToStr(maxTeamKills) + ' ' + maxTeamKillsName);
+        if maxTurnSkips > 2 then
+            SendStat(siMaxTurnSkips, IntToStr(maxTurnSkips) + ' ' + maxTurnSkipsName);
+        if maxTeamDamage > 30 then
+            SendStat(siMaxTeamDamage, IntToStr(maxTeamDamage) + ' ' + maxTeamDamageName);
 
-    if KilledHHs > 0 then
-        SendStat(siKilledHHs, IntToStr(KilledHHs));
+        if KilledHHs > 0 then
+            SendStat(siKilledHHs, IntToStr(KilledHHs));
+        end;
 
     // now to console
     if winnersClan <> nil then
@@ -342,9 +412,12 @@
     DamageClan  := 0;
     DamageTotal := 0;
     DamageTurn  := 0;
+    PoisonClan  := 0;
+    PoisonTurn  := 0;
     KillsClan   := 0;
     Kills       := 0;
     KillsTotal  := 0;
+    HitTargets  := 0;
     AmmoUsedCount := 0;
     AmmoDamagingUsed := false;
     SkippedTurns:= 0;