1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 
20 /* Author: Paul Grathwohl */
21 
22 #include "game/logic/upgradecalculator.h"
23 #include "utility/log.h"
24 #include "main.h"
25 #include "game/data/units/unitdata.h"
26 #include <sstream>
27 
28 //--------------------------------------------------
instance()29 cUpgradeCalculator& cUpgradeCalculator::instance()
30 {
31 	static cUpgradeCalculator _instance;
32 	// do the setup on the first call, not on startup of the program
33 	if (!_instance.setupDone)
34 		_instance.setupLookupTables();
35 	return _instance;
36 }
37 
38 //--------------------------------------------------
cUpgradeCalculator()39 cUpgradeCalculator::cUpgradeCalculator()
40 	: setupDone (false)
41 {}
42 
43 //--------------------------------------------------
setupLookupTables()44 void cUpgradeCalculator::setupLookupTables()
45 {
46 	// ------------------------------ HITPOINTS and ARMOR and AMMO
47 	hitpointsArmorAmmo_2 [2] = 39;
48 	hitpointsArmorAmmo_2 [3] = 321;
49 
50 	hitpointsArmorAmmo_4 [4] = 8;
51 	hitpointsArmorAmmo_4 [5] = 31;
52 	hitpointsArmorAmmo_4 [6] = 91;
53 	hitpointsArmorAmmo_4 [7] = 230;
54 	hitpointsArmorAmmo_4 [8] = 513;
55 
56 	hitpointsArmorAmmo_6 [6]  = 4;
57 	hitpointsArmorAmmo_6 [7]  = 11;
58 	hitpointsArmorAmmo_6 [8]  = 24;
59 	hitpointsArmorAmmo_6 [9]  = 51;
60 	hitpointsArmorAmmo_6 [10] = 96;
61 	hitpointsArmorAmmo_6 [11] = 174;
62 	hitpointsArmorAmmo_6 [12] = 297;
63 	hitpointsArmorAmmo_6 [13] = 491;
64 	hitpointsArmorAmmo_6 [14] = 780;
65 
66 	hitpointsArmorAmmo_7 [7]  = 3;
67 	hitpointsArmorAmmo_7 [8]  = 8;
68 	hitpointsArmorAmmo_7 [9]  = 16;
69 	hitpointsArmorAmmo_7 [10] = 30;
70 	hitpointsArmorAmmo_7 [11] = 54;
71 	hitpointsArmorAmmo_7 [12] = 94;
72 	hitpointsArmorAmmo_7 [13] = 155;
73 	hitpointsArmorAmmo_7 [14] = 245;
74 	hitpointsArmorAmmo_7 [15] = 378;
75 	hitpointsArmorAmmo_7 [16] = 567;
76 
77 	hitpointsArmorAmmo_8  [8]  = 2;
78 	hitpointsArmorAmmo_8  [9]  = 6;
79 	hitpointsArmorAmmo_8  [10] = 11;
80 	hitpointsArmorAmmo_8  [11] = 20;
81 	hitpointsArmorAmmo_8  [12] = 35;
82 	hitpointsArmorAmmo_8  [13] = 56;
83 	hitpointsArmorAmmo_8  [14] = 91;
84 	hitpointsArmorAmmo_8  [15] = 139;
85 	hitpointsArmorAmmo_8  [16] = 208;
86 	hitpointsArmorAmmo_8  [17] = 305;
87 	hitpointsArmorAmmo_8  [18] = 438;
88 	hitpointsArmorAmmo_8  [19] = 617;
89 
90 	hitpointsArmorAmmo_9  [9]  = 2;
91 	hitpointsArmorAmmo_9  [10] = 5;
92 	hitpointsArmorAmmo_9  [11] = 8;
93 	hitpointsArmorAmmo_9  [12] = 14;
94 	hitpointsArmorAmmo_9  [13] = 23;
95 	hitpointsArmorAmmo_9  [14] = 38;
96 	hitpointsArmorAmmo_9  [15] = 57;
97 	hitpointsArmorAmmo_9  [16] = 86;
98 	hitpointsArmorAmmo_9  [17] = 127;
99 	hitpointsArmorAmmo_9  [18] = 181;
100 	hitpointsArmorAmmo_9  [19] = 254;
101 	hitpointsArmorAmmo_9  [20] = 353;
102 	hitpointsArmorAmmo_9  [21] = 480;
103 	hitpointsArmorAmmo_9  [22] = 645;
104 
105 	hitpointsArmorAmmo_10 [10] = 5;
106 	hitpointsArmorAmmo_10 [12] = 17;
107 	hitpointsArmorAmmo_10 [14] = 43;
108 	hitpointsArmorAmmo_10 [16] = 97;
109 	hitpointsArmorAmmo_10 [18] = 198;
110 	hitpointsArmorAmmo_10 [20] = 377;
111 	hitpointsArmorAmmo_10 [22] = 682;
112 
113 	hitpointsArmorAmmo_12 [12] = 4;
114 	hitpointsArmorAmmo_12 [14] = 11;
115 	hitpointsArmorAmmo_12 [16] = 24;
116 	hitpointsArmorAmmo_12 [18] = 51;
117 	hitpointsArmorAmmo_12 [20] = 96;
118 	hitpointsArmorAmmo_12 [22] = 174;
119 	hitpointsArmorAmmo_12 [24] = 297;
120 	hitpointsArmorAmmo_12 [26] = 491;
121 	hitpointsArmorAmmo_12 [28] = 780;
122 
123 	hitpointsArmorAmmo_14 [14] = 3;
124 	hitpointsArmorAmmo_14 [16] = 8;
125 	hitpointsArmorAmmo_14 [18] = 16;
126 	hitpointsArmorAmmo_14 [20] = 30;
127 	hitpointsArmorAmmo_14 [22] = 54;
128 	hitpointsArmorAmmo_14 [24] = 94;
129 	hitpointsArmorAmmo_14 [26] = 155;
130 	hitpointsArmorAmmo_14 [28] = 245;
131 	hitpointsArmorAmmo_14 [30] = 378;
132 	hitpointsArmorAmmo_14 [32] = 567;
133 
134 	hitpointsArmorAmmo_16 [16] = 2;
135 	hitpointsArmorAmmo_16 [18] = 6;
136 	hitpointsArmorAmmo_16 [20] = 11;
137 	hitpointsArmorAmmo_16 [22] = 20;
138 	hitpointsArmorAmmo_16 [24] = 35;
139 	hitpointsArmorAmmo_16 [26] = 56;
140 	hitpointsArmorAmmo_16 [28] = 91;
141 	hitpointsArmorAmmo_16 [30] = 139;
142 	hitpointsArmorAmmo_16 [32] = 208;
143 	hitpointsArmorAmmo_16 [34] = 305;
144 	hitpointsArmorAmmo_16 [36] = 438;
145 	hitpointsArmorAmmo_16 [38] = 617;
146 
147 	hitpointsArmorAmmo_18 [18] = 2;
148 	hitpointsArmorAmmo_18 [20] = 5;
149 	hitpointsArmorAmmo_18 [22] = 8;
150 	hitpointsArmorAmmo_18 [24] = 14;
151 	hitpointsArmorAmmo_18 [26] = 23;
152 	hitpointsArmorAmmo_18 [28] = 38;
153 	hitpointsArmorAmmo_18 [30] = 57;
154 	hitpointsArmorAmmo_18 [32] = 86;
155 	hitpointsArmorAmmo_18 [34] = 127;
156 	hitpointsArmorAmmo_18 [36] = 181;
157 	hitpointsArmorAmmo_18 [38] = 254;
158 	hitpointsArmorAmmo_18 [40] = 353;
159 	hitpointsArmorAmmo_18 [42] = 480;
160 	hitpointsArmorAmmo_18 [44] = 645;
161 
162 	hitpointsArmorAmmo_20 [20] = 2;
163 	hitpointsArmorAmmo_20 [22] = 3;
164 	hitpointsArmorAmmo_20 [24] = 7;
165 	hitpointsArmorAmmo_20 [26] = 10;
166 	hitpointsArmorAmmo_20 [28] = 17;
167 	hitpointsArmorAmmo_20 [30] = 26;
168 	hitpointsArmorAmmo_20 [32] = 40;
169 	hitpointsArmorAmmo_20 [34] = 57;
170 	hitpointsArmorAmmo_20 [36] = 82;
171 	hitpointsArmorAmmo_20 [38] = 116;
172 	hitpointsArmorAmmo_20 [40] = 160;
173 	hitpointsArmorAmmo_20 [42] = 217;
174 	hitpointsArmorAmmo_20 [44] = 293;
175 	hitpointsArmorAmmo_20 [46] = 389;
176 	hitpointsArmorAmmo_20 [48] = 509;
177 	hitpointsArmorAmmo_20 [50] = 660;
178 
179 	hitpointsArmorAmmo_24 [24] = 1;
180 	hitpointsArmorAmmo_24 [26] = 3;
181 	hitpointsArmorAmmo_24 [28] = 4;
182 	hitpointsArmorAmmo_24 [30] = 7;
183 	hitpointsArmorAmmo_24 [32] = 10;
184 	hitpointsArmorAmmo_24 [34] = 14;
185 	hitpointsArmorAmmo_24 [36] = 21;
186 	hitpointsArmorAmmo_24 [38] = 30;
187 	hitpointsArmorAmmo_24 [40] = 40;
188 	hitpointsArmorAmmo_24 [42] = 56;
189 	hitpointsArmorAmmo_24 [44] = 75;
190 	hitpointsArmorAmmo_24 [46] = 99;
191 	hitpointsArmorAmmo_24 [48] = 129;
192 	hitpointsArmorAmmo_24 [50] = 168;
193 	hitpointsArmorAmmo_24 [52] = 216;
194 	hitpointsArmorAmmo_24 [54] = 275;
195 	hitpointsArmorAmmo_24 [56] = 346;
196 	hitpointsArmorAmmo_24 [58] = 434;
197 	hitpointsArmorAmmo_24 [60] = 538;
198 	hitpointsArmorAmmo_24 [62] = 663;
199 
200 	hitpointsArmorAmmo_26 [26] = 5;
201 	hitpointsArmorAmmo_26 [31] = 15;
202 	hitpointsArmorAmmo_26 [36] = 38;
203 	hitpointsArmorAmmo_26 [41] = 84;
204 	hitpointsArmorAmmo_26 [46] = 168;
205 	hitpointsArmorAmmo_26 [51] = 319;
206 	hitpointsArmorAmmo_26 [56] = 567;
207 
208 	hitpointsArmorAmmo_28 [28] = 4;
209 	hitpointsArmorAmmo_28 [33] = 13;
210 	hitpointsArmorAmmo_28 [38] = 30;
211 	hitpointsArmorAmmo_28 [43] = 64;
212 	hitpointsArmorAmmo_28 [48] = 126;
213 	hitpointsArmorAmmo_28 [53] = 232;
214 	hitpointsArmorAmmo_28 [58] = 404;
215 	hitpointsArmorAmmo_28 [63] = 677;
216 
217 	hitpointsArmorAmmo_32 [32] = 3;
218 	hitpointsArmorAmmo_32 [37] = 10;
219 	hitpointsArmorAmmo_32 [42] = 20;
220 	hitpointsArmorAmmo_32 [47] = 41;
221 	hitpointsArmorAmmo_32 [52] = 75;
222 	hitpointsArmorAmmo_32 [57] = 134;
223 	hitpointsArmorAmmo_32 [62] = 225;
224 	hitpointsArmorAmmo_32 [67] = 365;
225 	hitpointsArmorAmmo_32 [72] = 574;
226 
227 	hitpointsArmorAmmo_36 [36] = 3;
228 	hitpointsArmorAmmo_36 [41] = 7;
229 	hitpointsArmorAmmo_36 [46] = 15;
230 	hitpointsArmorAmmo_36 [51] = 27;
231 	hitpointsArmorAmmo_36 [56] = 50;
232 	hitpointsArmorAmmo_36 [61] = 84;
233 	hitpointsArmorAmmo_36 [66] = 137;
234 	hitpointsArmorAmmo_36 [71] = 218;
235 	hitpointsArmorAmmo_36 [76] = 332;
236 	hitpointsArmorAmmo_36 [81] = 497;
237 	hitpointsArmorAmmo_36 [86] = 724;
238 
239 	hitpointsArmorAmmo_40 [40] = 2;
240 	hitpointsArmorAmmo_40 [45] = 6;
241 	hitpointsArmorAmmo_40 [50] = 11;
242 	hitpointsArmorAmmo_40 [55] = 20;
243 	hitpointsArmorAmmo_40 [60] = 35;
244 	hitpointsArmorAmmo_40 [65] = 56;
245 	hitpointsArmorAmmo_40 [70] = 91;
246 	hitpointsArmorAmmo_40 [75] = 139;
247 	hitpointsArmorAmmo_40 [80] = 208;
248 	hitpointsArmorAmmo_40 [85] = 305;
249 	hitpointsArmorAmmo_40 [90] = 438;
250 	hitpointsArmorAmmo_40 [95] = 617;
251 
252 	hitpointsArmorAmmo_56 [56]  = 4;
253 	hitpointsArmorAmmo_56 [66]  = 13;
254 	hitpointsArmorAmmo_56 [76]  = 30;
255 	hitpointsArmorAmmo_56 [86]  = 64;
256 	hitpointsArmorAmmo_56 [96]  = 126;
257 	hitpointsArmorAmmo_56 [106] = 232;
258 	hitpointsArmorAmmo_56 [116] = 404;
259 	hitpointsArmorAmmo_56 [126] = 677;
260 
261 
262 	// ------------------------------ ATTACK and SPEED
263 	attackSpeed_5  [5]  = 11;
264 	attackSpeed_5  [6]  = 34;
265 	attackSpeed_5  [7]  = 86;
266 	attackSpeed_5  [8]  = 193;
267 	attackSpeed_5  [9]  = 396;
268 	attackSpeed_5  [10] = 755;
269 
270 	attackSpeed_6  [6]  = 8;
271 	attackSpeed_6  [7]  = 22;
272 	attackSpeed_6  [8]  = 49;
273 	attackSpeed_6  [9]  = 101;
274 	attackSpeed_6  [10] = 193;
275 	attackSpeed_6  [11] = 347;
276 	attackSpeed_6  [12] = 595;
277 
278 	attackSpeed_7  [7]  = 6;
279 	attackSpeed_7  [8]  = 16;
280 	attackSpeed_7  [9]  = 32;
281 	attackSpeed_7  [10] = 60;
282 	attackSpeed_7  [11] = 109;
283 	attackSpeed_7  [12] = 188;
284 	attackSpeed_7  [13] = 309;
285 	attackSpeed_7  [14] = 490;
286 	attackSpeed_7  [15] = 757;
287 
288 	attackSpeed_8  [8]  = 5;
289 	attackSpeed_8  [9]  = 12;
290 	attackSpeed_8  [10] = 22;
291 	attackSpeed_8  [11] = 40;
292 	attackSpeed_8  [12] = 69;
293 	attackSpeed_8  [13] = 113;
294 	attackSpeed_8  [14] = 181;
295 	attackSpeed_8  [15] = 278;
296 	attackSpeed_8  [16] = 416;
297 	attackSpeed_8  [17] = 611;
298 
299 	attackSpeed_9  [9]  = 4;
300 	attackSpeed_9  [10] = 10;
301 	attackSpeed_9  [11] = 16;
302 	attackSpeed_9  [12] = 29;
303 	attackSpeed_9  [13] = 46;
304 	attackSpeed_9  [14] = 75;
305 	attackSpeed_9  [15] = 115;
306 	attackSpeed_9  [16] = 172;
307 	attackSpeed_9  [17] = 253;
308 	attackSpeed_9  [18] = 362;
309 	attackSpeed_9  [19] = 509;
310 	attackSpeed_9  [20] = 705;
311 
312 	attackSpeed_10 [10] = 11;
313 	attackSpeed_10 [12] = 34;
314 	attackSpeed_10 [14] = 86;
315 	attackSpeed_10 [16] = 193;
316 	attackSpeed_10 [18] = 396;
317 	attackSpeed_10 [20] = 755;
318 
319 	attackSpeed_11 [11] = 10;
320 	attackSpeed_11 [13] = 26;
321 	attackSpeed_11 [15] = 64;
322 	attackSpeed_11 [17] = 137;
323 	attackSpeed_11 [19] = 269;
324 	attackSpeed_11 [21] = 500;
325 
326 	attackSpeed_12 [12] = 8;
327 	attackSpeed_12 [14] = 22;
328 	attackSpeed_12 [16] = 49;
329 	attackSpeed_12 [18] = 101;
330 	attackSpeed_12 [20] = 193;
331 	attackSpeed_12 [22] = 347;
332 	attackSpeed_12 [24] = 595;
333 
334 	attackSpeed_14 [14] = 6;
335 	attackSpeed_14 [16] = 16;
336 	attackSpeed_14 [18] = 32;
337 	attackSpeed_14 [20] = 60;
338 	attackSpeed_14 [22] = 109;
339 	attackSpeed_14 [24] = 188;
340 	attackSpeed_14 [26] = 309;
341 	attackSpeed_14 [28] = 490;
342 	attackSpeed_14 [30] = 757;
343 
344 	attackSpeed_15 [15] = 6;
345 	attackSpeed_15 [17] = 13;
346 	attackSpeed_15 [19] = 26;
347 	attackSpeed_15 [21] = 49;
348 	attackSpeed_15 [23] = 86;
349 	attackSpeed_15 [25] = 144;
350 	attackSpeed_15 [27] = 233;
351 	attackSpeed_15 [29] = 364;
352 	attackSpeed_15 [31] = 554;
353 
354 	attackSpeed_16 [16] = 5;
355 	attackSpeed_16 [18] = 12;
356 	attackSpeed_16 [20] = 22;
357 	attackSpeed_16 [22] = 40;
358 	attackSpeed_16 [24] = 69;
359 	attackSpeed_16 [26] = 113;
360 	attackSpeed_16 [28] = 181;
361 	attackSpeed_16 [30] = 278;
362 	attackSpeed_16 [32] = 416;
363 	attackSpeed_16 [34] = 611;
364 
365 	attackSpeed_17 [17] = 5;
366 	attackSpeed_17 [19] = 10;
367 	attackSpeed_17 [21] = 19;
368 	attackSpeed_17 [23] = 34;
369 	attackSpeed_17 [25] = 56;
370 	attackSpeed_17 [27] = 91;
371 	attackSpeed_17 [29] = 143;
372 	attackSpeed_17 [31] = 216;
373 	attackSpeed_17 [33] = 321;
374 	attackSpeed_17 [35] = 466;
375 	attackSpeed_17 [37] = 661;
376 
377 	attackSpeed_18 [18] = 4;
378 	attackSpeed_18 [20] = 10;
379 	attackSpeed_18 [22] = 16;
380 	attackSpeed_18 [24] = 29;
381 	attackSpeed_18 [26] = 46;
382 	attackSpeed_18 [28] = 75;
383 	attackSpeed_18 [30] = 115;
384 	attackSpeed_18 [32] = 172;
385 	attackSpeed_18 [34] = 253;
386 	attackSpeed_18 [36] = 362;
387 	attackSpeed_18 [38] = 509;
388 	attackSpeed_18 [40] = 705;
389 
390 	attackSpeed_20 [20] = 4;
391 	attackSpeed_20 [22] = 7;
392 	attackSpeed_20 [24] = 13;
393 	attackSpeed_20 [26] = 21;
394 	attackSpeed_20 [28] = 34;
395 	attackSpeed_20 [30] = 52;
396 	attackSpeed_20 [32] = 79;
397 	attackSpeed_20 [34] = 114;
398 	attackSpeed_20 [36] = 164;
399 	attackSpeed_20 [38] = 232;
400 	attackSpeed_20 [40] = 320;
401 	attackSpeed_20 [42] = 435;
402 	attackSpeed_20 [44] = 586;
403 	attackSpeed_20 [46] = 777;
404 
405 	attackSpeed_22 [22] = 3;
406 	attackSpeed_22 [24] = 7;
407 	attackSpeed_22 [26] = 10;
408 	attackSpeed_22 [28] = 16;
409 	attackSpeed_22 [30] = 26;
410 	attackSpeed_22 [32] = 38;
411 	attackSpeed_22 [34] = 56;
412 	attackSpeed_22 [36] = 81;
413 	attackSpeed_22 [38] = 113;
414 	attackSpeed_22 [40] = 156;
415 	attackSpeed_22 [42] = 214;
416 	attackSpeed_22 [44] = 286;
417 	attackSpeed_22 [46] = 380;
418 	attackSpeed_22 [48] = 498;
419 	attackSpeed_22 [50] = 646;
420 
421 	attackSpeed_24 [24] = 3;
422 	attackSpeed_24 [26] = 5;
423 	attackSpeed_24 [28] = 9;
424 	attackSpeed_24 [30] = 13;
425 	attackSpeed_24 [32] = 20;
426 	attackSpeed_24 [34] = 29;
427 	attackSpeed_24 [36] = 42;
428 	attackSpeed_24 [38] = 59;
429 	attackSpeed_24 [40] = 81;
430 	attackSpeed_24 [42] = 112;
431 	attackSpeed_24 [44] = 149;
432 	attackSpeed_24 [46] = 198;
433 	attackSpeed_24 [48] = 259;
434 	attackSpeed_24 [50] = 336;
435 	attackSpeed_24 [52] = 432;
436 	attackSpeed_24 [54] = 549;
437 	attackSpeed_24 [56] = 693;
438 
439 	attackSpeed_28 [28] = 9;
440 	attackSpeed_28 [33] = 26;
441 	attackSpeed_28 [38] = 60;
442 	attackSpeed_28 [43] = 128;
443 	attackSpeed_28 [48] = 252;
444 	attackSpeed_28 [53] = 463;
445 
446 	attackSpeed_30 [30] = 8;
447 	attackSpeed_30 [35] = 22;
448 	attackSpeed_30 [40] = 49;
449 	attackSpeed_30 [45] = 101;
450 	attackSpeed_30 [50] = 193;
451 	attackSpeed_30 [55] = 347;
452 	attackSpeed_30 [60] = 595;
453 
454 	attackSpeed_36 [36] = 6;
455 	attackSpeed_36 [41] = 15;
456 	attackSpeed_36 [46] = 29;
457 	attackSpeed_36 [51] = 55;
458 	attackSpeed_36 [56] = 99;
459 	attackSpeed_36 [61] = 169;
460 	attackSpeed_36 [66] = 274;
461 	attackSpeed_36 [71] = 435;
462 	attackSpeed_36 [76] = 665;
463 
464 
465 	// ------------------------------ RANGE and SCAN
466 	rangeScan_3  [3] = 61;
467 	rangeScan_3  [4] = 299;
468 
469 	rangeScan_4  [4] = 34;
470 	rangeScan_4  [5] = 125;
471 	rangeScan_4  [6] = 364;
472 
473 	rangeScan_5  [5] = 23;
474 	rangeScan_5  [6] = 68;
475 	rangeScan_5  [7] = 172;
476 	rangeScan_5  [8] = 386;
477 	rangeScan_5  [9] = 791;
478 
479 	rangeScan_6  [6]  = 17;
480 	rangeScan_6  [7]  = 44;
481 	rangeScan_6  [8]  = 98;
482 	rangeScan_6  [9]  = 201;
483 	rangeScan_6  [10] = 386;
484 	rangeScan_6  [11] = 694;
485 
486 	rangeScan_7  [7]  = 13;
487 	rangeScan_7  [8]  = 31;
488 	rangeScan_7  [9]  = 64;
489 	rangeScan_7  [10] = 121;
490 	rangeScan_7  [11] = 218;
491 	rangeScan_7  [12] = 375;
492 	rangeScan_7  [13] = 618;
493 
494 	rangeScan_8  [8]  = 11;
495 	rangeScan_8  [9]  = 23;
496 	rangeScan_8  [10] = 45;
497 	rangeScan_8  [11] = 80;
498 	rangeScan_8  [12] = 138;
499 	rangeScan_8  [13] = 226;
500 	rangeScan_8  [14] = 361;
501 	rangeScan_8  [15] = 556;
502 
503 	rangeScan_9  [9]  = 9;
504 	rangeScan_9  [10] = 19;
505 	rangeScan_9  [11] = 33;
506 	rangeScan_9  [12] = 57;
507 	rangeScan_9  [13] = 93;
508 	rangeScan_9  [14] = 149;
509 	rangeScan_9  [15] = 230;
510 	rangeScan_9  [16] = 345;
511 	rangeScan_9  [17] = 505;
512 	rangeScan_9  [18] = 724;
513 
514 	rangeScan_10 [10] = 23;
515 	rangeScan_10 [12] = 68;
516 	rangeScan_10 [14] = 172;
517 	rangeScan_10 [16] = 386;
518 	rangeScan_10 [18] = 791;
519 
520 	rangeScan_11 [11] = 20;
521 	rangeScan_11 [13] = 53;
522 	rangeScan_11 [15] = 128;
523 	rangeScan_11 [17] = 273;
524 	rangeScan_11 [19] = 539;
525 
526 	rangeScan_12 [12] = 17;
527 	rangeScan_12 [14] = 44;
528 	rangeScan_12 [16] = 98;
529 	rangeScan_12 [18] = 201;
530 	rangeScan_12 [20] = 386;
531 	rangeScan_12 [22] = 694;
532 
533 	rangeScan_14 [14] = 13;
534 	rangeScan_14 [16] = 31;
535 	rangeScan_14 [18] = 64;
536 	rangeScan_14 [20] = 121;
537 	rangeScan_14 [22] = 218;
538 	rangeScan_14 [24] = 375;
539 	rangeScan_14 [26] = 618;
540 
541 	rangeScan_16 [16] = 11;
542 	rangeScan_16 [18] = 23;
543 	rangeScan_16 [20] = 45;
544 	rangeScan_16 [22] = 80;
545 	rangeScan_16 [24] = 138;
546 	rangeScan_16 [26] = 226;
547 	rangeScan_16 [28] = 361;
548 	rangeScan_16 [30] = 556;
549 
550 	rangeScan_18 [18] = 9;
551 	rangeScan_18 [20] = 19;
552 	rangeScan_18 [22] = 33;
553 	rangeScan_18 [24] = 57;
554 	rangeScan_18 [26] = 93;
555 	rangeScan_18 [28] = 149;
556 	rangeScan_18 [30] = 230;
557 	rangeScan_18 [32] = 345;
558 	rangeScan_18 [34] = 505;
559 	rangeScan_18 [36] = 724;
560 
561 	rangeScan_20 [20] = 8;
562 	rangeScan_20 [22] = 15;
563 	rangeScan_20 [24] = 26;
564 	rangeScan_20 [26] = 42;
565 	rangeScan_20 [28] = 68;
566 	rangeScan_20 [30] = 104;
567 	rangeScan_20 [32] = 157;
568 	rangeScan_20 [34] = 229;
569 	rangeScan_20 [36] = 328;
570 	rangeScan_20 [38] = 463;
571 	rangeScan_20 [40] = 640;
572 
573 	rangeScan_24 [24] = 6;
574 	rangeScan_24 [26] = 11;
575 	rangeScan_24 [28] = 17;
576 	rangeScan_24 [30] = 27;
577 	rangeScan_24 [32] = 40;
578 	rangeScan_24 [34] = 58;
579 	rangeScan_24 [36] = 84;
580 	rangeScan_24 [38] = 117;
581 	rangeScan_24 [40] = 163;
582 	rangeScan_24 [42] = 223;
583 	rangeScan_24 [44] = 298;
584 	rangeScan_24 [46] = 396;
585 	rangeScan_24 [48] = 518;
586 	rangeScan_24 [50] = 673;
587 
588 	// ------------------------------ SHOTS
589 	shots_1 [1] = 720;
590 
591 	shots_2 [2] = 79;
592 	shots_2 [3] = 641;
593 
594 	// finished....
595 	setupDone = true;
596 }
597 
598 //--------------------------------------------------
lookupPrice(const PriceMap & prices,int value) const599 int cUpgradeCalculator::lookupPrice (const PriceMap& prices, int value) const
600 {
601 	PriceMap::const_iterator it = prices.find (value);
602 	if (it != prices.end())
603 		return it->second; // the price
604 	return kNoPriceAvailable;
605 }
606 
607 //--------------------------------------------------
calcPrice(int curValue,int orgValue,int upgradeType,const cResearch & researchLevel) const608 int cUpgradeCalculator::calcPrice (int curValue, int orgValue, int upgradeType, const cResearch& researchLevel) const
609 {
610 	int bonusByResearch = calcChangeByResearch (orgValue, researchLevel.getCurResearchLevel (researchLevel.getResearchArea (upgradeType)));
611 	curValue -= bonusByResearch;
612 
613 	int price = kNoPriceAvailable;
614 	switch (upgradeType)
615 	{
616 
617 		case kHitpoints:
618 		case kArmor:
619 		case kAmmo:
620 		{
621 			switch (orgValue)
622 			{
623 				case 2:  price = lookupPrice (hitpointsArmorAmmo_2,  curValue); break;
624 				case 4:  price = lookupPrice (hitpointsArmorAmmo_4,  curValue); break;
625 				case 6:  price = lookupPrice (hitpointsArmorAmmo_6,  curValue); break;
626 				case 7:  price = lookupPrice (hitpointsArmorAmmo_7,  curValue); break;
627 				case 8:  price = lookupPrice (hitpointsArmorAmmo_8,  curValue); break;
628 				case 9:  price = lookupPrice (hitpointsArmorAmmo_9,  curValue); break;
629 				case 10: price = lookupPrice (hitpointsArmorAmmo_10, curValue); break;
630 				case 12: price = lookupPrice (hitpointsArmorAmmo_12, curValue); break;
631 				case 14: price = lookupPrice (hitpointsArmorAmmo_14, curValue); break;
632 				case 16: price = lookupPrice (hitpointsArmorAmmo_16, curValue); break;
633 				case 18: price = lookupPrice (hitpointsArmorAmmo_18, curValue); break;
634 				case 20: price = lookupPrice (hitpointsArmorAmmo_20, curValue); break;
635 				case 24: price = lookupPrice (hitpointsArmorAmmo_24, curValue); break;
636 				case 26: price = lookupPrice (hitpointsArmorAmmo_26, curValue); break;
637 				case 28: price = lookupPrice (hitpointsArmorAmmo_28, curValue); break;
638 				case 32: price = lookupPrice (hitpointsArmorAmmo_32, curValue); break;
639 				case 36: price = lookupPrice (hitpointsArmorAmmo_36, curValue); break;
640 				case 40: price = lookupPrice (hitpointsArmorAmmo_40, curValue); break;
641 				case 56: price = lookupPrice (hitpointsArmorAmmo_56, curValue); break;
642 				default: break;
643 			}
644 			break;
645 		}
646 
647 		case kAttack:
648 		case kSpeed:
649 		{
650 			switch (orgValue)
651 			{
652 				case 5:  price = lookupPrice (attackSpeed_5,  curValue); break;
653 				case 6:  price = lookupPrice (attackSpeed_6,  curValue); break;
654 				case 7:  price = lookupPrice (attackSpeed_7,  curValue); break;
655 				case 8:  price = lookupPrice (attackSpeed_8,  curValue); break;
656 				case 9:  price = lookupPrice (attackSpeed_9,  curValue); break;
657 				case 10: price = lookupPrice (attackSpeed_10, curValue); break;
658 				case 11: price = lookupPrice (attackSpeed_11, curValue); break;
659 				case 12: price = lookupPrice (attackSpeed_12, curValue); break;
660 				case 14: price = lookupPrice (attackSpeed_14, curValue); break;
661 				case 15: price = lookupPrice (attackSpeed_15, curValue); break;
662 				case 16: price = lookupPrice (attackSpeed_16, curValue); break;
663 				case 17: price = lookupPrice (attackSpeed_17, curValue); break;
664 				case 18: price = lookupPrice (attackSpeed_18, curValue); break;
665 				case 20: price = lookupPrice (attackSpeed_20, curValue); break;
666 				case 22: price = lookupPrice (attackSpeed_22, curValue); break;
667 				case 24: price = lookupPrice (attackSpeed_24, curValue); break;
668 				case 28: price = lookupPrice (attackSpeed_28, curValue); break;
669 				case 30: price = lookupPrice (attackSpeed_30, curValue); break;
670 				case 36: price = lookupPrice (attackSpeed_36, curValue); break;
671 				default: break;
672 			}
673 			break;
674 		}
675 
676 		case kRange:
677 		case kScan:
678 		{
679 			switch (orgValue)
680 			{
681 				case 3:  price = lookupPrice (rangeScan_3,  curValue); break;
682 				case 4:  price = lookupPrice (rangeScan_4,  curValue); break;
683 				case 5:  price = lookupPrice (rangeScan_5,  curValue); break;
684 				case 6:  price = lookupPrice (rangeScan_6,  curValue); break;
685 				case 7:  price = lookupPrice (rangeScan_7,  curValue); break;
686 				case 8:  price = lookupPrice (rangeScan_8,  curValue); break;
687 				case 9:  price = lookupPrice (rangeScan_9,  curValue); break;
688 				case 10: price = lookupPrice (rangeScan_10, curValue); break;
689 				case 11: price = lookupPrice (rangeScan_11, curValue); break;
690 				case 12: price = lookupPrice (rangeScan_12, curValue); break;
691 				case 14: price = lookupPrice (rangeScan_14, curValue); break;
692 				case 16: price = lookupPrice (rangeScan_16, curValue); break;
693 				case 18: price = lookupPrice (rangeScan_18, curValue); break;
694 				case 20: price = lookupPrice (rangeScan_20, curValue); break;
695 				case 24: price = lookupPrice (rangeScan_24, curValue); break;
696 				default: break;
697 			}
698 			break;
699 		}
700 
701 		case kShots:
702 		{
703 			switch (orgValue)
704 			{
705 				case 1:  price = lookupPrice (shots_1,  curValue); break;
706 				case 2:  price = lookupPrice (shots_2,  curValue); break;
707 				default: break;
708 			}
709 			break;
710 		}
711 
712 		default: break;
713 	}
714 	return price;
715 }
716 
717 //--------------------------------------------------
getCostForUpgrade(int orgValue,int curValue,int newValue,int upgradeType,cResearch & researchLevel) const718 int cUpgradeCalculator::getCostForUpgrade (int orgValue, int curValue, int newValue, int upgradeType, cResearch& researchLevel) const
719 {
720 	int cost = 0;
721 	if (orgValue <= curValue && curValue < newValue)
722 	{
723 		int upgradedValue = curValue;
724 		while (upgradedValue < newValue)
725 		{
726 			int costsForThis = calcPrice (upgradedValue, orgValue, upgradeType, researchLevel);
727 			if (costsForThis != kNoPriceAvailable)
728 			{
729 				cost += costsForThis;
730 				upgradedValue += calcIncreaseByUpgrade (orgValue);
731 				if (upgradedValue > newValue)
732 				{
733 					// it is not possible to reach the newValue with upgrading
734 					return kNoPriceAvailable;
735 				}
736 			}
737 			else
738 				return kNoPriceAvailable;
739 		}
740 	}
741 	return cost;
742 }
743 
744 //--------------------------------------------------
calcResearchTurns(int curResearchLevel,int upgradeType) const745 int cUpgradeCalculator::calcResearchTurns (int curResearchLevel, int upgradeType) const
746 {
747 	switch (upgradeType)
748 	{
749 		case kHitpoints:
750 		case kArmor:
751 		{
752 			const unsigned int index = curResearchLevel / 10;
753 			const int values[] =
754 			{
755 				8, 15, 25, 42, 67, 104, 156, 229, 328, 462,
756 				639, 871, 1171, 1553, 2036, 2640, 3389, 4311, 5437, 6803,
757 				8448
758 			};
759 
760 			if (index < sizeof (values) / sizeof (*values))
761 				return values[index];
762 			break;
763 		}
764 
765 		case kAttack:
766 		case kSpeed:
767 		case kShots:
768 		{
769 			const unsigned int index = curResearchLevel / 10;
770 			const int values[] =
771 			{
772 				16, 30, 51, 85, 135, 208, 312, 458, 657, 924,
773 				1278, 1742, 2342, 3106, 4072, 5280, 6778, 8622, 10874, 13606,
774 				16896
775 			};
776 
777 			if (index < sizeof (values) / sizeof (*values))
778 				return values[index];
779 			break;
780 		}
781 
782 		case kRange:
783 		case kScan:
784 		case kCost:
785 		{
786 			const unsigned int index = curResearchLevel / 10;
787 			const int values[] =
788 			{
789 				33, 60, 103, 170, 270, 416, 625, 916, 1314, 1849,
790 				2559, 3487, 4684, 6213, 8144, 10560, 13556, 17244, 21748, 27212,
791 				33792
792 			};
793 
794 			if (index < sizeof (values) / sizeof (*values))
795 				return values[index];
796 			break;
797 		}
798 
799 		// case kAmmo: <- There's no research possibility for Ammo in M.A.X.!
800 		default: break;
801 	}
802 
803 	return kNoResearchAvailable;
804 }
805 
806 //--------------------------------------------------
calcIncreaseByUpgrade(int startValue) const807 int cUpgradeCalculator::calcIncreaseByUpgrade (int startValue) const
808 {
809 	if (startValue < 10)
810 		return 1;
811 	if (startValue < 26)
812 		return 2;
813 	if (startValue < 56)
814 		return 5;
815 	return 10;
816 }
817 
818 //--------------------------------------------------
calcChangeByResearch(int startValue,int curResearchLevel,int upgradeType,int unitType) const819 int cUpgradeCalculator::calcChangeByResearch (int startValue, int curResearchLevel,
820 											  int upgradeType, int unitType) const
821 {
822 	if (curResearchLevel <= 0) // no research done yet...
823 		return 0;
824 
825 	// standard research areas - all handled the same way
826 	if (upgradeType == -1 || upgradeType != kCost)
827 	{
828 		// a simple integer division does the job
829 		int newValue = (startValue * (100 + curResearchLevel)) / 100;
830 		return newValue - startValue;
831 	}
832 	else if (upgradeType == kCost)
833 	{
834 		// cost makes a decrease based on the formula 1/x
835 		// (where x is the research level)
836 		float realCost = startValue / ((100.0f + curResearchLevel) / 100.0f);
837 
838 		// now the real cost is rounded to the next possible cost value
839 		// (Unit factories: steps of 3,
840 		//  Building construction: steps of 2,
841 		//  Infantry training: steps of 1)
842 		int costRounded = startValue;
843 		if (unitType == kBuilding)
844 			costRounded = getNearestPossibleCost (realCost, 2);
845 		else if (unitType == kInfantry)
846 			costRounded = getNearestPossibleCost (realCost, 1);
847 		else if (unitType == kStandardUnit)
848 			costRounded = getNearestPossibleCost (realCost, 3);
849 
850 		return costRounded - startValue;
851 	}
852 	else
853 		return 0;
854 }
855 
856 //--------------------------------------------------
getMaterialCostForUpgrading(int unitCost) const857 int cUpgradeCalculator::getMaterialCostForUpgrading (int unitCost) const
858 {
859 	if (unitCost < 4)
860 		return 0;
861 	return unitCost / 4;
862 }
863 
864 //--------------------------------------------------
getNearestPossibleCost(float realCost,int costDifference) const865 int cUpgradeCalculator::getNearestPossibleCost (float realCost, int costDifference) const
866 {
867 	if (costDifference <= 0)
868 		return (int) realCost;
869 
870 	int intCost = (int) realCost;
871 	int nearestLowerCost = intCost - (intCost % costDifference);
872 	int result;
873 	if (realCost - nearestLowerCost < (costDifference / 2.0f))
874 		result = nearestLowerCost;
875 	else
876 		result = nearestLowerCost + costDifference;
877 	if (result <= 0)   // a cost of zero or below is forbidden
878 		result = costDifference;
879 	return result;
880 }
881 
882 //--------------------------------------------------
printAllToLog() const883 void cUpgradeCalculator::printAllToLog() const
884 {
885 	printToLog ("CALC CHANGE BY RESEARCH TEST ---- CALC CHANGE BY RESEARCH TEST");
886 
887 	printToLog ("--------------- Cost-Research for Buildings ----------------");
888 	printToLog ("Building-Cost: Start 40, Level   0 => Change: ", calcChangeByResearch (40,   0, kCost, kBuilding));
889 	printToLog ("Building-Cost: Start 40, Level  10 => Change: ", calcChangeByResearch (40,  10, kCost, kBuilding));
890 	printToLog ("Building-Cost: Start 40, Level  20 => Change: ", calcChangeByResearch (40,  20, kCost, kBuilding));
891 	printToLog ("Building-Cost: Start 40, Level  30 => Change: ", calcChangeByResearch (40,  30, kCost, kBuilding));
892 	printToLog ("Building-Cost: Start 40, Level  40 => Change: ", calcChangeByResearch (40,  40, kCost, kBuilding));
893 	printToLog ("Building-Cost: Start 40, Level  50 => Change: ", calcChangeByResearch (40,  50, kCost, kBuilding));
894 	printToLog ("Building-Cost: Start 40, Level  60 => Change: ", calcChangeByResearch (40,  60, kCost, kBuilding));
895 	printToLog ("Building-Cost: Start 40, Level  70 => Change: ", calcChangeByResearch (40,  70, kCost, kBuilding));
896 	printToLog ("Building-Cost: Start 40, Level  80 => Change: ", calcChangeByResearch (40,  80, kCost, kBuilding));
897 	printToLog ("Building-Cost: Start 40, Level  90 => Change: ", calcChangeByResearch (40,  90, kCost, kBuilding));
898 	printToLog ("Building-Cost: Start 40, Level 100 => Change: ", calcChangeByResearch (40, 100, kCost, kBuilding));
899 	printToLog ("Building-Cost: Start 40, Level 110 => Change: ", calcChangeByResearch (40, 110, kCost, kBuilding));
900 	printToLog ("Building-Cost: Start 40, Level 120 => Change: ", calcChangeByResearch (40, 120, kCost, kBuilding));
901 	printToLog ("Building-Cost: Start 40, Level 130 => Change: ", calcChangeByResearch (40, 130, kCost, kBuilding));
902 	printToLog ("Building-Cost: Start 40, Level 140 => Change: ", calcChangeByResearch (40, 140, kCost, kBuilding));
903 	printToLog ("Building-Cost: Start 40, Level 150 => Change: ", calcChangeByResearch (40, 150, kCost, kBuilding));
904 	printToLog ("Building-Cost: Start 40, Level 160 => Change: ", calcChangeByResearch (40, 160, kCost, kBuilding));
905 	printToLog ("Building-Cost: Start 40, Level 170 => Change: ", calcChangeByResearch (40, 170, kCost, kBuilding));
906 	printToLog ("Building-Cost: Start 40, Level 180 => Change: ", calcChangeByResearch (40, 180, kCost, kBuilding));
907 	printToLog ("Building-Cost: Start 40, Level 190 => Change: ", calcChangeByResearch (40, 190, kCost, kBuilding));
908 	printToLog ("Building-Cost: Start 40, Level 200 => Change: ", calcChangeByResearch (40, 200, kCost, kBuilding));
909 	printToLog ("Building-Cost: Start 40, Level 210 => Change: ", calcChangeByResearch (40, 210, kCost, kBuilding));
910 	printToLog ("Building-Cost: Start 40, Level 220 => Change: ", calcChangeByResearch (40, 220, kCost, kBuilding));
911 
912 	printToLog ("--------------- Cost-Research for Standard Units ----------------");
913 	printToLog ("Unit-Cost: Start 24, Level   0 => Change: ", calcChangeByResearch (24,   0, kCost, kStandardUnit));
914 	printToLog ("Unit-Cost: Start 24, Level  10 => Change: ", calcChangeByResearch (24,  10, kCost, kStandardUnit));
915 	printToLog ("Unit-Cost: Start 24, Level  20 => Change: ", calcChangeByResearch (24,  20, kCost, kStandardUnit));
916 	printToLog ("Unit-Cost: Start 24, Level  30 => Change: ", calcChangeByResearch (24,  30, kCost, kStandardUnit));
917 	printToLog ("Unit-Cost: Start 24, Level  40 => Change: ", calcChangeByResearch (24,  40, kCost, kStandardUnit));
918 	printToLog ("Unit-Cost: Start 24, Level  50 => Change: ", calcChangeByResearch (24,  50, kCost, kStandardUnit));
919 	printToLog ("Unit-Cost: Start 24, Level  60 => Change: ", calcChangeByResearch (24,  60, kCost, kStandardUnit));
920 	printToLog ("Unit-Cost: Start 24, Level  70 => Change: ", calcChangeByResearch (24,  70, kCost, kStandardUnit));
921 	printToLog ("Unit-Cost: Start 24, Level  80 => Change: ", calcChangeByResearch (24,  80, kCost, kStandardUnit));
922 	printToLog ("Unit-Cost: Start 24, Level  90 => Change: ", calcChangeByResearch (24,  90, kCost, kStandardUnit));
923 	printToLog ("Unit-Cost: Start 24, Level 100 => Change: ", calcChangeByResearch (24, 100, kCost, kStandardUnit));
924 	printToLog ("Unit-Cost: Start 24, Level 110 => Change: ", calcChangeByResearch (24, 110, kCost, kStandardUnit));
925 	printToLog ("Unit-Cost: Start 24, Level 120 => Change: ", calcChangeByResearch (24, 120, kCost, kStandardUnit));
926 	printToLog ("Unit-Cost: Start 24, Level 130 => Change: ", calcChangeByResearch (24, 130, kCost, kStandardUnit));
927 	printToLog ("Unit-Cost: Start 24, Level 140 => Change: ", calcChangeByResearch (24, 140, kCost, kStandardUnit));
928 	printToLog ("Unit-Cost: Start 24, Level 150 => Change: ", calcChangeByResearch (24, 150, kCost, kStandardUnit));
929 	printToLog ("Unit-Cost: Start 24, Level 160 => Change: ", calcChangeByResearch (24, 160, kCost, kStandardUnit));
930 	printToLog ("Unit-Cost: Start 24, Level 170 => Change: ", calcChangeByResearch (24, 170, kCost, kStandardUnit));
931 	printToLog ("Unit-Cost: Start 24, Level 180 => Change: ", calcChangeByResearch (24, 180, kCost, kStandardUnit));
932 	printToLog ("Unit-Cost: Start 24, Level 190 => Change: ", calcChangeByResearch (24, 190, kCost, kStandardUnit));
933 	printToLog ("Unit-Cost: Start 24, Level 200 => Change: ", calcChangeByResearch (24, 200, kCost, kStandardUnit));
934 	printToLog ("Unit-Cost: Start 24, Level 210 => Change: ", calcChangeByResearch (24, 210, kCost, kStandardUnit));
935 	printToLog ("Unit-Cost: Start 24, Level 220 => Change: ", calcChangeByResearch (24, 220, kCost, kStandardUnit));
936 
937 	printToLog ("--------------- Cost-Research for Infantry ----------------");
938 	printToLog ("Infantry-Cost: Start 9, Level   0 => Change: ", calcChangeByResearch (9,   0, kCost, kInfantry));
939 	printToLog ("Infantry-Cost: Start 9, Level  10 => Change: ", calcChangeByResearch (9,  10, kCost, kInfantry));
940 	printToLog ("Infantry-Cost: Start 9, Level  20 => Change: ", calcChangeByResearch (9,  20, kCost, kInfantry));
941 	printToLog ("Infantry-Cost: Start 9, Level  30 => Change: ", calcChangeByResearch (9,  30, kCost, kInfantry));
942 	printToLog ("Infantry-Cost: Start 9, Level  40 => Change: ", calcChangeByResearch (9,  40, kCost, kInfantry));
943 	printToLog ("Infantry-Cost: Start 9, Level  50 => Change: ", calcChangeByResearch (9,  50, kCost, kInfantry));
944 	printToLog ("Infantry-Cost: Start 9, Level  60 => Change: ", calcChangeByResearch (9,  60, kCost, kInfantry));
945 	printToLog ("Infantry-Cost: Start 9, Level  70 => Change: ", calcChangeByResearch (9,  70, kCost, kInfantry));
946 	printToLog ("Infantry-Cost: Start 9, Level  80 => Change: ", calcChangeByResearch (9,  80, kCost, kInfantry));
947 	printToLog ("Infantry-Cost: Start 9, Level  90 => Change: ", calcChangeByResearch (9,  90, kCost, kInfantry));
948 	printToLog ("Infantry-Cost: Start 9, Level 100 => Change: ", calcChangeByResearch (9, 100, kCost, kInfantry));
949 	printToLog ("Infantry-Cost: Start 9, Level 110 => Change: ", calcChangeByResearch (9, 110, kCost, kInfantry));
950 	printToLog ("Infantry-Cost: Start 9, Level 120 => Change: ", calcChangeByResearch (9, 120, kCost, kInfantry));
951 	printToLog ("Infantry-Cost: Start 9, Level 130 => Change: ", calcChangeByResearch (9, 130, kCost, kInfantry));
952 	printToLog ("Infantry-Cost: Start 9, Level 140 => Change: ", calcChangeByResearch (9, 140, kCost, kInfantry));
953 	printToLog ("Infantry-Cost: Start 9, Level 150 => Change: ", calcChangeByResearch (9, 150, kCost, kInfantry));
954 	printToLog ("Infantry-Cost: Start 9, Level 160 => Change: ", calcChangeByResearch (9, 160, kCost, kInfantry));
955 	printToLog ("Infantry-Cost: Start 9, Level 170 => Change: ", calcChangeByResearch (9, 170, kCost, kInfantry));
956 	printToLog ("Infantry-Cost: Start 9, Level 180 => Change: ", calcChangeByResearch (9, 180, kCost, kInfantry));
957 	printToLog ("Infantry-Cost: Start 9, Level 190 => Change: ", calcChangeByResearch (9, 190, kCost, kInfantry));
958 	printToLog ("Infantry-Cost: Start 9, Level 200 => Change: ", calcChangeByResearch (9, 200, kCost, kInfantry));
959 	printToLog ("Infantry-Cost: Start 9, Level 210 => Change: ", calcChangeByResearch (9, 210, kCost, kInfantry));
960 	printToLog ("Infantry-Cost: Start 9, Level 220 => Change: ", calcChangeByResearch (9, 220, kCost, kInfantry));
961 
962 	printToLog ("--------------- Upgrade-Research (e.g. Armor) ----------------");
963 	printToLog ("Normal-Research: Start 12, Level   0 => Change: ", calcChangeByResearch (12,   0));
964 	printToLog ("Normal-Research: Start 12, Level  10 => Change: ", calcChangeByResearch (12,  10));
965 	printToLog ("Normal-Research: Start 12, Level  20 => Change: ", calcChangeByResearch (12,  20));
966 	printToLog ("Normal-Research: Start 12, Level  30 => Change: ", calcChangeByResearch (12,  30));
967 	printToLog ("Normal-Research: Start 12, Level  40 => Change: ", calcChangeByResearch (12,  40));
968 	printToLog ("Normal-Research: Start 12, Level  50 => Change: ", calcChangeByResearch (12,  50));
969 	printToLog ("Normal-Research: Start 12, Level  60 => Change: ", calcChangeByResearch (12,  60));
970 	printToLog ("Normal-Research: Start 12, Level  70 => Change: ", calcChangeByResearch (12,  70));
971 	printToLog ("Normal-Research: Start 12, Level  80 => Change: ", calcChangeByResearch (12,  80));
972 	printToLog ("Normal-Research: Start 12, Level  90 => Change: ", calcChangeByResearch (12,  90));
973 	printToLog ("Normal-Research: Start 12, Level 100 => Change: ", calcChangeByResearch (12, 100));
974 	printToLog ("Normal-Research: Start 12, Level 110 => Change: ", calcChangeByResearch (12, 110));
975 	printToLog ("Normal-Research: Start 12, Level 120 => Change: ", calcChangeByResearch (12, 120));
976 	printToLog ("Normal-Research: Start 12, Level 130 => Change: ", calcChangeByResearch (12, 130));
977 	printToLog ("Normal-Research: Start 12, Level 140 => Change: ", calcChangeByResearch (12, 140));
978 	printToLog ("Normal-Research: Start 12, Level 150 => Change: ", calcChangeByResearch (12, 150));
979 	printToLog ("Normal-Research: Start 12, Level 160 => Change: ", calcChangeByResearch (12, 160));
980 	printToLog ("Normal-Research: Start 12, Level 170 => Change: ", calcChangeByResearch (12, 170));
981 	printToLog ("Normal-Research: Start 12, Level 180 => Change: ", calcChangeByResearch (12, 180));
982 	printToLog ("Normal-Research: Start 12, Level 190 => Change: ", calcChangeByResearch (12, 190));
983 	printToLog ("Normal-Research: Start 12, Level 200 => Change: ", calcChangeByResearch (12, 200));
984 	printToLog ("Normal-Research: Start 12, Level 210 => Change: ", calcChangeByResearch (12, 210));
985 	printToLog ("Normal-Research: Start 12, Level 220 => Change: ", calcChangeByResearch (12, 220));
986 }
987 
988 //--------------------------------------------------
printToLog(const char * str,int value) const989 void cUpgradeCalculator::printToLog (const char* str, int value) const
990 {
991 	if (value != -1000)
992 	{
993 		std::stringstream ss;
994 		std::string printStr;
995 		ss << value;
996 		ss >> printStr;
997 		printStr.insert (0, str);
998 		Log.write (printStr, cLog::eLOG_TYPE_INFO);
999 	}
1000 	else
1001 		Log.write (str, cLog::eLOG_TYPE_INFO);
1002 }
1003 
1004 
1005 #if 0
1006 // This is the old code (from JCK?) for calculating the upgrade cost.
1007 // Interesting is the formula used for calculating (although it doesn't produce
1008 // the exact same results - but nearly).
1009 // Maybe the formula could be used for interpolating costs for "non M.A.X." upgrades,
1010 // which are introduced by mods of M.A.X. Reloaded.
1011 {
1012 	int tmp;
1013 	double a, b, c;
1014 	switch (upgradeKind)
1015 	{
1016 		// Treffer, Panzerung, Munition & Angriff
1017 		case 0:
1018 			switch (org)
1019 			{
1020 				case 2:
1021 					if (value == 2) return 39;
1022 					else return 321;
1023 					break;
1024 				case 4:
1025 					a = 0.0016091639;
1026 					b = -0.073815318;
1027 					c = 6.0672869;
1028 					break;
1029 				case 6:
1030 					a = 0.000034548596;
1031 					b = -0.27217472;
1032 					c = 6.3695123;
1033 					break;
1034 				case 8:
1035 					a = 0.00037219059;
1036 					b = 2.5148748;
1037 					c = 5.0938608;
1038 					break;
1039 				case 9:
1040 					a = 0.000059941694;
1041 					b = 1.3962889;
1042 					c = 4.6045196;
1043 					break;
1044 				case 10:
1045 					a = 0.000033736018;
1046 					b = 1.4674423;
1047 					c = 5.5606209;
1048 					break;
1049 				case 12:
1050 					a = 0.0000011574058;
1051 					b = 0.23439586;
1052 					c = 6.113616;
1053 					break;
1054 				case 14:
1055 					a = 0.0000012483447;
1056 					b = 1.4562373;
1057 					c = 5.8250952;
1058 					break;
1059 				case 15:
1060 					a = 0.00000018548742;
1061 					b = -0.33519669;
1062 					c = 6.3333527;
1063 					break;
1064 				case 16:
1065 					a = 0.000010898263;
1066 					b = 5.0297434;
1067 					c = 5.0938627;
1068 					break;
1069 				case 18:
1070 					a = 0.00000017182818;
1071 					b = 2.0009536;
1072 					c = 5.8937153;
1073 					break;
1074 				case 20:
1075 					a = 0.00000004065782;
1076 					b = 1.6533066;
1077 					c = 6.0601538;
1078 					break;
1079 				case 22:
1080 					a = 0.0000000076942857;
1081 					b = -0.45461813;
1082 					c = 6.4148588;
1083 					break;
1084 				case 24:
1085 					a = 0.00000076484313;
1086 					b = 8.0505377;
1087 					c = 5.1465019;
1088 					break;
1089 				case 28:
1090 					a = 0.00000015199858;
1091 					b = 5.1528048;
1092 					c = 5.4700225;
1093 					break;
1094 				case 32:
1095 					a = 0.00000030797077;
1096 					b = 8.8830596;
1097 					c = 5.1409486;
1098 					break;
1099 				case 56:
1100 					a = 0.000000004477053;
1101 					b = 11.454622;
1102 					c = 5.4335099;
1103 					break;
1104 				default:
1105 					return 0;
1106 					break;
1107 			}
1108 			break;
1109 		// Geschwindgigkeit
1110 		case 1:
1111 			org = org / 4;
1112 			value = value / 4;
1113 			switch (org)
1114 			{
1115 				case 5:
1116 					a = 0.00040716128;
1117 					b = -0.16662054;
1118 					c = 6.2234362;
1119 					break;
1120 				case 6:
1121 					a = 0.00038548127;
1122 					b = 0.48236948;
1123 					c = 5.827724;
1124 					break;
1125 				case 7:
1126 					a = 0.000019798772;
1127 					b = -0.31204765;
1128 					c = 6.3982628;
1129 					break;
1130 				case 9:
1131 					a = 0.0000030681294;
1132 					b = -0.25372812;
1133 					c = 6.3995668;
1134 					break;
1135 				case 10:
1136 					a = 0.0000062019158;
1137 					b = -0.23774407;
1138 					c = 6.1901333;
1139 					break;
1140 				case 12:
1141 					a = 0.0000064901101;
1142 					b = 0.93320705;
1143 					c = 5.8395847;
1144 					break;
1145 				case 14:
1146 					a = 0.0000062601892;
1147 					b = 2.1588132;
1148 					c = 5.5866699;
1149 					break;
1150 				case 15:
1151 					a = 0.00000027748628;
1152 					b = -0.0031671959;
1153 					c = 6.2349744;
1154 					break;
1155 				case 16:
1156 					a = 0.0000011401659;
1157 					b = 1.8660343;
1158 					c = 5.7884287;
1159 					break;
1160 				case 18:
1161 					a = 0.00000093928003;
1162 					b = 2.9224069;
1163 					c = 5.6503159;
1164 					break;
1165 				case 20:
1166 					a = 0.00000003478867;
1167 					b = 0.44735558;
1168 					c = 6.2388156;
1169 					break;
1170 				case 24:
1171 					a = 0.0000000038623391;
1172 					b = -0.4486039;
1173 					c = 6.4245686;
1174 					break;
1175 				case 28:
1176 					a = 0.000000039660207;
1177 					b = 1.6425505;
1178 					c = 5.8842817;
1179 					break;
1180 				default:
1181 					return 0;
1182 					break;
1183 			}
1184 			break;
1185 		// Shots
1186 		case 2:
1187 			switch (org)
1188 			{
1189 				case 1:
1190 					return 720;
1191 					break;
1192 				case 2:
1193 					if (value == 2) return 79;
1194 					else return 641;
1195 					break;
1196 				default:
1197 					return 0;
1198 					break;
1199 			}
1200 			break;
1201 		// Reichweite, Scan
1202 		case 3:
1203 			switch (org)
1204 			{
1205 				case 3:
1206 					if (value == 3) return 61;
1207 					else return 299;
1208 					break;
1209 				case 4:
1210 					a = 0.010226741;
1211 					b = -0.001141961;
1212 					c = 5.8477272;
1213 					break;
1214 				case 5:
1215 					a = 0.00074684696;
1216 					b = -0.24064936;
1217 					c = 6.2377712;
1218 					break;
1219 				case 6:
1220 					a = 0.0000004205569;
1221 					b = -2.5074874;
1222 					c = 8.1868728;
1223 					break;
1224 				case 7:
1225 					a = 0.00018753949;
1226 					b = 0.42735532;
1227 					c = 5.9259322;
1228 					break;
1229 				case 8:
1230 					a = 0.000026278484;
1231 					b = 0.0026600724;
1232 					c = 6.2281618;
1233 					break;
1234 				case 9:
1235 					a = 0.000017724816;
1236 					b = 0.35087138;
1237 					c = 6.1028354;
1238 					break;
1239 				case 10:
1240 					a = 0.000011074461;
1241 					b = -0.41358078;
1242 					c = 6.2067919;
1243 					break;
1244 				case 11:
1245 					a = 0.0000022011968;
1246 					b = -0.97456761;
1247 					c = 6.4502985;
1248 					break;
1249 				case 12:
1250 					a = 0.0000000034515189;
1251 					b = -4.4597674;
1252 					c = 7.9715326;
1253 					break;
1254 				case 14:
1255 					a = 0.0000028257552;
1256 					b = 0.78730358;
1257 					c = 5.9483863;
1258 					break;
1259 				case 18:
1260 					a = 0.00000024289322;
1261 					b = 0.64536566;
1262 					c = 6.11706;
1263 					break;
1264 				default:
1265 					return 0;
1266 					break;
1267 			}
1268 			break;
1269 		default:
1270 			return 0;
1271 	}
1272 
1273 	tmp = (int) Round ((a * pow ((value - b), c)), 0);
1274 	return tmp;
1275 }
1276 #endif
1277 
1278 
1279 
1280 //--------------------------------------------------
1281 // R E S E A R C H   C L A S S ---------------------
1282 //--------------------------------------------------
1283 
1284 //--------------------------------------------------
cResearch()1285 cResearch::cResearch()
1286 {
1287 	init();
1288 }
1289 
1290 //--------------------------------------------------
init()1291 void cResearch::init()
1292 {
1293 	int oldCurResearchLevel[kNrResearchAreas];
1294 	int oldCurResearchPoints[kNrResearchAreas];
1295 	int oldNeededResearchPoints[kNrResearchAreas];
1296 
1297 	for (int i = 0; i < kNrResearchAreas; i++)
1298 	{
1299 		oldCurResearchLevel[i] = curResearchLevel[i];
1300 		oldCurResearchPoints[i] = curResearchPoints[i];
1301 		oldNeededResearchPoints[i] = neededResearchPoints[i];
1302 
1303 		curResearchLevel[i] = 0;
1304 		curResearchPoints[i] = 0;
1305 		neededResearchPoints[i] = cUpgradeCalculator::instance().calcResearchTurns (0, getUpgradeCalculatorUpgradeType (i));
1306 	}
1307 
1308 	for (int i = 0; i < kNrResearchAreas; i++)
1309 	{
1310 		if (oldCurResearchLevel[i] != curResearchLevel[i]) currentResearchLevelChanged ((ResearchArea)i);
1311 		if (oldCurResearchPoints[i] != curResearchPoints[i]) currentResearchPointsChanged ((ResearchArea)i);
1312 		if (oldNeededResearchPoints[i] != neededResearchPoints[i]) neededResearchPointsChanged ((ResearchArea)i);
1313 	}
1314 }
1315 
1316 //--------------------------------------------------
getCurResearchLevel(int researchArea) const1317 int cResearch::getCurResearchLevel (int researchArea) const
1318 {
1319 	if (0 <= researchArea && researchArea <= kNrResearchAreas)
1320 		return curResearchLevel[researchArea];
1321 	return 0;
1322 }
1323 
1324 //--------------------------------------------------
getCurResearchPoints(int researchArea) const1325 int cResearch::getCurResearchPoints (int researchArea) const
1326 {
1327 	if (0 <= researchArea && researchArea <= kNrResearchAreas)
1328 		return curResearchPoints[researchArea];
1329 	return 0;
1330 }
1331 
1332 //--------------------------------------------------
getNeededResearchPoints(int researchArea) const1333 int cResearch::getNeededResearchPoints (int researchArea) const
1334 {
1335 	if (0 <= researchArea && researchArea <= kNrResearchAreas)
1336 		return neededResearchPoints[researchArea];
1337 	return cUpgradeCalculator::kNoResearchAvailable;
1338 }
1339 
1340 //--------------------------------------------------
getRemainingTurns(int researchArea,int centersWorkingOn) const1341 int cResearch::getRemainingTurns (int researchArea, int centersWorkingOn) const
1342 {
1343 	if (0 <= researchArea && researchArea <= kNrResearchAreas && centersWorkingOn > 0)
1344 	{
1345 		int remainingPoints = getRemainingResearchPoints (researchArea);
1346 		if (remainingPoints % centersWorkingOn == 0)
1347 			return remainingPoints / centersWorkingOn;
1348 		else
1349 			return (remainingPoints / centersWorkingOn) + 1;
1350 	}
1351 	return 0;
1352 }
1353 
1354 //--------------------------------------------------
setCurResearchLevel(int researchLevel,int researchArea)1355 void cResearch::setCurResearchLevel (int researchLevel, int researchArea)
1356 {
1357 	if (0 <= researchArea && researchArea <= kNrResearchAreas && researchLevel >= 0 && researchLevel % 10 == 0)
1358 	{
1359 		const auto oldLevel = curResearchLevel[researchArea];
1360 		const auto oldPoints = curResearchPoints[researchArea];
1361 		const auto oldNeededPoints = neededResearchPoints[researchArea];
1362 
1363 		curResearchLevel[researchArea] = researchLevel;
1364 		neededResearchPoints[researchArea] = cUpgradeCalculator::instance().calcResearchTurns (researchLevel, getUpgradeCalculatorUpgradeType (researchArea));
1365 		if (curResearchPoints[researchArea] >= neededResearchPoints[researchArea])
1366 		{
1367 			curResearchPoints[researchArea] = 0;
1368 		}
1369 
1370 		if (oldLevel != curResearchLevel[researchArea]) currentResearchLevelChanged ((ResearchArea)researchArea);
1371 		if (oldPoints != curResearchPoints[researchArea]) currentResearchPointsChanged ((ResearchArea)researchArea);
1372 		if (oldNeededPoints != neededResearchPoints[researchArea]) neededResearchPointsChanged ((ResearchArea)researchArea);
1373 	}
1374 }
1375 
1376 //--------------------------------------------------
setCurResearchPoints(int researchPoints,int researchArea)1377 void cResearch::setCurResearchPoints (int researchPoints, int researchArea)
1378 {
1379 	if (0 <= researchArea && researchArea <= kNrResearchAreas && researchPoints >= 0 && researchPoints < neededResearchPoints[researchArea])
1380 	{
1381 		std::swap (curResearchPoints[researchArea], researchPoints);
1382 
1383 		if (researchPoints != curResearchPoints[researchArea]) currentResearchPointsChanged ((ResearchArea)researchArea);
1384 	}
1385 }
1386 
1387 //--------------------------------------------------
doResearch(int researchPoints,int researchArea)1388 bool cResearch::doResearch (int researchPoints, int researchArea)
1389 {
1390 	if (0 <= researchArea && researchArea <= kNrResearchAreas && researchPoints > 0)
1391 	{
1392 		const auto oldPoints = curResearchPoints[researchArea];
1393 
1394 		curResearchPoints[researchArea] += researchPoints;
1395 
1396 		if (curResearchPoints[researchArea] >= neededResearchPoints [researchArea])
1397 		{
1398 			const auto oldLevel = curResearchLevel[researchArea];
1399 			const auto oldNeededPoints = neededResearchPoints[researchArea];
1400 
1401 			curResearchPoints[researchArea] = 0;
1402 			curResearchLevel[researchArea] += 10;
1403 			neededResearchPoints[researchArea] = cUpgradeCalculator::instance().calcResearchTurns (curResearchLevel[researchArea],
1404 												 getUpgradeCalculatorUpgradeType (researchArea));
1405 
1406 			if (oldLevel != curResearchLevel[researchArea]) currentResearchLevelChanged ((ResearchArea)researchArea);
1407 			if (oldPoints != curResearchPoints[researchArea]) currentResearchPointsChanged ((ResearchArea)researchArea);
1408 			if (oldNeededPoints != neededResearchPoints[researchArea]) neededResearchPointsChanged ((ResearchArea)researchArea);
1409 
1410 			return true;
1411 		}
1412 
1413 		if (oldPoints != curResearchPoints[researchArea]) currentResearchPointsChanged ((ResearchArea)researchArea);
1414 	}
1415 	return false;
1416 }
1417 
1418 //--------------------------------------------------
getUpgradeCalculatorUpgradeType(int researchArea) const1419 int cResearch::getUpgradeCalculatorUpgradeType (int researchArea) const
1420 {
1421 	switch (researchArea)
1422 	{
1423 		case kHitpointsResearch: return cUpgradeCalculator::kHitpoints;
1424 		case kArmorResearch: return cUpgradeCalculator::kArmor;
1425 		case kAttackResearch: return cUpgradeCalculator::kAttack;
1426 		case kSpeedResearch: return cUpgradeCalculator::kSpeed;
1427 		case kShotsResearch: return cUpgradeCalculator::kShots;
1428 		case kRangeResearch: return cUpgradeCalculator::kRange;
1429 		case kScanResearch: return cUpgradeCalculator::kScan;
1430 		case kCostResearch: return cUpgradeCalculator::kCost;
1431 	}
1432 	return 0;
1433 }
1434 
1435 //--------------------------------------------------
getResearchArea(int upgradeCalculatorType) const1436 int cResearch::getResearchArea (int upgradeCalculatorType) const
1437 {
1438 	switch (upgradeCalculatorType)
1439 	{
1440 		case cUpgradeCalculator::kHitpoints: return kHitpointsResearch;
1441 		case cUpgradeCalculator::kArmor: return kArmorResearch;
1442 		case cUpgradeCalculator::kAmmo: return -1;
1443 		case cUpgradeCalculator::kAttack: return kAttackResearch;
1444 		case cUpgradeCalculator::kSpeed: return kSpeedResearch;
1445 		case cUpgradeCalculator::kShots: return kShotsResearch;
1446 		case cUpgradeCalculator::kRange: return kRangeResearch;
1447 		case cUpgradeCalculator::kScan: return kScanResearch;
1448 		case cUpgradeCalculator::kCost: return kCostResearch;
1449 	}
1450 	return 0;
1451 }
1452 
1453 //--------------------------------------------------
1454 //      sUnitUpgrade C L A S S ---------------------
1455 //--------------------------------------------------
1456 
1457 //--------------------------------------------------
GetUpgradeType(const sUnitUpgrade & upgrade)1458 static cUpgradeCalculator::UpgradeTypes GetUpgradeType (const sUnitUpgrade& upgrade)
1459 {
1460 	switch (upgrade.getType())
1461 	{
1462 		case sUnitUpgrade::UPGRADE_TYPE_DAMAGE: return cUpgradeCalculator::kAttack;
1463 		case sUnitUpgrade::UPGRADE_TYPE_SHOTS: return cUpgradeCalculator::kShots;
1464 		case sUnitUpgrade::UPGRADE_TYPE_RANGE: return cUpgradeCalculator::kRange;
1465 		case sUnitUpgrade::UPGRADE_TYPE_AMMO: return cUpgradeCalculator::kAmmo;
1466 		case sUnitUpgrade::UPGRADE_TYPE_ARMOR: return cUpgradeCalculator::kArmor;
1467 		case sUnitUpgrade::UPGRADE_TYPE_HITS: return cUpgradeCalculator::kHitpoints;
1468 		case sUnitUpgrade::UPGRADE_TYPE_SCAN: return cUpgradeCalculator::kScan;
1469 		case sUnitUpgrade::UPGRADE_TYPE_SPEED: return cUpgradeCalculator::kSpeed;
1470 		case sUnitUpgrade::UPGRADE_TYPE_NONE: // Follow next line
1471 		default: return cUpgradeCalculator::kAttack;
1472 	}
1473 }
1474 
1475 //--------------------------------------------------
purchase(const cResearch & researchLevel)1476 int sUnitUpgrade::purchase (const cResearch& researchLevel)
1477 {
1478 	cUpgradeCalculator::UpgradeTypes upgradeType = GetUpgradeType (*this);
1479 	const cUpgradeCalculator& uc = cUpgradeCalculator::instance();
1480 	const int cost = nextPrice;
1481 
1482 	if (upgradeType == cUpgradeCalculator::kSpeed)
1483 	{
1484 		curValue += 4 * uc.calcIncreaseByUpgrade (startValue / 4);
1485 		nextPrice = uc.calcPrice (curValue / 4, startValue / 4, upgradeType, researchLevel);
1486 	}
1487 	else
1488 	{
1489 		curValue += uc.calcIncreaseByUpgrade (startValue);
1490 		nextPrice = uc.calcPrice (curValue, startValue, upgradeType, researchLevel);
1491 	}
1492 	++purchased;
1493 	return cost;
1494 }
1495 
1496 //--------------------------------------------------
cancelPurchase(const cResearch & researchLevel)1497 int sUnitUpgrade::cancelPurchase (const cResearch& researchLevel)
1498 {
1499 	cUpgradeCalculator::UpgradeTypes upgradeType = GetUpgradeType (*this);
1500 	const cUpgradeCalculator& uc = cUpgradeCalculator::instance();
1501 
1502 	if (upgradeType == cUpgradeCalculator::kSpeed)
1503 	{
1504 		curValue -= 4 * uc.calcIncreaseByUpgrade (startValue / 4);
1505 		nextPrice = uc.calcPrice (curValue / 4, startValue / 4, upgradeType, researchLevel);
1506 	}
1507 	else
1508 	{
1509 		curValue -= uc.calcIncreaseByUpgrade (startValue);
1510 		nextPrice = uc.calcPrice (curValue, startValue, upgradeType, researchLevel);
1511 	}
1512 	--purchased;
1513 	return -nextPrice;
1514 }
1515 
1516 //--------------------------------------------------
computedPurchasedCount(const cResearch & researchLevel)1517 int sUnitUpgrade::computedPurchasedCount (const cResearch& researchLevel)
1518 {
1519 	if (type == sUnitUpgrade::UPGRADE_TYPE_NONE) return 0;
1520 
1521 	cUpgradeCalculator::UpgradeTypes upgradeType = GetUpgradeType (*this);
1522 	const cUpgradeCalculator& uc = cUpgradeCalculator::instance();
1523 	sUnitUpgrade other (*this);
1524 	int cost = 0;
1525 	const int bonusByResearch = uc.calcChangeByResearch (startValue, researchLevel.getCurResearchLevel (researchLevel.getResearchArea (upgradeType)));
1526 
1527 	other.purchased = 0;
1528 	while (other.curValue != startValue + bonusByResearch)
1529 	{
1530 		cost += other.cancelPurchase (researchLevel);
1531 	}
1532 	purchased += -other.purchased;
1533 	return -cost;
1534 }
1535 
1536 //--------------------------------------------------
init(const sUnitData & origData,const sUnitData & curData,const cResearch & researchLevel)1537 void cUnitUpgrade::init (const sUnitData& origData, const sUnitData& curData, const cResearch& researchLevel)
1538 {
1539 	int i = 0;
1540 
1541 	if (curData.canAttack)
1542 	{
1543 		// Damage:
1544 		upgrades[i].startValue = origData.getDamage();
1545 		upgrades[i].curValue = curData.getDamage();
1546 		upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getDamage(), origData.getDamage(), cUpgradeCalculator::kAttack, researchLevel);
1547 		upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_DAMAGE;
1548 		i++;
1549 		if (!curData.explodesOnContact)
1550 		{
1551 			// Shots:
1552 			upgrades[i].startValue = origData.getShotsMax();
1553 			upgrades[i].curValue = curData.getShotsMax();
1554 			upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getShotsMax(), origData.getShotsMax(), cUpgradeCalculator::kShots, researchLevel);
1555 			upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_SHOTS;
1556 			i++;
1557 			// Range:
1558 			upgrades[i].startValue = origData.getRange();
1559 			upgrades[i].curValue = curData.getRange();
1560 			upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getRange(), origData.getRange(), cUpgradeCalculator::kRange, researchLevel);
1561 			upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_RANGE;
1562 			i++;
1563 			// Ammo:
1564 			upgrades[i].startValue = origData.getAmmoMax();
1565 			upgrades[i].curValue = curData.getAmmoMax();
1566 			upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getAmmoMax(), origData.getAmmoMax(), cUpgradeCalculator::kAmmo, researchLevel);
1567 			upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_AMMO;
1568 			i++;
1569 		}
1570 	}
1571 
1572 	if (curData.storeResType != sUnitData::STORE_RES_NONE)
1573 	{
1574 		i++;
1575 	}
1576 
1577 	if (curData.produceEnergy) i += 2;
1578 
1579 	if (curData.produceHumans) i++;
1580 
1581 	// Armor:
1582 	upgrades[i].startValue = origData.getArmor();
1583 	upgrades[i].curValue = curData.getArmor();
1584 	upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getArmor(), origData.getArmor(), cUpgradeCalculator::kArmor, researchLevel);
1585 	upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_ARMOR;
1586 	i++;
1587 
1588 	// Hitpoints:
1589 	upgrades[i].startValue = origData.getHitpointsMax();
1590 	upgrades[i].curValue = curData.getHitpointsMax();
1591 	upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getHitpointsMax(), origData.getHitpointsMax(), cUpgradeCalculator::kHitpoints, researchLevel);
1592 	upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_HITS;
1593 	i++;
1594 
1595 	// Scan:
1596 	if (curData.getScan())
1597 	{
1598 		upgrades[i].startValue = origData.getScan();
1599 		upgrades[i].curValue = curData.getScan();
1600 		upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getScan(), origData.getScan(), cUpgradeCalculator::kScan, researchLevel);
1601 		upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_SCAN;
1602 		i++;
1603 	}
1604 
1605 	// Speed:
1606 	if (curData.getSpeedMax())
1607 	{
1608 		upgrades[i].startValue = origData.getSpeedMax();
1609 		upgrades[i].curValue = curData.getSpeedMax();
1610 		upgrades[i].nextPrice = cUpgradeCalculator::instance().calcPrice (curData.getSpeedMax() / 4, origData.getSpeedMax() / 4, cUpgradeCalculator::kSpeed, researchLevel);
1611 		upgrades[i].type = sUnitUpgrade::UPGRADE_TYPE_SPEED;
1612 		i++;
1613 	}
1614 }
1615 
1616 //--------------------------------------------------
computedPurchasedCount(const cResearch & researchLevel)1617 int cUnitUpgrade::computedPurchasedCount (const cResearch& researchLevel)
1618 {
1619 	int cost = 0;
1620 
1621 	for (int i = 0; i < 8; ++i)
1622 	{
1623 		cost += upgrades[i].computedPurchasedCount (researchLevel);
1624 	}
1625 	return cost;
1626 }
1627 
1628 //--------------------------------------------------
getUpgrade(sUnitUpgrade::eUpgradeTypes type)1629 sUnitUpgrade* cUnitUpgrade::getUpgrade (sUnitUpgrade::eUpgradeTypes type)
1630 {
1631 	for (int i = 0; i < 8; i++)
1632 	{
1633 		if (upgrades[i].type == type) return &upgrades[i];
1634 	}
1635 	return nullptr;
1636 }
1637 
1638 //--------------------------------------------------
getUpgrade(sUnitUpgrade::eUpgradeTypes type) const1639 const sUnitUpgrade* cUnitUpgrade::getUpgrade (sUnitUpgrade::eUpgradeTypes type) const
1640 {
1641 	for (int i = 0; i < 8; i++)
1642 	{
1643 		if (upgrades[i].type == type) return &upgrades[i];
1644 	}
1645 	return nullptr;
1646 }
1647 
1648 //--------------------------------------------------
getValueOrDefault(sUnitUpgrade::eUpgradeTypes upgradeType,int defaultValue) const1649 int cUnitUpgrade::getValueOrDefault (sUnitUpgrade::eUpgradeTypes upgradeType, int defaultValue) const
1650 {
1651 	for (int i = 0; i != 8; ++i)
1652 	{
1653 		if (upgrades[i].type == upgradeType)
1654 			return upgrades[i].curValue;
1655 	}
1656 	return defaultValue; // the specified upgrade was not found...
1657 }
1658 
1659 //--------------------------------------------------
hasBeenPurchased() const1660 bool cUnitUpgrade::hasBeenPurchased() const
1661 {
1662 	for (int i = 0; i != 8; ++i)
1663 	{
1664 		if (upgrades[i].purchased)
1665 		{
1666 			return true;
1667 		}
1668 	}
1669 	return false;
1670 }
1671 
1672 //--------------------------------------------------
updateUnitData(sUnitData & data) const1673 void cUnitUpgrade::updateUnitData (sUnitData& data) const
1674 {
1675 	for (int i = 0; i < 8; ++i)
1676 	{
1677 		switch (upgrades[i].getType())
1678 		{
1679 			case sUnitUpgrade::UPGRADE_TYPE_DAMAGE:
1680 				data.setDamage (upgrades[i].curValue);
1681 				break;
1682 			case sUnitUpgrade::UPGRADE_TYPE_SHOTS:
1683 				data.setShotsMax (upgrades[i].curValue);
1684 				break;
1685 			case sUnitUpgrade::UPGRADE_TYPE_RANGE:
1686 				data.setRange (upgrades[i].curValue);
1687 				break;
1688 			case sUnitUpgrade::UPGRADE_TYPE_AMMO:
1689 				data.setAmmoMax (upgrades[i].curValue);
1690 				break;
1691 			case sUnitUpgrade::UPGRADE_TYPE_ARMOR:
1692 				data.setArmor (upgrades[i].curValue);
1693 				break;
1694 			case sUnitUpgrade::UPGRADE_TYPE_HITS:
1695 				data.setHitpointsMax (upgrades[i].curValue);
1696 				break;
1697 			case sUnitUpgrade::UPGRADE_TYPE_SCAN:
1698 				data.setScan (upgrades[i].curValue);
1699 				break;
1700 			case sUnitUpgrade::UPGRADE_TYPE_SPEED:
1701 				data.setSpeedMax (upgrades[i].curValue);
1702 				break;
1703 			case sUnitUpgrade::UPGRADE_TYPE_NONE:
1704 				break;
1705 		}
1706 	}
1707 }
1708