1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-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 #include "C4Include.h"
17 #include "player/C4ScenarioParameters.h"
18 #include "c4group/C4Components.h"
19 #include "script/C4Aul.h"
20
21 // *** C4ScenarioParameters
22
CompileFunc(StdCompiler * pComp)23 void C4ScenarioParameterDef::Option::CompileFunc(StdCompiler *pComp)
24 {
25 if (!pComp->Name("Option")) { pComp->NameEnd(); pComp->excNotFound("Option"); }
26 pComp->Value(mkNamingAdapt(mkParAdapt(Name, StdCompiler::RCT_All), "Name", StdCopyStrBuf()));
27 pComp->Value(mkNamingAdapt(mkParAdapt(Description, StdCompiler::RCT_All), "Description", StdCopyStrBuf()));
28 pComp->Value(mkNamingAdapt( Value, "Value", 0));
29 pComp->NameEnd();
30 }
31
GetOptionByValue(int32_t val) const32 const C4ScenarioParameterDef::Option *C4ScenarioParameterDef::GetOptionByValue(int32_t val) const
33 {
34 // search option by value
35 for (const auto & Option : Options)
36 if (Option.Value == val)
37 return &Option;
38 return nullptr;
39 }
40
GetOptionByIndex(size_t idx) const41 const C4ScenarioParameterDef::Option *C4ScenarioParameterDef::GetOptionByIndex(size_t idx) const
42 {
43 if (idx >= Options.size()) return nullptr;
44 return &Options[idx];
45 }
46
CompileFunc(StdCompiler * pComp)47 void C4ScenarioParameterDef::CompileFunc(StdCompiler *pComp)
48 {
49 if (!pComp->Name("ParameterDef")) { pComp->NameEnd(); pComp->excNotFound("ParameterDef"); }
50 pComp->Value(mkNamingAdapt(mkParAdapt(Name, StdCompiler::RCT_All), "Name", StdCopyStrBuf()));
51 pComp->Value(mkNamingAdapt(mkParAdapt(Description, StdCompiler::RCT_All), "Description", StdCopyStrBuf()));
52 pComp->Value(mkNamingAdapt(mkParAdapt(ID, StdCompiler::RCT_Idtf), "ID", StdCopyStrBuf()));
53 StdEnumEntry<ParameterType> ParTypeEntries[] =
54 {
55 { "Enumeration", SPDT_Enum },
56 { nullptr, SPDT_Enum }
57 };
58 pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(Type, ParTypeEntries), "Type", SPDT_Enum));
59 pComp->Value(mkNamingAdapt(Default, "Default", 0));
60 pComp->Value(mkNamingAdapt(LeagueValue, "LeagueValue", 0));
61 pComp->Value(mkNamingAdapt(mkParAdapt(Achievement, StdCompiler::RCT_Idtf), "Achievement", StdCopyStrBuf()));
62 pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(Options, StdCompiler::SEP_NONE), "Options"));
63 pComp->NameEnd();
64 }
65
CompileFunc(StdCompiler * pComp)66 void C4ScenarioParameterDefs::CompileFunc(StdCompiler *pComp)
67 {
68 pComp->Value(mkSTLContainerAdapt(Parameters, StdCompiler::SEP_NONE));
69 }
70
GetParameterDefByIndex(size_t idx) const71 const C4ScenarioParameterDef *C4ScenarioParameterDefs::GetParameterDefByIndex(size_t idx) const
72 {
73 if (idx >= Parameters.size()) return nullptr;
74 return &Parameters[idx];
75 }
76
Load(C4Group & hGroup,C4LangStringTable * pLang)77 bool C4ScenarioParameterDefs::Load(C4Group &hGroup, C4LangStringTable *pLang)
78 {
79 // Load buffer, localize and parse
80 StdStrBuf Buf;
81 if (!hGroup.LoadEntryString(C4CFN_ScenarioParameterDefs,&Buf)) return false;
82 if (pLang) pLang->ReplaceStrings(Buf);
83 if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(*this, Buf, C4CFN_ScenarioParameterDefs))
84 { return false; }
85 return true;
86 }
87
RegisterScriptConstants(const C4ScenarioParameters & values)88 void C4ScenarioParameterDefs::RegisterScriptConstants(const C4ScenarioParameters &values)
89 {
90 // register constants for all parameters in script engine
91
92 // old-style: one constant per parameter
93 for (const auto & Parameter : Parameters)
94 {
95 StdStrBuf constant_name;
96 constant_name.Format("SCENPAR_%s", Parameter.GetID());
97 int32_t constant_value = values.GetValueByID(Parameter.GetID(), Parameter.GetDefault());
98 ::ScriptEngine.RegisterGlobalConstant(constant_name.getData(), C4VInt(constant_value));
99 }
100
101 // new-style: all constants in a proplist
102 auto scenpar = C4PropList::NewStatic(nullptr, nullptr, &Strings.P[P_SCENPAR]);
103 for (const auto & Parameter : Parameters)
104 {
105 int32_t constant_value = values.GetValueByID(Parameter.GetID(), Parameter.GetDefault());
106 scenpar->SetPropertyByS(Strings.RegString(StdStrBuf(Parameter.GetID())), C4VInt(constant_value));
107 }
108 scenpar->Freeze();
109 ::ScriptEngine.RegisterGlobalConstant("SCENPAR", C4Value(scenpar));
110 }
111
Clear()112 void C4ScenarioParameters::Clear()
113 {
114 Parameters.clear();
115 }
116
Merge(const C4ScenarioParameters & other)117 void C4ScenarioParameters::Merge(const C4ScenarioParameters &other)
118 {
119 // Merge lists and keep larger value
120 for (const auto & Parameter : other.Parameters)
121 {
122 auto j = Parameters.find(Parameter.first);
123 if (j != Parameters.end())
124 if (j->second >= Parameter.second)
125 continue; // existing value is same or larger - keep old
126 // update to new value from other list
127 Parameters[Parameter.first] = Parameter.second;
128 }
129 }
130
GetValueByID(const char * id,int32_t default_value) const131 int32_t C4ScenarioParameters::GetValueByID(const char *id, int32_t default_value) const
132 {
133 // return map value if name is in map. Otherwise, return default value.
134 auto i = Parameters.find(StdStrBuf(id));
135 if (i != Parameters.end()) return i->second; else return default_value;
136 }
137
SetValue(const char * id,int32_t value,bool only_if_larger)138 void C4ScenarioParameters::SetValue(const char *id, int32_t value, bool only_if_larger)
139 {
140 if (only_if_larger)
141 {
142 auto i = Parameters.find(StdStrBuf(id));
143 if (i != Parameters.end())
144 if (i->second >= value)
145 // could become smaller. don't set.
146 return;
147 }
148 // just update map
149 Parameters[StdCopyStrBuf(id)] = value;
150 }
151
CompileFunc(StdCompiler * pComp)152 void C4ScenarioParameters::CompileFunc(StdCompiler *pComp)
153 {
154 // Unfortunately, StdCompiler cannot save std::map yet
155 if (pComp->isDeserializer())
156 {
157 Parameters.clear();
158 if (pComp->hasNaming())
159 {
160 // load from INI
161 size_t name_count = pComp->NameCount();
162 for (size_t i=0; i<name_count; ++i)
163 {
164 int32_t v=0;
165 const char *name = pComp->GetNameByIndex(0); // always get name index 0, because names are removed after values have been extracted for them
166 StdCopyStrBuf sName(name);
167 if (!name) continue;
168 pComp->Value(mkNamingAdapt(v, sName.getData(), 0));
169 Parameters[sName] = v;
170 }
171 }
172 else
173 {
174 // load from binary
175 int32_t name_count=0;
176 pComp->Value(name_count);
177 for (int32_t i=0; i<name_count; ++i)
178 {
179 StdCopyStrBuf name; int32_t v;
180 pComp->Value(name);
181 pComp->Value(v);
182 Parameters[name] = v;
183 }
184 }
185 }
186 else
187 {
188 if (pComp->hasNaming())
189 {
190 // save to INI
191 for (auto & Parameter : Parameters)
192 pComp->Value(mkNamingAdapt(Parameter.second, Parameter.first.getData()));
193 }
194 else
195 {
196 // save to binary
197 int32_t name_count=Parameters.size();
198 pComp->Value(name_count);
199 for (auto & Parameter : Parameters)
200 {
201 pComp->Value(const_cast<StdCopyStrBuf &>(Parameter.first));
202 pComp->Value(Parameter.second);
203 }
204 }
205 }
206 }
207
AddFilename2ID(const char * filename,const char * id)208 StdStrBuf C4ScenarioParameters::AddFilename2ID(const char *filename, const char *id)
209 {
210 // composes an ID string that contains both the relevant part of the filename and the ID
211 // we care for .oc* folders only
212 StdStrBuf sResult, sSource(filename, true), sPart;
213 sSource.ReplaceChar(AltDirectorySeparator, DirectorySeparator);
214 size_t idx=0;
215 while (sSource.GetSection(idx++, &sPart, DirectorySeparator))
216 {
217 size_t len = sPart.getLength();
218 if (len > 4 && SEqual2NoCase(sPart.getPtr(len - 4), ".oc", 3))
219 {
220 // .oc* folders separated by underscores
221 sResult.Append(sPart.getData(), len - 4);
222 sResult.AppendChar('_');
223 }
224 }
225 sResult.Append(id);
226 return sResult;
227 }
228