1 /*
2 * Seven Kingdoms: Ancient Adversaries
3 *
4 * Copyright 1997,1998 Enlight Software Ltd.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 // Filename : OW_PLANT.CPP
22 // Description: growth of plant
23 // Ownership : Gilbert
24
25 #include <OMATRIX.h>
26 #include <OWORLD.h>
27 #include <OWORLDMT.h>
28 #include <OWEATHER.h>
29 #include <OPLANT.h>
30 #include <OTERRAIN.h>
31 #include <ALL.h>
32 #include <math.h>
33 #include <stdlib.h>
34
35
36 //------------ Define constant ---------------//
37 static short opt_temp[3] = { 32, 25, 28 }; // tropical,temperate and both
38 #define PLANT_ARRAY_SIZE 8
39
40 //------------ Define inline function -------//
rand_inner_x()41 inline int rand_inner_x()
42 {
43 // can use misc.random(ZOOM_LOC_WIDTH) instead
44 // return (ZOOM_LOC_WIDTH *3)/8 + misc.random(ZOOM_LOC_WIDTH/4);
45 return ZOOM_LOC_WIDTH / 4 + misc.random(ZOOM_LOC_WIDTH/2);
46 }
47
rand_inner_y()48 inline int rand_inner_y()
49 {
50 return (ZOOM_LOC_HEIGHT * 3) / 8 + misc.random(ZOOM_LOC_HEIGHT/4);
51 }
52
53 //----------- Begin of function World::plant_ops -----------//
54 //
plant_ops()55 void World::plant_ops()
56 {
57 plant_grow(40);
58 plant_reprod(10);
59 plant_death();
60 plant_spread(50);
61 }
62 //----------- End of function World::plant_ops -----------//
63
64 //------------ begin of function World::plant_grow ------------//
65 //
66 // pGrow = prabability of grow, range from 0 to 100
67 // scanDensity = scan one square per scanDensity^2
68 //
plant_grow(int pGrow,int scanDensity)69 void World::plant_grow(int pGrow, int scanDensity)
70 {
71 // scan part of the map for plant
72 int yBase = misc.random(scanDensity);
73 int xBase = misc.random(scanDensity);
74 for( int y = yBase; y < max_y_loc; y += scanDensity)
75 for( int x = xBase; x < max_x_loc; x += scanDensity)
76 {
77 Location *l = get_loc(x,y);
78 short bitmapId, basePlantId;
79
80 // is a plant and is not at maximum grade
81 if( l->is_plant() && misc.random(100) < pGrow &&
82 (basePlantId = plant_res.plant_recno(bitmapId = l->plant_id())) != 0 &&
83 bitmapId - plant_res[basePlantId]->first_bitmap < plant_res[basePlantId]->bitmap_count -1)
84 {
85 // increase the grade of plant
86 l->grow_plant();
87 }
88 }
89 }
90 //------------ end of function World::plant_grow ------------//
91
92
93 //------------ begin of function World::plant_reprod --------//
94 //
95 // pReprod = prabability of reproduction, range from 0 to 20
96 // scanDensity = scan one square per scanDensity^2
97 //
plant_reprod(int pReprod,int scanDensity)98 void World::plant_reprod(int pReprod, int scanDensity)
99 {
100 if( plant_count > plant_limit )
101 return;
102 if( 5 * plant_count < 4 * plant_limit )
103 pReprod++; // higher probability to grow
104
105 // determine the rainful, temperature and sunlight
106 short t = weather.temp_c();
107
108 // scan the map for plant
109 int yBase = misc.random(scanDensity);
110 int xBase = misc.random(scanDensity);
111 for( int y = yBase; y < max_y_loc; y += scanDensity)
112 {
113 for( int x = xBase; x < max_x_loc; x += scanDensity)
114 {
115 Location *l = get_loc(x,y);
116 short bitmapId, basePlantId, plantGrade;
117 // is a plant and grade > 3
118 if( l->is_plant() && (basePlantId = plant_res.plant_recno(
119 bitmapId = l->plant_id())) != 0 &&
120 ((plantGrade = bitmapId - plant_res[basePlantId]->first_bitmap) >= 3 ||
121 plantGrade == plant_res[basePlantId]->bitmap_count-1))
122 {
123 // find the optimal temperature for the plant
124 short oTemp = opt_temp[plant_res[basePlantId]->climate_zone -1];
125 short tempEffect = 5 - abs( oTemp - t);
126 tempEffect = tempEffect > 0 ? tempEffect : 0;
127
128 if(misc.random(100) < tempEffect * pReprod)
129 {
130 // produce the same plant but grade 1,
131 char trial = 2;
132 Location *newl;
133 while( trial --)
134 {
135 newl = NULL;
136 switch(misc.random(8))
137 {
138 case 0: // north square
139 if( y > 0)
140 newl = get_loc(x,y-1);
141 break;
142 case 1: // east square
143 if( x < max_x_loc-1 )
144 newl = get_loc(x+1,y);
145 break;
146 case 2: // south square
147 if( y < max_y_loc-1 )
148 newl = get_loc(x,y+1);
149 break;
150 case 3: // west square
151 if( x > 0)
152 newl = get_loc(x-1,y);
153 break;
154 case 4: // north west square
155 if( y > 0 && x > 0)
156 newl = get_loc(x-1,y-1);
157 break;
158 case 5: // north east square
159 if( y > 0 && x < max_x_loc-1 )
160 newl = get_loc(x+1,y-1);
161 break;
162 case 6: // south east square
163 if( y < max_y_loc-1 && x < max_x_loc-1)
164 newl = get_loc(x+1,y+1);
165 break;
166 case 7: // south west square
167 if( y < max_y_loc-1 && x > 0)
168 newl = get_loc(x-1,y+1);
169 break;
170 }
171
172 char teraType;
173 // #### begin Gilbert 6/3 #######//
174 if( newl && newl->can_add_plant() &&
175 (plant_res[basePlantId]->tera_type[0] ==
176 (teraType = terrain_res[newl->terrain_id]->average_type) ||
177 plant_res[basePlantId]->tera_type[1] == teraType ||
178 plant_res[basePlantId]->tera_type[2] == teraType) )
179 // #### end Gilbert 6/3 #######//
180 {
181 newl->set_plant(plant_res[basePlantId]->first_bitmap
182 , rand_inner_x(), rand_inner_y() );
183
184 // ------- set flammability ---------
185 newl->set_fire_src(100);
186 plant_count++;
187 //### begin alex 24/6 ###//
188 //newl->set_power_off();
189 //newl->power_nation_recno = 0;
190 //set_surr_power_off(x, y);
191 //#### end alex 24/6 ####//
192 break;
193 }
194 }
195 }
196 }
197 }
198 }
199 }
200 //------------ end of function World::plant_reprod --------//
201
202
203 //------------ begin of function World::plant_spread ------------//
204 //
205 // pSpread = probability of spreading, range from 0 to 1000
206 //
plant_spread(int pSpread)207 void World::plant_spread(int pSpread)
208 {
209 if( plant_count > plant_limit)
210 return;
211 if( 5 * plant_count < 4 * plant_limit )
212 pSpread += pSpread;
213
214 if(misc.random(1000) >= pSpread)
215 return;
216
217 // ------- determine temperature
218 short t = weather.temp_c();
219
220 // ------- randomly select a place to seed plant
221 int y = 1+misc.random(max_y_loc-2);
222 int x = 1+misc.random(max_x_loc-2);
223
224 Location *l = get_loc(x,y);
225 int build_flag = 1;
226 char teraType = terrain_res[l->terrain_id]->average_type;
227
228 // ------- all square around are the same terrain type and empty
229 for( int y1 = y-1; y1 <= y+1; ++y1)
230 for( int x1 = x-1; x1 <= x+1; ++x1)
231 {
232 l = get_loc(x1,y1);
233 // #### begin Gilbert 6/3 #######//
234 if( !l->can_add_plant() || terrain_res[l->terrain_id]->average_type != teraType)
235 build_flag = 0;
236 // #### end Gilbert 6/3 #######//
237 }
238
239 if( build_flag)
240 {
241 char climateZone = 0;
242 short plantBitmap = 0;
243 for( int retry=0; !climateZone && retry < 5; ++retry)
244 {
245 for( char j=0; j < 3; ++j)
246 {
247 if( misc.random(5) > abs(t- opt_temp[j]) )
248 {
249 climateZone = j+1;
250 plantBitmap = plant_res.scan( climateZone, teraType, 0);
251 if( plantBitmap)
252 {
253 l = get_loc(x,y);
254 l->set_plant( plantBitmap, rand_inner_x(), rand_inner_y() );
255 l->set_fire_src(100);
256 plant_count++;
257 //### begin alex 24/6 ###//
258 //l->set_power_off();
259 //l->power_nation_recno = 0;
260 //set_surr_power_off(x, y);
261 //#### end alex 24/6 ####//
262 }
263 break;
264 }
265 }
266 }
267 }
268 }
269 //------------ end of function World::plant_spread ------------//
270
271
272 //------------ begin of function World::plant_death ---------//
273 //
274 // a plant may death, if it is surrounded by many trees
275 //
plant_death(int scanDensity)276 void World::plant_death(int scanDensity)
277 {
278 int yBase = misc.random(scanDensity);
279 int xBase = misc.random(scanDensity);
280 for( int y = yBase; y < max_y_loc; y += scanDensity)
281 {
282 for( int x = xBase; x < max_x_loc; x += scanDensity)
283 {
284 Location *locPtr = get_loc(x,y);
285 if( locPtr->is_plant() )
286 {
287 char neighbour =0;
288 char totalSpace =0;
289
290 // west
291 if( x > 0)
292 {
293 totalSpace++;
294 if( (locPtr-1)->is_plant() )
295 neighbour++;
296 }
297
298 // east
299 if( x < max_x_loc-1)
300 {
301 totalSpace++;
302 if( (locPtr+1)->is_plant() )
303 neighbour++;
304 }
305
306 if( y > 0)
307 {
308 locPtr = get_loc(x,y-1);
309
310 // north square
311 totalSpace++;
312 if( locPtr->is_plant() )
313 neighbour++;
314
315 // north west
316 if( x > 0)
317 {
318 totalSpace++;
319 if( (locPtr-1)->is_plant() )
320 neighbour++;
321 }
322
323 // north east
324 if( x < max_x_loc-1)
325 {
326 totalSpace++;
327 if( (locPtr+1)->is_plant() )
328 neighbour++;
329 }
330 }
331
332 if( y < max_x_loc-1)
333 {
334 locPtr = get_loc(x,y+1);
335
336 // south square
337 totalSpace++;
338 if( locPtr->is_plant() )
339 neighbour++;
340
341 // south west
342 if( x > 0)
343 {
344 totalSpace++;
345 if( (locPtr-1)->is_plant() )
346 neighbour++;
347 }
348
349 // south east
350 if( x < max_x_loc-1)
351 {
352 totalSpace++;
353 if( (locPtr+1)->is_plant() )
354 neighbour++;
355 }
356 }
357
358 // may remove plant if more than two third of the space is occupied
359 if( misc.random(totalSpace) + 2*totalSpace/3 <= neighbour )
360 {
361 locPtr = get_loc(x,y);
362 get_loc(x,y)->remove_plant();
363 if( locPtr->fire_src() > 50)
364 locPtr->set_fire_src(50);
365 plant_count--;
366 //### begin alex 24/6 ###//
367 //newl->set_power_off();
368 //newl->power_nation_recno = 0;
369 //set_surr_power_off(x, y);
370 //#### end alex 24/6 ####//
371 }
372 }
373 }
374 }
375 }
376 //------------ end of function World::plant_death ---------//
377
378
379 //------------ begin of function World::plant_init ------------//
380 // randomly select a place and call plant_spray to enlarge the
381 // forest
382 //
plant_init()383 void World::plant_init()
384 {
385 plant_count = 0;
386 int trial;
387 for(trial = 50; trial > 0; --trial)
388 {
389 // ------- randomly select a place to seed plant
390 int y = 1+misc.random(max_y_loc-2);
391 int x = 1+misc.random(max_x_loc-2);
392
393 Location *l = get_loc(x,y);
394 int build_flag = 1;
395 char teraType = terrain_res[l->terrain_id]->average_type;
396
397 // ------- all square around are the same terrain type and empty
398 for( int y1 = y-1; y1 <= y+1; ++y1)
399 for( int x1 = x-1; x1 <= x+1; ++x1)
400 {
401 l = get_loc(x1,y1);
402 // #### begin Gilbert 6/3 #######//
403 if( !l->can_add_plant() || terrain_res[l->terrain_id]->average_type != teraType)
404 build_flag = 0;
405 // #### end Gilbert 6/3 #######//
406 }
407
408 if( build_flag )
409 {
410 short plantBitmap = plant_res.scan( 0, teraType, 0);
411 short plantArray[PLANT_ARRAY_SIZE];
412 for( int i = 0; i < PLANT_ARRAY_SIZE; ++i)
413 {
414 plantArray[i] = plant_res.plant_recno(plant_res.scan(0, teraType, 0));
415 }
416 if( plantArray[0] )
417 {
418 plant_spray(plantArray, 6+misc.random(4), x, y);
419 }
420 }
421 }
422
423 plant_limit = plant_count * 3 / 2;
424
425 // ------- kill some plant ----------//
426 for(trial = 8; trial > 0; --trial)
427 {
428 plant_death(2);
429 }
430 }
431 //------------ end of function World::plant_init ------------//
432
433 //------------ begin of function World::plant_spray ------------//
plant_spray(short * plantArray,char strength,short x,short y)434 void World::plant_spray(short *plantArray, char strength, short x, short y)
435 {
436 if( strength <= 0)
437 return;
438
439 //---------- if the space is empty put a plant on it ----------//
440 Location *newl = get_loc(x, y);
441 short basePlantId = plantArray[misc.random(PLANT_ARRAY_SIZE)];
442 short plantSize = misc.random(plant_res[basePlantId]->bitmap_count);
443 if( plantSize > strength)
444 plantSize = strength;
445
446 char teraType;
447 if( newl && newl->can_add_plant() &&
448 (plant_res[basePlantId]->tera_type[0] ==
449 (teraType = terrain_res[newl->terrain_id]->average_type) ||
450 plant_res[basePlantId]->tera_type[1] == teraType ||
451 plant_res[basePlantId]->tera_type[2] == teraType) )
452 {
453 newl->set_plant(plant_res[basePlantId]->first_bitmap +plantSize
454 , rand_inner_x(), rand_inner_y() );
455 newl->set_fire_src(100);
456 plant_count++;
457 //### begin alex 24/6 ###//
458 //newl->set_power_off();
459 //newl->power_nation_recno = 0;
460 //set_surr_power_off(x, y);
461 //#### end alex 24/6 ####//
462 }
463 else if( newl && newl->is_plant() &&
464 // 1. same type, large override small
465 // newl->plant_id() >= plant_res[basePlantId]->first_bitmap &&
466 // newl->plant_id() < plant_res[basePlantId]->first_bitmap + plantSize)
467 // 2. same type, small override large
468 // newl->plant_id() > plant_res[basePlantId]->first_bitmap + plantSize &&
469 // newl->plant_id() < plant_res[basePlantId]->first_bitmap + plant_res[basePlantId]->bitmap_count)
470 // 3. all types, small override large
471 (newl->plant_id() - plant_res[plant_res.plant_recno(newl->plant_id())]->first_bitmap) >
472 plantSize )
473 {
474 // same kind of plant, but smaller, override by a smaller one
475 newl->remove_plant();
476 newl->set_plant(plant_res[basePlantId]->first_bitmap +plantSize
477 , rand_inner_x(), rand_inner_y() );
478 newl->set_fire_src(100);
479 //### begin alex 24/6 ###//
480 //newl->set_power_off();
481 //newl->power_nation_recno = 0;
482 //set_surr_power_off(x, y);
483 //#### end alex 24/6 ####//
484 }
485 else
486 {
487 plantSize = -1;
488 }
489
490 if( plantSize >= 0 && strength)
491 {
492 char trial = 3;
493 while( trial--)
494 {
495 switch(misc.random(8))
496 {
497 case 0: // north square
498 if( y > 0)
499 plant_spray(plantArray, strength-1, x,y-1);
500 break;
501 case 1: // east square
502 if( x < max_x_loc-1 )
503 plant_spray(plantArray, strength-1, x+1,y);
504 break;
505 case 2: // south square
506 if( y < max_y_loc-1 )
507 plant_spray(plantArray, strength-1, x,y+1);
508 break;
509 case 3: // west square
510 if( x > 0)
511 plant_spray(plantArray, strength-1, x-1,y);
512 break;
513 case 4: // north west square
514 if( y > 0 && x > 0)
515 plant_spray(plantArray, strength-1, x-1,y-1);
516 break;
517 case 5: // north east square
518 if( y > 0 && x < max_x_loc-1 )
519 plant_spray(plantArray, strength-1, x+1,y-1);
520 break;
521 case 6: // south east square
522 if( y < max_y_loc-1 && x < max_x_loc-1)
523 plant_spray(plantArray, strength-1, x+1,y+1);
524 break;
525 case 7: // south west square
526 if( y < max_y_loc-1 && x > 0)
527 plant_spray(plantArray, strength-1, x-1,y+1);
528 break;
529 }
530 }
531 }
532 }
533 //------------ end of function World::plant_spray ------------//
534
535