/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 1998-2000, Matthes Bender * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2009-2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ /* Structures for object and player info components */ #include "C4Include.h" #include "object/C4InfoCore.h" #include "object/C4Def.h" #include "object/C4DefList.h" #include "lib/C4Random.h" #include "lib/C4Markup.h" #include "player/C4RankSystem.h" #include "c4group/C4Group.h" #include "c4group/C4Components.h" #include "game/C4Game.h" #include "object/C4GameObjects.h" #include "lib/C4Random.h" //------------------------------- Player Info ---------------------------------------- C4PlayerInfoCore::C4PlayerInfoCore() { Default(); } void C4PlayerInfoCore::Default(C4RankSystem *pRanks) { *Comment='\0'; *RankName='\0'; TotalScore=0; Rounds=RoundsWon=RoundsLost=0; TotalPlayingTime=0; *LeagueName='\0'; LastRound.Default(); ExtraData = C4ValueMapData(); PrefControl.Clear(); Rank=0; SCopy("Neuling",PrefName); if (pRanks) SCopy(pRanks->GetRankName(Rank,false).getData(),RankName); else SCopy("Rang",RankName); PrefClonkSkin=0; PrefColor=0; PrefColorDw=0xff; PrefColor2Dw=0; OldPrefControl=0; PrefPosition=0; PrefMouse=1; OldPrefControlStyle = 0; OldPrefAutoContextMenu = 0; PrefControl.Clear(); ExtraData.Reset(); } DWORD C4PlayerInfoCore::GetPrefColorValue(int32_t iPrefColor) { DWORD valRGB[12] = { 0xFF0000E8, 0xFFF40000, 0xFF00C800, 0xFFFCF41C, 0xFFC48444, 0xFF784830, 0xFFA04400, 0xFFF08050, 0xFF848484, 0xFFFFFFFF, 0xFF0094F8, 0xFFBC00C0 }; if (Inside(iPrefColor, 0, 11)) return valRGB[iPrefColor]; return 0xFFAAAAAA; } bool C4PlayerInfoCore::Load(C4Group &hGroup) { // New version StdStrBuf Source; if (hGroup.LoadEntryString(C4CFN_PlayerInfoCore,&Source)) { // Compile StdStrBuf GrpName = hGroup.GetFullName(); GrpName.Append(DirSep C4CFN_PlayerInfoCore); if (!CompileFromBuf_LogWarn(*this, Source, GrpName.getData())) return false; // Pref for AutoContextMenus is still undecided: default by player's control style if (OldPrefAutoContextMenu == -1) OldPrefAutoContextMenu = OldPrefControlStyle; // Determine true color from indexed pref color if (!PrefColorDw) PrefColorDw = GetPrefColorValue(PrefColor); // Validate colors PrefColorDw &= 0xffffff; PrefColor2Dw &= 0xffffff; // Validate name C4Markup::StripMarkup(PrefName); // Success return true; } // Old version no longer supported - sorry return false; } bool C4PlayerInfoCore::Save(C4Group &hGroup) { StdStrBuf Source, Name = hGroup.GetFullName(); Name.Append(DirSep C4CFN_PlayerInfoCore); if (!DecompileToBuf_Log(*this, &Source, Name.getData())) return false; if (!hGroup.Add(C4CFN_PlayerInfoCore,Source,false,true)) return false; hGroup.Delete("C4Player.ocb"); return true; } void C4PlayerInfoCore::Promote(int32_t iRank, C4RankSystem &rRanks) { Rank=iRank; SCopy(rRanks.GetRankName(Rank,true).getData(),RankName,C4MaxName); } bool C4PlayerInfoCore::CheckPromotion(C4RankSystem &rRanks) { if (TotalScore>=rRanks.Experience(Rank+1)) { Promote(Rank+1,rRanks); return true; } return false; } void C4PlayerInfoCore::CompileFunc(StdCompiler *pComp) { C4ValueNumbers numbers; pComp->Name("Player"); pComp->Value(mkNamingAdapt(toC4CStr(PrefName),"Name", "Neuling")); pComp->Value(mkNamingAdapt(toC4CStr(Comment), "Comment", "")); pComp->Value(mkNamingAdapt(Rank, "Rank", 0)); pComp->Value(mkNamingAdapt(toC4CStr(RankName),"RankName", LoadResStr("IDS_MSG_RANK"))); // TODO: check if this would be desirable pComp->Value(mkNamingAdapt(TotalScore, "Score", 0)); pComp->Value(mkNamingAdapt(Rounds, "Rounds", 0)); pComp->Value(mkNamingAdapt(RoundsWon, "RoundsWon", 0)); pComp->Value(mkNamingAdapt(RoundsLost, "RoundsLost", 0)); pComp->Value(mkNamingAdapt(TotalPlayingTime, "TotalPlayingTime", 0)); pComp->Value(mkNamingAdapt(mkParAdapt(ExtraData, &numbers), "ExtraData", C4ValueMapData())); pComp->Value(mkNamingAdapt(numbers, "ExtraDataValues")); if (pComp->isCompiler()) { numbers.Denumerate(); ExtraData.Denumerate(&numbers); } pComp->Value(mkNamingAdapt(toC4CStr(LeagueName),"LeagueName", "")); pComp->NameEnd(); pComp->Name("Preferences"); pComp->Value(mkNamingAdapt(PrefColor, "Color", 0)); pComp->Value(mkNamingAdapt(PrefColorDw, "ColorDw", 0xffu)); pComp->Value(mkNamingAdapt(PrefColor2Dw, "AlternateColorDw", 0u)); pComp->Value(mkNamingAdapt(PrefPosition, "Position", 0)); pComp->Value(mkNamingAdapt(PrefMouse, "Mouse", 1)); pComp->Value(mkNamingAdapt(OldPrefControl, "Control", 1)); pComp->Value(mkNamingAdapt(OldPrefControlStyle, "AutoStopControl", 0)); pComp->Value(mkNamingAdapt(OldPrefAutoContextMenu, "AutoContextMenu", -1)); // compiling default is -1 (if this is detected, AutoContextMenus will be defaulted by control style) pComp->Value(mkNamingAdapt(PrefControl, "ControlSet", StdStrBuf())); pComp->Value(mkNamingAdapt(PrefClonkSkin, "ClonkSkin", 0)); pComp->NameEnd(); pComp->Value(mkNamingAdapt(LastRound, "LastRound")); pComp->Value(mkNamingAdapt(Achievements, "Achievements")); } //------------------------------- Object Info ---------------------------------------- C4ObjectInfoCore::C4ObjectInfoCore() { Default(); } void C4ObjectInfoCore::Default(C4ID n_id, C4DefList *pDefs, const char *cpNames) { // Def C4Def *pDef=NULL; if (pDefs) pDef = pDefs->ID2Def(n_id); // Defaults id=n_id; Participation=1; Rank=0; Experience=0; Rounds=0; DeathCount=0; Birthday=0; TotalPlayingTime=0; SCopy("Clonk",Name,C4MaxName); SCopy("Clonk",TypeName,C4MaxName); sRankName.Copy("Clonk"); sNextRankName.Clear(); NextRankExp=0; DeathMessage[0]='\0'; Age=0; ExtraData.Reset(); // Type if (pDef) SCopy(pDef->GetName(),TypeName,C4MaxName); // Name if (cpNames) { SCopySegment(cpNames,Random(SCharCount(0x0A,cpNames)),Name,0x0A,C4MaxName+1); SClearFrontBack(Name); SReplaceChar(Name,0x0D,0x00); if (!Name[0]) SCopy("Clonk",Name,C4MaxName); } if (pDefs) UpdateCustomRanks(pDefs); } void C4ObjectInfoCore::Promote(int32_t iRank, C4RankSystem &rRanks, bool fForceRankName) { Rank=iRank; // copy new rank name if defined only, or forced to use highest defined rank for too high info ranks StdStrBuf sNewRank(rRanks.GetRankName(Rank,fForceRankName)); if (sNewRank) sRankName.Copy(sNewRank); } void C4ObjectInfoCore::UpdateCustomRanks(C4DefList *pDefs) { assert(pDefs); C4Def *pDef = pDefs->ID2Def(id); if (!pDef) return; if (pDef->pRankNames) { StdStrBuf sRank(pDef->pRankNames->GetRankName(Rank,false)); if (sRank) sRankName.Copy(sRank); // next rank data StdStrBuf sNextRank(pDef->pRankNames->GetRankName(Rank+1,false)); if (sNextRank) { sNextRankName.Copy(sNextRank); NextRankExp = pDef->pRankNames->Experience(Rank+1); } else { // no more promotion possible by custom rank system sNextRankName.Clear(); NextRankExp = C4RankSystem::EXP_NoPromotion; } } else { // definition does not have custom rank names sNextRankName.Clear(); NextRankExp = 0; } } bool C4ObjectInfoCore::GetNextRankInfo(C4RankSystem &rDefaultRanks, int32_t *piNextRankExp, StdStrBuf *psNextRankName) { int32_t iNextRankExp; // custom rank assigned? if (NextRankExp) { iNextRankExp = NextRankExp; if (psNextRankName) psNextRankName->Copy(sNextRankName); } else { // no custom rank: Get from default set StdStrBuf sRank(rDefaultRanks.GetRankName(Rank+1, false)); if (sRank) { iNextRankExp = rDefaultRanks.Experience(Rank+1); if (psNextRankName) psNextRankName->Copy(sRank); } else // no more promotion iNextRankExp = C4RankSystem::EXP_NoPromotion; } // return result if (piNextRankExp) *piNextRankExp = iNextRankExp; // return value is whether additional promotion is possible return iNextRankExp != C4RankSystem::EXP_NoPromotion; } bool C4ObjectInfoCore::Load(C4Group &hGroup) { StdStrBuf Source; return hGroup.LoadEntryString(C4CFN_ObjectInfoCore, &Source) && Compile(Source.getData()); } bool C4ObjectInfoCore::Save(C4Group &hGroup, C4DefList *pDefs) { // rank overload by def: Update any NextRank-stuff if (pDefs) UpdateCustomRanks(pDefs); char *Buffer; size_t BufferSize; if (!Decompile(&Buffer,&BufferSize)) return false; if (!hGroup.Add(C4CFN_ObjectInfoCore,Buffer,BufferSize,false,true) ) { delete [] Buffer; return false; } return true; } void C4ObjectInfoCore::CompileFunc(StdCompiler *pComp) { C4ValueNumbers numbers; pComp->Value(mkNamingAdapt(id, "id", C4ID::None)); pComp->Value(mkNamingAdapt(toC4CStr(Name), "Name", "Clonk")); pComp->Value(mkNamingAdapt(toC4CStr(DeathMessage), "DeathMessage", "")); pComp->Value(mkNamingAdapt(Rank, "Rank", 0)); pComp->Value(mkNamingAdapt(sRankName, "RankName", "Clonk")); pComp->Value(mkNamingAdapt(sNextRankName, "NextRankName", "")); pComp->Value(mkNamingAdapt(toC4CStr(TypeName), "TypeName", "Clonk")); pComp->Value(mkNamingAdapt(Participation, "Participation", 1)); pComp->Value(mkNamingAdapt(Experience, "Experience", 0)); pComp->Value(mkNamingAdapt(NextRankExp, "NextRankExp", 0)); pComp->Value(mkNamingAdapt(Rounds, "Rounds", 0)); pComp->Value(mkNamingAdapt(DeathCount, "DeathCount", 0)); pComp->Value(mkNamingAdapt(Birthday, "Birthday", 0)); pComp->Value(mkNamingAdapt(TotalPlayingTime, "TotalPlayingTime", 0)); pComp->Value(mkNamingAdapt(Age, "Age", 0)); pComp->Value(mkNamingAdapt(mkParAdapt(ExtraData, &numbers), "ExtraData", C4ValueMapData())); pComp->Value(mkNamingAdapt(numbers, "ExtraDataValues")); if (pComp->isCompiler()) { numbers.Denumerate(); ExtraData.Denumerate(&numbers); } } bool C4ObjectInfoCore::Compile(const char *szSource) { bool ret = CompileFromBuf_LogWarn( mkNamingAdapt(*this, "ObjectInfo"), StdStrBuf(szSource), "ObjectInfo"); // DeathMessages are not allowed to stay forever if ('@' == DeathMessage[0]) DeathMessage[0] = ' '; return ret; } bool C4ObjectInfoCore::Decompile(char **ppOutput, size_t *ipSize) { StdStrBuf Buf; if (!DecompileToBuf_Log( mkNamingAdapt(*this, "ObjectInfo"), &Buf, "ObjectInfo")) { if (ppOutput) *ppOutput = NULL; if (ipSize) *ipSize = 0; return false; } if (ppOutput) *ppOutput = Buf.GrabPointer(); if (ipSize) *ipSize = Buf.getSize(); return true; } //------------------------------- Round Info ------------------------------------------ void C4RoundResult::Default() { InplaceReconstruct(this); } void C4RoundResult::CompileFunc(StdCompiler *pComp) { pComp->Value(mkNamingAdapt(Title, "Title", "")); pComp->Value(mkNamingAdapt(Date, "Date", 0u)); pComp->Value(mkNamingAdapt(Duration, "Duration", 0)); pComp->Value(mkNamingAdapt(Won, "Won", 0)); pComp->Value(mkNamingAdapt(Score, "Score", 0)); pComp->Value(mkNamingAdapt(FinalScore, "FinalScore", 0)); pComp->Value(mkNamingAdapt(TotalScore, "TotalScore", 0)); pComp->Value(mkNamingAdapt(Bonus, "Bonus", 0)); pComp->Value(mkNamingAdapt(Level, "Level", 0)); }