/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
// Filename : OW_PLANT.CPP
// Description: growth of plant
// Ownership : Gilbert
#include
#include
#include
#include
#include
#include
#include
#include
//------------ Define constant ---------------//
static short opt_temp[3] = { 32, 25, 28 }; // tropical,temperate and both
#define PLANT_ARRAY_SIZE 8
//------------ Define inline function -------//
inline int rand_inner_x()
{
// can use m.random(ZOOM_LOC_WIDTH) instead
// return (ZOOM_LOC_WIDTH *3)/8 + m.random(ZOOM_LOC_WIDTH/4);
return ZOOM_LOC_WIDTH / 4 + m.random(ZOOM_LOC_WIDTH/2);
}
inline int rand_inner_y()
{
return (ZOOM_LOC_HEIGHT * 3) / 8 + m.random(ZOOM_LOC_HEIGHT/4);
}
//----------- Begin of function World::plant_ops -----------//
//
void World::plant_ops()
{
plant_grow(40);
plant_reprod(10);
plant_death();
plant_spread(50);
}
//----------- End of function World::plant_ops -----------//
//------------ begin of function World::plant_grow ------------//
//
// pGrow = prabability of grow, range from 0 to 100
// scanDensity = scan one square per scanDensity^2
//
void World::plant_grow(int pGrow, int scanDensity)
{
// scan part of the map for plant
int yBase = m.random(scanDensity);
int xBase = m.random(scanDensity);
for( int y = yBase; y < max_y_loc; y += scanDensity)
for( int x = xBase; x < max_x_loc; x += scanDensity)
{
Location *l = get_loc(x,y);
short bitmapId, basePlantId;
// is a plant and is not at maximum grade
if( l->is_plant() && m.random(100) < pGrow &&
(basePlantId = plant_res.plant_recno(bitmapId = l->plant_id())) != 0 &&
bitmapId - plant_res[basePlantId]->first_bitmap < plant_res[basePlantId]->bitmap_count -1)
{
// increase the grade of plant
l->grow_plant();
}
}
}
//------------ end of function World::plant_grow ------------//
//------------ begin of function World::plant_reprod --------//
//
// pReprod = prabability of reproduction, range from 0 to 20
// scanDensity = scan one square per scanDensity^2
//
void World::plant_reprod(int pReprod, int scanDensity)
{
if( plant_count > plant_limit )
return;
if( 5 * plant_count < 4 * plant_limit )
pReprod++; // higher probability to grow
// determine the rainful, temperature and sunlight
short t = weather.temp_c();
// scan the map for plant
int yBase = m.random(scanDensity);
int xBase = m.random(scanDensity);
for( int y = yBase; y < max_y_loc; y += scanDensity)
{
for( int x = xBase; x < max_x_loc; x += scanDensity)
{
Location *l = get_loc(x,y);
short bitmapId, basePlantId, plantGrade;
// is a plant and grade > 3
if( l->is_plant() && (basePlantId = plant_res.plant_recno(
bitmapId = l->plant_id())) != 0 &&
((plantGrade = bitmapId - plant_res[basePlantId]->first_bitmap) >= 3 ||
plantGrade == plant_res[basePlantId]->bitmap_count-1))
{
// find the optimal temperature for the plant
short oTemp = opt_temp[plant_res[basePlantId]->climate_zone -1];
short tempEffect = 5 - abs( oTemp - t);
tempEffect = tempEffect > 0 ? tempEffect : 0;
if( m.random(100) < tempEffect * pReprod)
{
// produce the same plant but grade 1,
char trial = 2;
Location *newl;
while( trial --)
{
newl = NULL;
switch(m.random(8))
{
case 0: // north square
if( y > 0)
newl = get_loc(x,y-1);
break;
case 1: // east square
if( x < max_x_loc-1 )
newl = get_loc(x+1,y);
break;
case 2: // south square
if( y < max_y_loc-1 )
newl = get_loc(x,y+1);
break;
case 3: // west square
if( x > 0)
newl = get_loc(x-1,y);
break;
case 4: // north west square
if( y > 0 && x > 0)
newl = get_loc(x-1,y-1);
break;
case 5: // north east square
if( y > 0 && x < max_x_loc-1 )
newl = get_loc(x+1,y-1);
break;
case 6: // south east square
if( y < max_y_loc-1 && x < max_x_loc-1)
newl = get_loc(x+1,y+1);
break;
case 7: // south west square
if( y < max_y_loc-1 && x > 0)
newl = get_loc(x-1,y+1);
break;
}
char teraType;
// #### begin Gilbert 6/3 #######//
if( newl && newl->can_add_plant() &&
(plant_res[basePlantId]->tera_type[0] ==
(teraType = terrain_res[newl->terrain_id]->average_type) ||
plant_res[basePlantId]->tera_type[1] == teraType ||
plant_res[basePlantId]->tera_type[2] == teraType) )
// #### end Gilbert 6/3 #######//
{
newl->set_plant(plant_res[basePlantId]->first_bitmap
, rand_inner_x(), rand_inner_y() );
// ------- set flammability ---------
newl->set_fire_src(100);
plant_count++;
//### begin alex 24/6 ###//
//newl->set_power_off();
//newl->power_nation_recno = 0;
//set_surr_power_off(x, y);
//#### end alex 24/6 ####//
break;
}
}
}
}
}
}
}
//------------ end of function World::plant_reprod --------//
//------------ begin of function World::plant_spread ------------//
//
// pSpread = probability of spreading, range from 0 to 1000
//
void World::plant_spread(int pSpread)
{
if( plant_count > plant_limit)
return;
if( 5 * plant_count < 4 * plant_limit )
pSpread += pSpread;
if(m.random(1000) >= pSpread )
return;
// ------- determine temperature
short t = weather.temp_c();
// ------- randomly select a place to seed plant
int y = 1+m.random(max_y_loc-2);
int x = 1+m.random(max_x_loc-2);
Location *l = get_loc(x,y);
int build_flag = TRUE;
char teraType = terrain_res[l->terrain_id]->average_type;
// ------- all square around are the same terrain type and empty
for( int y1 = y-1; y1 <= y+1; ++y1)
for( int x1 = x-1; x1 <= x+1; ++x1)
{
l = get_loc(x1,y1);
// #### begin Gilbert 6/3 #######//
if( !l->can_add_plant() || terrain_res[l->terrain_id]->average_type != teraType)
build_flag = FALSE;
// #### end Gilbert 6/3 #######//
}
if( build_flag)
{
char climateZone = 0;
short plantBitmap = 0;
for( int retry=0; !climateZone && retry < 5; ++retry)
{
for( char j=0; j < 3; ++j)
{
if( m.random(5) > abs(t- opt_temp[j]) )
{
climateZone = j+1;
plantBitmap = plant_res.scan( climateZone, teraType, 0);
if( plantBitmap)
{
l = get_loc(x,y);
l->set_plant( plantBitmap, rand_inner_x(), rand_inner_y() );
l->set_fire_src(100);
plant_count++;
//### begin alex 24/6 ###//
//l->set_power_off();
//l->power_nation_recno = 0;
//set_surr_power_off(x, y);
//#### end alex 24/6 ####//
}
break;
}
}
}
}
}
//------------ end of function World::plant_spread ------------//
//------------ begin of function World::plant_death ---------//
//
// a plant may death, if it is surrounded by many trees
//
void World::plant_death(int scanDensity)
{
int yBase = m.random(scanDensity);
int xBase = m.random(scanDensity);
for( int y = yBase; y < max_y_loc; y += scanDensity)
{
for( int x = xBase; x < max_x_loc; x += scanDensity)
{
Location *locPtr = get_loc(x,y);
if( locPtr->is_plant() )
{
char neighbour =0;
char totalSpace =0;
// west
if( x > 0)
{
totalSpace++;
if( (locPtr-1)->is_plant() )
neighbour++;
}
// east
if( x < max_x_loc-1)
{
totalSpace++;
if( (locPtr+1)->is_plant() )
neighbour++;
}
if( y > 0)
{
locPtr = get_loc(x,y-1);
// north square
totalSpace++;
if( locPtr->is_plant() )
neighbour++;
// north west
if( x > 0)
{
totalSpace++;
if( (locPtr-1)->is_plant() )
neighbour++;
}
// north east
if( x < max_x_loc-1)
{
totalSpace++;
if( (locPtr+1)->is_plant() )
neighbour++;
}
}
if( y < max_x_loc-1)
{
locPtr = get_loc(x,y+1);
// south square
totalSpace++;
if( locPtr->is_plant() )
neighbour++;
// south west
if( x > 0)
{
totalSpace++;
if( (locPtr-1)->is_plant() )
neighbour++;
}
// south east
if( x < max_x_loc-1)
{
totalSpace++;
if( (locPtr+1)->is_plant() )
neighbour++;
}
}
// may remove plant if more than two third of the space is occupied
if( m.random(totalSpace) + 2*totalSpace/3 <= neighbour )
{
locPtr = get_loc(x,y);
get_loc(x,y)->remove_plant();
if( locPtr->fire_src() > 50)
locPtr->set_fire_src(50);
plant_count--;
//### begin alex 24/6 ###//
//newl->set_power_off();
//newl->power_nation_recno = 0;
//set_surr_power_off(x, y);
//#### end alex 24/6 ####//
}
}
}
}
}
//------------ end of function World::plant_death ---------//
//------------ begin of function World::plant_init ------------//
// randomly select a place and call plant_spray to enlarge the
// forest
//
void World::plant_init()
{
plant_count = 0;
int trial;
for(trial = 50; trial > 0; --trial)
{
// ------- randomly select a place to seed plant
int y = 1+m.random(max_y_loc-2);
int x = 1+m.random(max_x_loc-2);
Location *l = get_loc(x,y);
int build_flag = TRUE;
char teraType = terrain_res[l->terrain_id]->average_type;
// ------- all square around are the same terrain type and empty
for( int y1 = y-1; y1 <= y+1; ++y1)
for( int x1 = x-1; x1 <= x+1; ++x1)
{
l = get_loc(x1,y1);
// #### begin Gilbert 6/3 #######//
if( !l->can_add_plant() || terrain_res[l->terrain_id]->average_type != teraType)
build_flag = FALSE;
// #### end Gilbert 6/3 #######//
}
if( build_flag )
{
short plantBitmap = plant_res.scan( 0, teraType, 0);
short plantArray[PLANT_ARRAY_SIZE];
for( int i = 0; i < PLANT_ARRAY_SIZE; ++i)
{
plantArray[i] = plant_res.plant_recno(plant_res.scan(0, teraType, 0));
}
if( plantArray[0] )
{
plant_spray(plantArray, 6+m.random(4), x, y);
}
}
}
plant_limit = plant_count * 3 / 2;
// ------- kill some plant ----------//
for(trial = 8; trial > 0; --trial)
{
plant_death(2);
}
}
//------------ end of function World::plant_init ------------//
//------------ begin of function World::plant_spray ------------//
void World::plant_spray(short *plantArray, char strength, short x, short y)
{
if( strength <= 0)
return;
//---------- if the space is empty put a plant on it ----------//
Location *newl = get_loc(x, y);
short basePlantId = plantArray[m.random(PLANT_ARRAY_SIZE)];
short plantSize = m.random(plant_res[basePlantId]->bitmap_count);
if( plantSize > strength)
plantSize = strength;
char teraType;
if( newl && newl->can_add_plant() &&
(plant_res[basePlantId]->tera_type[0] ==
(teraType = terrain_res[newl->terrain_id]->average_type) ||
plant_res[basePlantId]->tera_type[1] == teraType ||
plant_res[basePlantId]->tera_type[2] == teraType) )
{
newl->set_plant(plant_res[basePlantId]->first_bitmap +plantSize
, rand_inner_x(), rand_inner_y() );
newl->set_fire_src(100);
plant_count++;
//### begin alex 24/6 ###//
//newl->set_power_off();
//newl->power_nation_recno = 0;
//set_surr_power_off(x, y);
//#### end alex 24/6 ####//
}
else if( newl && newl->is_plant() &&
// 1. same type, large override small
// newl->plant_id() >= plant_res[basePlantId]->first_bitmap &&
// newl->plant_id() < plant_res[basePlantId]->first_bitmap + plantSize)
// 2. same type, small override large
// newl->plant_id() > plant_res[basePlantId]->first_bitmap + plantSize &&
// newl->plant_id() < plant_res[basePlantId]->first_bitmap + plant_res[basePlantId]->bitmap_count)
// 3. all types, small override large
(newl->plant_id() - plant_res[plant_res.plant_recno(newl->plant_id())]->first_bitmap) >
plantSize )
{
// same kind of plant, but smaller, override by a smaller one
newl->remove_plant();
newl->set_plant(plant_res[basePlantId]->first_bitmap +plantSize
, rand_inner_x(), rand_inner_y() );
newl->set_fire_src(100);
//### begin alex 24/6 ###//
//newl->set_power_off();
//newl->power_nation_recno = 0;
//set_surr_power_off(x, y);
//#### end alex 24/6 ####//
}
else
{
plantSize = -1;
}
if( plantSize >= 0 && strength)
{
char trial = 3;
while( trial--)
{
switch(m.random(8))
{
case 0: // north square
if( y > 0)
plant_spray(plantArray, strength-1, x,y-1);
break;
case 1: // east square
if( x < max_x_loc-1 )
plant_spray(plantArray, strength-1, x+1,y);
break;
case 2: // south square
if( y < max_y_loc-1 )
plant_spray(plantArray, strength-1, x,y+1);
break;
case 3: // west square
if( x > 0)
plant_spray(plantArray, strength-1, x-1,y);
break;
case 4: // north west square
if( y > 0 && x > 0)
plant_spray(plantArray, strength-1, x-1,y-1);
break;
case 5: // north east square
if( y > 0 && x < max_x_loc-1 )
plant_spray(plantArray, strength-1, x+1,y-1);
break;
case 6: // south east square
if( y < max_y_loc-1 && x < max_x_loc-1)
plant_spray(plantArray, strength-1, x+1,y+1);
break;
case 7: // south west square
if( y < max_y_loc-1 && x > 0)
plant_spray(plantArray, strength-1, x-1,y+1);
break;
}
}
}
}
//------------ end of function World::plant_spray ------------//