123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
- // Filename : OW_PLANT.CPP
- // Description: growth of plant
- // Ownership : Gilbert
- #include <OMATRIX.h>
- #include <OWORLD.h>
- #include <OWORLDMT.h>
- #include <OWEATHER.h>
- #include <OPLANT.h>
- #include <OTERRAIN.h>
- #include <ALL.h>
- #include <math.h>
- //------------ 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 ------------//
|