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