1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 /* interface header */
14 #include "Score.h"
15 #include "bzfsAPI.h"
16 #include "WorldEventManager.h"
17 #include "GameKeeper.h"
18 #include "bzfs.h"
19 
20 // bzflag library headers
21 #include "Pack.h"
22 
23 // API headers for notification
24 
25 float Score::tkKickRatio = 3.0;
26 int   Score::score       = 999;
27 bool  Score::randomRanking = false;
28 
29 bool Score::KeepPlayerScores = true;
30 bool Score::KeepTeamScores = true;
31 
Score()32 Score::Score(): wins(0), losses(0), tks(0), handicap(0)
33 {
34     playerID = -1;
35 }
36 
dump()37 void Score::dump()
38 {
39     std::cout << wins << '-' << losses;
40 }
41 
ranking()42 float Score::ranking()
43 {
44     if (randomRanking)
45         return (float)bzfrand();
46 
47     // otherwise do score-based ranking
48     int sum = wins + losses;
49     if (sum == 0)
50         return 0.5;
51     float average = (float)wins/(float)sum;
52     // IIRC that is how wide is the gaussian
53     float penalty = (1.0f - 0.5f / sqrt((float)sum));
54     return average * penalty;
55 }
56 
isTK() const57 bool Score::isTK() const
58 {
59     // arbitrary 3
60     return (tks >= 3) && (tkKickRatio > 0)
61            && ((wins == 0) || (tks * 100 / wins > tkKickRatio));
62 }
63 
64 // Change a score element, then call an event
changeScoreElement(bz_eScoreElement element,int * toChange,int newValue)65 void Score::changeScoreElement(bz_eScoreElement element, int *toChange, int newValue)
66 {
67     int oldValue = *toChange;
68     *toChange = newValue;
69     bz_PlayerScoreChangeEventData_V1 eventData = bz_PlayerScoreChangeEventData_V1(playerID, element, oldValue, newValue);
70     worldEventManager.callEvents(&eventData);
71 }
72 
73 
tK()74 void Score::tK()
75 {
76     if (KeepPlayerScores)
77         changeScoreElement(bz_eTKs, &tks, tks + 1);
78 }
79 
killedBy()80 void Score::killedBy()
81 {
82     if (KeepPlayerScores)
83         changeScoreElement(bz_eLosses, &losses, losses + 1);
84 }
85 
kill()86 void Score::kill()
87 {
88     if (KeepPlayerScores)
89         changeScoreElement(bz_eWins, &wins, wins + 1);
90 }
91 
92 
reset()93 void Score::reset()
94 {
95     changeScoreElement(bz_eWins, &wins, 0);
96     changeScoreElement(bz_eLosses, &losses, 0);
97     changeScoreElement(bz_eTKs, &tks, 0);
98 }
99 
pack(void * buf)100 void *Score::pack(void *buf)
101 {
102     buf = nboPackUShort(buf, wins);
103     buf = nboPackUShort(buf, losses);
104     buf = nboPackUShort(buf, tks);
105     return buf;
106 }
107 
reached() const108 bool Score::reached() const
109 {
110     return wins - losses >= score;
111 }
112 
setTeamKillRatio(int _tkKickRatio)113 void Score::setTeamKillRatio(int _tkKickRatio)
114 {
115     tkKickRatio = (float)_tkKickRatio;
116 }
117 
setWinLimit(int _score)118 void Score::setWinLimit(int _score)
119 {
120     score = _score;
121 }
122 
setRandomRanking()123 void Score::setRandomRanking()
124 {
125     randomRanking = true;
126 }
127 
128 // Local Variables: ***
129 // mode: C++ ***
130 // tab-width: 4 ***
131 // c-basic-offset: 4 ***
132 // indent-tabs-mode: nil ***
133 // End: ***
134 // ex: shiftwidth=4 tabstop=4
135