OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4RoundResults.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // Round result information to be displayed in game over dialog
17 
18 #include "C4Include.h"
19 #include "control/C4RoundResults.h"
20 
21 #include "player/C4Player.h"
22 #include "game/C4Game.h"
23 #include "object/C4Def.h"
24 #include "object/C4Object.h"
25 #include "player/C4PlayerList.h"
26 #include "object/C4GameObjects.h"
27 #include "object/C4DefList.h"
28 
29 // *** C4RoundResultsPlayer
30 
32 {
33  // remember to adjust operator = and == when adding values here!
34  pComp->Value(mkNamingAdapt(id, "ID", 0));
35  // pComp->Value(mkNamingAdapt(fctBigIcon, "Icon", C4TargetFacet())); - not possible
36  pComp->Value(mkNamingAdapt(iTotalPlayingTime, "TotalPlayingTime", 0u));
37  pComp->Value(mkNamingAdapt(iScoreOld, "SettlementScoreOld", -1));
38  pComp->Value(mkNamingAdapt(iScoreNew, "SettlementScoreNew", -1));
39  pComp->Value(mkNamingAdapt(iLeagueScoreNew, "Score", -1)); // name used in league reply!
40  pComp->Value(mkNamingAdapt(iLeagueScoreGain, "GameScore", -1)); // name used in league reply!
41  pComp->Value(mkNamingAdapt(iLeagueRankNew, "Rank", 0)); // name used in league reply!
42  pComp->Value(mkNamingAdapt(iLeagueRankSymbolNew, "RankSymbol", 0)); // name used in league reply!
43  pComp->Value(mkNamingAdapt(sLeagueProgressData, "LeagueProgressData", StdCopyStrBuf()));
44  StdEnumEntry<LeagueStatus> LeagueStatusEntries[] =
45  {
46  { "", RRPLS_Unknown },
47  { "Lost", RRPLS_Lost },
48  { "Won", RRPLS_Won },
49  };
50  pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(eLeagueStatus, LeagueStatusEntries), "Status", RRPLS_Unknown)); // name used in league reply!
51 }
52 
54 {
55  assert(pPlr);
56  // set fields by player
57  iTotalPlayingTime = pPlr->TotalPlayingTime;
58  if (pPlr->Evaluated)
59  {
60  iScoreNew = pPlr->TotalScore;
61  iScoreOld = iScoreNew - pPlr->LastRound.FinalScore;
62  }
63  else
64  {
65  // player not evaluated (e.g., removed by disconnect): Old score known only
66  iScoreOld = pPlr->TotalScore;
67  }
68  // load icon from player
69  fctBigIcon.Clear();
70  if (pPlr->BigIcon.Surface)
71  {
72  fctBigIcon.Create(pPlr->BigIcon.Wdt, pPlr->BigIcon.Hgt);
73  pPlr->BigIcon.Draw(fctBigIcon);
74  }
75  // progress data by player
76  C4PlayerInfo *pInfo = pPlr->GetInfo();
77  if (pInfo)
78  {
79  sLeagueProgressData.Copy(pInfo->GetLeagueProgressData());
80  }
81 }
82 
84 {
85  assert(pLeaguePlayerInfo);
86  //
87  // copy league info
88  iLeagueScoreNew = pLeaguePlayerInfo->iLeagueScoreNew;
89  iLeagueScoreGain = pLeaguePlayerInfo->iLeagueScoreGain;
90  iLeagueRankNew = pLeaguePlayerInfo->iLeagueRankNew;
91  iLeagueRankSymbolNew = pLeaguePlayerInfo->iLeagueRankSymbolNew;
92  sLeagueProgressData =pLeaguePlayerInfo->sLeagueProgressData;
93 }
94 
95 void C4RoundResultsPlayer::AddCustomEvaluationString(const char *szCustomString)
96 {
97  if (sCustomEvaluationStrings.getLength()) sCustomEvaluationStrings.Append(" ");
98  sCustomEvaluationStrings.Append(szCustomString);
99 }
100 
102 {
103  // cmp all xcept icon
104  if (id != cmp.id) return false;
105  if (iTotalPlayingTime != cmp.iTotalPlayingTime) return false;
106  if (iScoreOld != cmp.iScoreOld) return false;
107  if (iScoreNew != cmp.iScoreNew) return false;
108  if (sCustomEvaluationStrings != cmp.sCustomEvaluationStrings) return false;
109  if (iLeagueScoreNew != cmp.iLeagueScoreNew) return false;
110  if (iLeagueScoreGain != cmp.iLeagueScoreGain) return false;
111  if (iLeagueRankNew != cmp.iLeagueRankNew) return false;
112  if (iLeagueRankSymbolNew != cmp.iLeagueRankSymbolNew) return false;
113  if (eLeagueStatus != cmp.eLeagueStatus) return false;
114  if (sLeagueProgressData != cmp.sLeagueProgressData) return false;
115  return true;
116 }
117 
119 {
120  if (this == &cpy) return *this;
121  // assign all xcept icon
122  id = cpy.id;
123  iTotalPlayingTime = cpy.iTotalPlayingTime;
124  iScoreOld = cpy.iScoreOld;
125  iScoreNew = cpy.iScoreNew;
126  sCustomEvaluationStrings = cpy.sCustomEvaluationStrings;
127  iLeagueScoreNew = cpy.iLeagueScoreNew;
128  iLeagueScoreGain = cpy.iLeagueScoreGain;
129  iLeagueRankNew = cpy.iLeagueRankNew;
130  iLeagueRankSymbolNew = cpy.iLeagueRankSymbolNew;
131  eLeagueStatus = cpy.eLeagueStatus;
132  sLeagueProgressData = cpy.sLeagueProgressData;
133  return *this;
134 }
135 
136 
137 // *** C4RoundResultsPlayers
138 
140 {
141  while (iPlayerCount) delete ppPlayers[--iPlayerCount];
142  delete [] ppPlayers;
143  ppPlayers = nullptr;
144  iPlayerCapacity = 0;
145 }
146 
148 {
149  bool deserializing = pComp->isDeserializer();
150  if (deserializing) Clear();
151  int32_t iTemp = iPlayerCount;
152  pComp->Value(mkNamingCountAdapt<int32_t>(iTemp, "Player"));
153  if (iTemp < 0 || iTemp > C4MaxPlayer)
154  { pComp->excCorrupt("player count out of range"); return; }
155  // Grow list, if necessary
156  if (deserializing && iTemp > iPlayerCapacity)
157  {
158  GrowList(iTemp - iPlayerCapacity);
159  iPlayerCount = iTemp;
160  ZeroMem(ppPlayers, sizeof(*ppPlayers) * iPlayerCount);
161  }
162  // Compile
163  pComp->Value(mkNamingAdapt(mkArrayAdaptMap(ppPlayers, iPlayerCount, mkPtrAdaptNoNull<C4RoundResultsPlayer>), "Player"));
164  // Force specialization
165  mkPtrAdaptNoNull<C4RoundResultsPlayer>(*ppPlayers);
166 }
167 
169 {
170  if (idx>=0 && idx<iPlayerCount)
171  return ppPlayers[idx];
172  else
173  return nullptr;
174 }
175 
177 {
178  for (int32_t idx=0; idx<iPlayerCount; ++idx)
179  if (ppPlayers[idx]->GetID() == id)
180  return ppPlayers[idx];
181  return nullptr;
182 }
183 
184 void C4RoundResultsPlayers::GrowList(size_t iByVal)
185 {
186  // create new list (out of mem: simply returns here; info list remains in a valid state)
187  C4RoundResultsPlayer **ppNew = new C4RoundResultsPlayer *[iPlayerCapacity += iByVal];
188  // move existing
189  if (ppPlayers)
190  {
191  memcpy(ppNew, ppPlayers, iPlayerCount * sizeof(C4RoundResultsPlayer *));
192  delete [] ppPlayers;
193  }
194  // assign new
195  ppPlayers = ppNew;
196 }
197 
199 {
200  assert(pNewPlayer);
201  if (iPlayerCount == iPlayerCapacity) GrowList(4);
202  ppPlayers[iPlayerCount++] = pNewPlayer;
203 }
204 
206 {
207  assert(id);
208  // find existing
209  C4RoundResultsPlayer *pPlr = GetByID(id);
210  // not found: Add new
211  if (!pPlr)
212  {
213  pPlr = new C4RoundResultsPlayer();
214  pPlr->SetID(id);
215  Add(pPlr);
216  }
217  return pPlr;
218 }
219 
221 {
222  if (iPlayerCount != cmp.iPlayerCount) return false;
223  for (int32_t i = 0; i < iPlayerCount; ++i)
224  if (!(*ppPlayers[i] == *cmp.ppPlayers[i]))
225  return false;
226  // equal
227  return true;
228 }
229 
231 {
232  Clear();
233  C4RoundResultsPlayer *pPlr; int32_t i=0;
234  while ((pPlr = cpy.GetByIndex(i++)))
235  Add(new C4RoundResultsPlayer(*pPlr));
236  return *this;
237 }
238 
239 
240 // *** C4RoundResults
241 
243 {
244  Players.Clear();
245  Goals.Clear();
246  iPlayingTime = 0;
247  sCustomEvaluationStrings.Clear();
248  iLeaguePerformance = 0;
249  sNetResult.Clear();
250  eNetResult = NR_None;
251  fHideSettlementScore=false;
252  Statistics.Clear();
253 }
254 
256 {
257  if (Game.C4S.Game.IsMelee())
258  fHideSettlementScore=true;
259  else fHideSettlementScore=false;
260 }
261 
263 {
264  bool deserializing = pComp->isDeserializer();
265  if (deserializing) Clear();
266  pComp->Value(mkNamingAdapt(Goals, "Goals", C4IDList()));
267  pComp->Value(mkNamingAdapt(iPlayingTime, "PlayingTime", 0u));
268  pComp->Value(mkNamingAdapt(fHideSettlementScore, "HideSettlementScore", Game.C4S.Game.IsMelee()));
269  pComp->Value(mkNamingAdapt(sCustomEvaluationStrings, "CustomEvaluationStrings", StdCopyStrBuf()));
270  pComp->Value(mkNamingAdapt(iLeaguePerformance, "LeaguePerformance", 0));
271  pComp->Value(mkNamingAdapt(Players, "PlayerInfos", C4RoundResultsPlayers()));
272  pComp->Value(mkNamingAdapt(sNetResult, "NetResult", StdCopyStrBuf()));
273  StdEnumEntry<NetResult> NetResultEntries[] =
274  {
275  { "", NR_None },
276  { "LeagueOK", NR_LeagueOK },
277  { "LeagueError", NR_LeagueError},
278  { "NetError", NR_NetError },
279  };
280  pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(eNetResult, NetResultEntries), "NetResult", NR_None));
281 }
282 
283 void C4RoundResults::EvaluateGoals(C4IDList &GoalList, C4IDList &FulfilledGoalList, int32_t iPlayerNumber)
284 {
285  // clear prev
286  GoalList.Clear(); FulfilledGoalList.Clear();
287  // Items
288  int32_t cnt; C4ID idGoal;
289  for (cnt=0; (idGoal=::Objects.GetListID(C4D_Goal,cnt)); cnt++)
290  {
291  // determine if the goal is fulfilled - do the calls even if the menu is not to be opened to ensure synchronization
292  bool fFulfilled = false;;
293  C4Object *pObj = C4Id2Def(idGoal) ? ::Objects.Find(::Definitions.ID2Def(idGoal)) : nullptr;
294  if (pObj)
295  {
296  // Check fulfilled per player, this enables the possibility of rivalry.
297  C4AulParSet pars(iPlayerNumber);
298  fFulfilled = !!pObj->Call(PSF_IsFulfilled, &pars);
299  }
300  GoalList.SetIDCount(idGoal, cnt, true);
301  if (fFulfilled) FulfilledGoalList.SetIDCount(idGoal, 1, true);
302  }
303 }
304 
306 {
307  // set game data
308  C4Player *pFirstLocalPlayer = ::Players.GetLocalByIndex(0);
309  int32_t iFirstLocalPlayer = pFirstLocalPlayer ? pFirstLocalPlayer->Number : NO_OWNER;
310  EvaluateGoals(Goals, FulfilledGoals, iFirstLocalPlayer);
311  iPlayingTime = Game.Time;
312 
313  // collect statistics
314  try
315  {
316  C4AulParSet Pars;
317  auto stats = ::ScriptEngine.GetPropList()->Call(PSF_CollectStatistics, &Pars);
318  if (stats != C4VNull)
319  Statistics = stats.ToJSON();
320  }
321  catch (C4JSONSerializationError& e)
322  {
323  DebugLogF("ERROR: cannot serialize CollectStatistics() result: %s", e.what());
324  }
325 }
326 
327 void C4RoundResults::EvaluateNetwork(C4RoundResults::NetResult eNetResult, const char *szResultMsg)
328 {
329  // take result only if there was no previous result (the previous one is usually more specific)
330  if (!HasNetResult())
331  {
332  this->eNetResult = eNetResult;
333  if (szResultMsg) sNetResult.Copy(szResultMsg); else sNetResult.Clear();
334  }
335 }
336 
337 void C4RoundResults::EvaluateLeague(const char *szResultMsg, bool fSuccess, const C4RoundResultsPlayers &rLeagueInfo)
338 {
339  // League evaluation imples network evaluation
341  // Evaluation called by league: Sets new league scores and ranks
342  C4RoundResultsPlayer *pPlr, *pOwnPlr; int32_t i = 0;
343  while ((pPlr = rLeagueInfo.GetByIndex(i++)))
344  {
345  pOwnPlr = Players.GetCreateByID(pPlr->GetID());
346  pOwnPlr->EvaluateLeague(pPlr);
347  }
348 }
349 
351 {
352  // Evaluation called by player when it's evaluated
353  assert(pPlr);
354  C4RoundResultsPlayer *pOwnPlr = Players.GetCreateByID(pPlr->ID);
355  pOwnPlr->EvaluatePlayer(pPlr);
356 }
357 
358 void C4RoundResults::AddCustomEvaluationString(const char *szCustomString, int32_t idPlayer)
359 {
360  // Set custom string to be shown in game over dialog
361  // idPlayer==0 for global strings
362  if (!idPlayer)
363  {
364  if (sCustomEvaluationStrings.getLength()) sCustomEvaluationStrings.AppendChar('|');
365  sCustomEvaluationStrings.Append(szCustomString);
366  }
367  else
368  {
369  C4RoundResultsPlayer *pOwnPlr = Players.GetCreateByID(idPlayer);
370  pOwnPlr->AddCustomEvaluationString(szCustomString);
371  }
372 }
373 
375 {
376  fHideSettlementScore=fHide;
377 }
378 
380 {
381  return fHideSettlementScore;
382 }
383 
384 void C4RoundResults::SetLeaguePerformance(int32_t iNewPerf, int32_t idPlayer)
385 {
386  // Store to be sent later. idPlayer == 0 means global performance.
387  if(!idPlayer)
388  {
389  iLeaguePerformance = iNewPerf;
390  }
391  else
392  {
393  C4RoundResultsPlayer *pOwnPlr = Players.GetCreateByID(idPlayer);
394  pOwnPlr->SetLeaguePerformance(iNewPerf);
395  }
396  }
397 
398 int32_t C4RoundResults::GetLeaguePerformance(int32_t idPlayer) const
399 {
400  if(!idPlayer)
401  return iLeaguePerformance;
402  else
403  if(C4RoundResultsPlayer *pPlr = Players.GetByID(idPlayer))
404  return pPlr->GetLeaguePerformance();
405  return 0;
406 }
407 
408 bool C4RoundResults::Load(C4Group &hGroup, const char *szFilename)
409 {
410  // clear previous
411  Clear();
412  // load file contents
413  StdStrBuf Buf;
414  if (!hGroup.LoadEntryString(szFilename, &Buf)) return false;
415  // compile
416  if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(*this, "RoundResults"), Buf, szFilename)) return false;
417  // done, success
418  return true;
419 }
420 
421 bool C4RoundResults::Save(C4Group &hGroup, const char *szFilename)
422 {
423  // remove previous entry from group
424  hGroup.DeleteEntry(szFilename);
425  // decompile
426  try
427  {
428  StdStrBuf Buf = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*this, "RoundResults"));
429  // save it, if not empty
430  if (Buf.getLength())
431  if (!hGroup.Add(szFilename, Buf, false, true))
432  return false;
433  }
434  catch (StdCompiler::Exception *)
435  { return false; }
436  // done, success
437  return true;
438 }
439 
440 
441 // *** C4PacketLeagueRoundResults
442 
444 {
445  pComp->Value(mkNamingAdapt(fSuccess, "Success", false));
446  pComp->Value(mkNamingAdapt(sResultsString, "ResultString", StdCopyStrBuf()));
447  pComp->Value(Players);
448 }
449 
C4Def * ID2Def(C4ID id)
class C4PlayerInfo * GetInfo()
Definition: C4Player.cpp:1553
int32_t TotalPlayingTime
Definition: C4InfoCore.h:92
void Clear()
Definition: stub-handle.cpp:64
void CompileFunc(StdCompiler *pComp)
void SetLeaguePerformance(int32_t iNewPerf, int32_t idPlayer=0)
Definition: StdAdaptors.h:763
C4PropListStatic * GetPropList()
Definition: C4Aul.h:153
bool IsMelee()
Definition: C4Scenario.cpp:510
C4Game Game
Definition: C4Globals.cpp:52
int32_t Number
Definition: C4Player.h:88
#define PSF_IsFulfilled
Definition: C4GameScript.h:84
virtual void CompileFunc(StdCompiler *pComp)
void excCorrupt(const char *szMessage,...)
Definition: StdCompiler.h:259
void EvaluatePlayer(C4Player *pPlr)
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
C4Scenario C4S
Definition: C4Game.h:76
void Clear()
Definition: StdBuf.h:474
#define PSF_CollectStatistics
Definition: C4GameScript.h:105
void EvaluateNetwork(NetResult eResult, const char *szResultsString)
bool HasNetResult() const
void EvaluateLeague(C4RoundResultsPlayer *pLeaguePlayer)
static void EvaluateGoals(C4IDList &GoalList, C4IDList &FulfilledGoalList, int32_t iPlayerNumber)
bool Load(C4Group &hGroup, const char *szFilename=C4CFN_RoundResults)
C4RoundResultsPlayer * GetByIndex(int32_t idx) const
virtual const char * what() const noexceptoverride
Definition: C4Value.h:69
void SetLeaguePerformance(int32_t iNewPerf)
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:93
void AppendChar(char cChar)
Definition: StdBuf.h:596
C4RoundResultsPlayer & operator=(const C4RoundResultsPlayer &cpy)
C4RoundResultsPlayer * GetCreateByID(int32_t id)
void Add(C4RoundResultsPlayer *pNewPlayer)
bool DebugLogF(const char *strMessage...)
Definition: C4Log.cpp:281
void SetID(int32_t idNew)
const char * GetLeagueProgressData() const
Definition: C4PlayerInfo.h:195
C4FacetSurface BigIcon
Definition: C4Player.h:140
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:527
int32_t Time
Definition: C4Game.h:133
void CompileFunc(StdCompiler *pComp)
void Draw(C4Facet &cgo, bool fAspect=true, int32_t iPhaseX=0, int32_t iPhaseY=0, bool fTransparent=true)
Definition: C4Facet.cpp:154
const int NO_OWNER
Definition: C4Constants.h:138
C4RoundResultsPlayers Players
void HideSettlementScore(bool fHide=true)
bool operator==(const C4RoundResultsPlayers &cmp)
void Value(const T &rStruct)
Definition: StdCompiler.h:171
bool Evaluated
Definition: C4Player.h:87
Definition: C4Id.h:28
C4RoundResults & RoundResults
Definition: C4Game.h:75
const int32_t C4MaxPlayer
Definition: C4Player.h:39
void EvaluateLeague(const char *szResultMsg, bool fSuccess, const C4RoundResultsPlayers &rLeagueInfo)
int32_t GetID() const
virtual bool isDeserializer()
Definition: StdCompiler.h:63
bool operator==(const C4RoundResultsPlayer &cmp)
int32_t ID
Definition: C4Player.h:89
bool DeleteEntry(const char *szFilename, bool fRecycle=false)
Definition: C4Group.cpp:1384
int32_t FinalScore
Definition: C4InfoCore.h:72
void AddCustomEvaluationString(const char *szCustomString, int32_t idPlayer)
const C4Value C4VNull
Definition: C4Value.cpp:32
C4ID GetListID(int32_t dwCategory, int Index) const
bool SettlementScoreIsHidden()
bool Save(C4Group &hGroup, const char *szFilename=C4CFN_RoundResults)
C4Def * C4Id2Def(C4ID id)
Definition: C4DefList.h:80
C4Object * Find(C4Def *def, int iOwner=ANY_OWNER, DWORD dwOCF=OCF_All)
int32_t TotalScore
Definition: C4InfoCore.h:90
bool LoadEntryString(const char *szEntryName, StdStrBuf *Buf)
Definition: C4Group.cpp:1932
float Hgt
Definition: C4Facet.h:120
C4RoundResultsPlayer * GetByID(int32_t id) const
bool Create(int iWdt, int iHgt, int iWdt2=C4FCT_Full, int iHgt2=C4FCT_Full)
Definition: C4FacetEx.cpp:54
bool SetIDCount(C4ID c_id, int32_t iCount, bool fAddNewID=false)
Definition: stub-handle.cpp:68
void AddCustomEvaluationString(const char *szCustomString)
C4SGame Game
Definition: C4Scenario.h:232
void EvaluatePlayer(C4Player *pPlr)
bool Add(const char *szFile, const char *szAddAs)
Definition: C4Group.cpp:1316
const int32_t C4D_Goal
Definition: C4Def.h:48
C4RoundResultsPlayers & operator=(const C4RoundResultsPlayers &cpy)
size_t getLength() const
Definition: StdBuf.h:453
C4DefList Definitions
Definition: C4Globals.cpp:49
void CompileFunc(StdCompiler *pComp)
std::enable_if< std::is_pod< T >::value >::type ZeroMem(T *lpMem, size_t dwSize)
Definition: Standard.h:63
C4Surface * Surface
Definition: C4Facet.h:119
C4Value Call(C4PropertyName k, C4AulParSet *pPars=0, bool fPassErrors=false)
Definition: C4PropList.h:112
StdArrayAdapt< T, M > mkArrayAdaptMap(T *pArray, int iSize, M &&map)
Definition: StdAdaptors.h:314
void Copy()
Definition: StdBuf.h:475
float Wdt
Definition: C4Facet.h:120
void Clear()
Definition: C4FacetEx.h:44
int32_t GetLeaguePerformance(int32_t idPlayer=0) const
C4GameObjects Objects
Definition: C4Globals.cpp:48
C4RoundResult LastRound
Definition: C4InfoCore.h:93