1 /**
2 Base Material & Production
3 Library to control the players base material and production. The initial values are read
4 from the Scenario.txt entries and per script one can modify these by:
5 * GetBaseMaterial(int player, id material, int index, int category)
6 * SetBaseMaterial(int player, id material, int amount)
7 * DoBaseMaterial(int player, id material, int change)
8 * GetBaseProduction(int player, id material, int index, int category)
9 * SetBaseProduction(int player, id material, int amount)
10 * DoBaseProduction(int player, id material, int change)
11 Performs also two callbacks to a base of the player:
12 * OnBaseMaterialChange(id material, int change);
13 * OnBaseProductionChange(id material, int change);
14
15 @author Randrian, Maikel
16 */
17
18
19 // Local variables to store the player's material and production.
20 // Is an array filled with [id, count] arrays.
21 local base_material;
22 local base_production;
23 local production_unit = 0;
24
25 // Maximum number of material.
26 static const BASEMATERIAL_MaxBaseMaterial = 25;
27 // Maximum number of production.
28 static const BASEMATERIAL_MaxBaseProduction = 10;
29 // Produce every X frames (currently set to a minute).
30 static const BASEMATERIAL_ProductionRate = 2160;
31
32
33 /*-- Global interface --*/
34
GetBaseMaterial(int player,id material,int index,int category)35 global func GetBaseMaterial(int player, id material, int index, int category)
36 {
37 var base = Library_BaseMaterial->GetBaseMaterialManager(player);
38 if (base)
39 return base->GetBaseMat(material, index, category);
40 }
41
SetBaseMaterial(int player,id material,int amount)42 global func SetBaseMaterial(int player, id material, int amount)
43 {
44 var base = Library_BaseMaterial->GetBaseMaterialManager(player);
45 if (base)
46 return base->SetBaseMat(material, amount);
47 }
48
DoBaseMaterial(int player,id material,int change)49 global func DoBaseMaterial(int player, id material, int change)
50 {
51 var base = Library_BaseMaterial->GetBaseMaterialManager(player);
52 if (base)
53 return base->DoBaseMat(material, change);
54 }
55
GetBaseProduction(int player,id material,int index,int category)56 global func GetBaseProduction(int player, id material, int index, int category)
57 {
58 var base = Library_BaseMaterial->GetBaseMaterialManager(player);
59 if (base)
60 return base->GetBaseProd(material, index, category);
61 }
62
SetBaseProduction(int player,id material,int amount)63 global func SetBaseProduction(int player, id material, int amount)
64 {
65 var base = Library_BaseMaterial->GetBaseMaterialManager(player);
66 if (base)
67 return base->SetBaseProd(material, amount);
68 }
69
DoBaseProduction(int player,id material,int change)70 global func DoBaseProduction(int player, id material, int change)
71 {
72 var base = Library_BaseMaterial->GetBaseMaterialManager(player);
73 if (base)
74 return base->DoBaseProd(material, change);
75 }
76
77
78 /*-- Definition Interface --*/
79
GetBaseMaterialManager(int player)80 protected func GetBaseMaterialManager(int player)
81 {
82 var base = FindObject(Find_ID(Library_BaseMaterial), Find_AnyLayer(), Find_Owner(player));
83 if (!base)
84 {
85 base = CreateObject(Library_BaseMaterial, 0, 0, player);
86 }
87 return base;
88 }
89
90 /*-- Object Interface --*/
91
Initialize()92 protected func Initialize()
93 {
94 // Gather base materials based on Scenario.txt player entries.
95 // TODO: Check teams and get the fitting player section
96 var player = GetOwner() % 4 + 1;
97 var section = Format("Player%d", player);
98
99 // Initialize arrays for material and production.
100 base_material = [];
101 base_production = [];
102
103 // Load materials from Scenario.txt
104 var index;
105 var material, count;
106 while (true)
107 {
108 material = GetScenarioVal("BaseMaterial", section, index * 2);
109 count = GetScenarioVal("BaseMaterial", section, index * 2 + 1);
110 if (!material && !count) break;
111 if (material)
112 {
113 PushBack(base_material, [material, count]);
114 }
115 index++;
116 }
117
118 // Load production from Scenario.txt
119 index = 0;
120 while (true)
121 {
122 material = GetScenarioVal("BaseProduction", section, index * 2);
123 count = GetScenarioVal("BaseProduction", section, index * 2 + 1);
124 if (!material && !count) break;
125 if (material)
126 {
127 PushBack(base_production, [material, count]);
128 }
129 index++;
130 }
131
132 // Add a timer for executing base production.
133 AddTimer("ExecBaseProduction", BASEMATERIAL_ProductionRate);
134 return;
135 }
136
137 // Called every minute and updates the materials according to production.
ExecBaseProduction()138 public func ExecBaseProduction()
139 {
140 production_unit++;
141 // Look at all production.
142 for (var combo in base_production)
143 {
144 // Check if this id is produced and check if it isn't already full.
145 if (combo[1] > 0 && GetBaseMat(combo[0]) < BASEMATERIAL_MaxBaseMaterial)
146 {
147 // Produce the material every production value / BASEMATERIAL_MaxBaseProduction times.
148 if (production_unit % BoundBy(BASEMATERIAL_MaxBaseProduction + 1 - combo[1], 1, BASEMATERIAL_MaxBaseProduction) == 0)
149 DoBaseMat(combo[0], 1);
150 }
151 }
152 return;
153 }
154
GetBaseMat(id material,int index,int category)155 public func GetBaseMat(id material, int index, int category)
156 {
157 // Get the count if the id is given.
158 if (material)
159 {
160 for (var combo in base_material)
161 if (combo[0] == material)
162 return combo[1];
163 return nil;
164 }
165 // If an index is given look for the id.
166 category = category ?? 0xffffff;
167 index = Max(0, index);
168 var count = 0;
169 for (var combo in base_material)
170 {
171 if (combo[0]->GetCategory() & category)
172 {
173 if (count == index)
174 {
175 return combo[0];
176 }
177 count++;
178 }
179 }
180 return;
181 }
182
SetBaseMat(id material,int amount)183 public func SetBaseMat(id material, int amount)
184 {
185 if (amount == nil)
186 return;
187 amount = Max(0, amount);
188 var change = 0;
189 // Scan through current list of id's and set material if available.
190 var found = false;
191 for (var index = 0; index < GetLength(base_material); ++index)
192 {
193 if (base_material[index][0] == material)
194 {
195 change = amount - base_material[index][1];
196 if (amount > 0)
197 {
198 base_material[index][1] = amount;
199 }
200 else
201 {
202 RemoveArrayIndex(base_material, index);
203 }
204 found = true;
205 break;
206 }
207 }
208 // If material is not available add it to the existing list.
209 if (!found && amount > 0)
210 {
211 change = amount;
212 PushBack(base_material, [material, amount]);
213 }
214 // Callback to the bases of the player.
215 BroadcastBaseMaterialChange(material, change);
216 return;
217 }
218
DoBaseMat(id material,int change)219 public func DoBaseMat(id material, int change)
220 {
221 if (change == 0)
222 return;
223 // Scan through current list of id's and increase material if available.
224 var found = false;
225 for (var index = 0; index < GetLength(base_material); ++index)
226 {
227 if (base_material[index][0] == material)
228 {
229 // Change must at least be minus the original value.
230 change = Max(change, -base_material[index][1]);
231 base_material[index][1] += change;
232 if (base_material[index][1] == 0)
233 {
234 RemoveArrayIndex(base_material, index);
235 }
236 found = true;
237 break;
238 }
239 }
240 // If material is not available add it to the existing list.
241 if (!found)
242 {
243 // Change must at least be zero.
244 change = Max(change, 0);
245 if (change > 0)
246 {
247 PushBack(base_material, [material, change]);
248 }
249 }
250 // Callback to the bases of the player.
251 BroadcastBaseMaterialChange(material, change);
252 return;
253 }
254
GetBaseProd(id material,int index,int category)255 public func GetBaseProd(id material, int index, int category)
256 {
257 // Get the count if the id is given.
258 if (material)
259 {
260 for (var combo in base_production)
261 if (combo[0] == material)
262 return combo[1];
263 return;
264 }
265 // If an index is given look for the id.
266 category = category ?? 0xffffff;
267 index = Max(0, index);
268 var count = 0;
269 for (var combo in base_production)
270 {
271 if (combo[0]->GetCategory() & category)
272 {
273 if (count == index)
274 {
275 return combo[0];
276 }
277 count++;
278 }
279 }
280 return;
281 }
282
SetBaseProd(id material,int amount)283 public func SetBaseProd(id material, int amount)
284 {
285 if (amount == nil)
286 return;
287 amount = Max(0, amount);
288 var change = 0;
289 // Scan through current list of id's and set production if available.
290 var found = false;
291 for (var index = 0; index < GetLength(base_production); ++index)
292 {
293 if (base_production[index][0] == material)
294 {
295 change = amount - base_production[index][1];
296 if (amount > 0)
297 {
298 base_production[index][1] = amount;
299 }
300 else
301 {
302 RemoveArrayIndex(base_production, index);
303 }
304 found = true;
305 break;
306 }
307 }
308 // If material is not available add it to the existing list.
309 if (!found && amount > 0)
310 {
311 change = amount;
312 PushBack(base_production, [material, amount]);
313 }
314 // Callback to the bases of the player.
315 BroadcastBaseProductionChange(material, change);
316 return;
317 }
318
DoBaseProd(id material,int change)319 public func DoBaseProd(id material, int change)
320 {
321 if (change == 0)
322 return;
323 // Scan through current list of id's and increase production if available.
324 var found = false;
325 for (var index = 0; index < GetLength(base_production); ++index)
326 {
327 if (base_production[index][0] == material)
328 {
329 // Change must at least be minus the original value.
330 change = Max(change, -base_production[index][1]);
331 base_production[index][1] += change;
332 if (base_production[index][1] == 0)
333 {
334 RemoveArrayIndex(base_production, index);
335 }
336 found = true;
337 break;
338 }
339 }
340 // If production is not available add it to the existing list.
341 if (!found)
342 {
343 // Change must at least be zero.
344 change = Max(change, 0);
345 if (change > 0)
346 {
347 PushBack(base_production, [material, change]);
348 }
349 }
350 // Callback to the bases of the player.
351 BroadcastBaseProductionChange(material, change);
352 return;
353 }
354
355
356 /*-- Miscellaneous --*/
357
BroadcastBaseProductionChange(id material,int change)358 protected func BroadcastBaseProductionChange(id material, int change)
359 {
360 var i = 0, base;
361 while (base = FindBase(GetOwner(), i++))
362 base->~OnBaseProductionChange(material, change);
363 }
364
BroadcastBaseMaterialChange(id material,int change)365 protected func BroadcastBaseMaterialChange(id material, int change)
366 {
367 var i = 0, base;
368 while (base = FindBase(GetOwner(), i++))
369 base->~OnBaseMaterialChange(material, change);
370 }
371
372 // Internal management object not saved. Use Scenario.txt or script
373 // to adjust base materials and production.
SaveScenarioObject()374 func SaveScenarioObject() { return false; }
375