00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <algorithm>
00023 #include <ctime>
00024 #include <cmath>
00025
00026 #include "global.h"
00027 #include "typen.h"
00028 #include "vehicletype.h"
00029 #include "buildingtype.h"
00030 #include "spfst.h"
00031 #include "actions/context.h"
00032 #include "actions/removeobject.h"
00033
00034 MapField :: MapField ( GameMap* gamemap_ )
00035 {
00036 init();
00037 setMap( gamemap_ );
00038 }
00039
00040 MapField :: MapField ( )
00041 {
00042 init();
00043 }
00044
00045
00046 void MapField::init ()
00047 {
00048 bdt.set ( 0 );
00049 typ = NULL;
00050 vehicle = NULL;
00051 secondvehicle = NULL;
00052 building = NULL;
00053 a.temp = 0;
00054 a.temp2 = 0;
00055 temp3 = 0;
00056 temp4 = 0;
00057 visible = 0;
00058 fuel = 0;
00059 material = 0;
00060 resourceview = NULL;
00061 connection = 0;
00062 gamemap = NULL;
00063 viewbonus = 0;
00064 }
00065
00066 int MapField::getMineralMaterial() const
00067 {
00068 return material;
00069 }
00070
00071 int MapField::getMineralFuel() const
00072 {
00073 return fuel;
00074 }
00075
00076 void MapField::setMineralMaterial( int material )
00077 {
00078 if ( material < 0 )
00079 this->material = 0;
00080 else
00081 if ( material > 255 )
00082 this->material = 255;
00083 else
00084 this->material = material;
00085 }
00086 void MapField::setMineralFuel( int fuel )
00087 {
00088 if ( fuel < 0 )
00089 this->fuel = 0;
00090 else
00091 if ( fuel > 255 )
00092 this->fuel = 255;
00093 else
00094 this->fuel = fuel;
00095 }
00096
00097 void MapField::Resourceview::setview( int player, int material, int fuel )
00098 {
00099 visible |= 1 << player;
00100 materialvisible[player] = material;
00101 fuelvisible[player] = fuel;
00102 }
00103
00104 void MapField::Resourceview::resetview( int player )
00105 {
00106 visible &= ~(1<<player);
00107 }
00108
00109
00110 void MapField::endRound( int turn )
00111 {
00112 bool recalc = false;
00113 for ( ObjectContainer::iterator i = objects.begin(); i != objects.end(); ) {
00114 if ( AgeableItem::age( *i )) {
00115 i = objects.erase(i);
00116 recalc = true;
00117 } else
00118 ++i;
00119 }
00120
00121
00122 for ( MineContainer::iterator i = mines.begin(); i != mines.end(); ) {
00123 if ( AgeableItem::age( *i )) {
00124 i = mines.erase(i);
00125 recalc = true;
00126 } else
00127 ++i;
00128 }
00129
00130
00131 if ( recalc )
00132 setparams();
00133 }
00134
00135
00136 void MapField::operator= ( const MapField& f )
00137 {
00138 typ = f.typ;
00139 fuel = f.fuel;
00140 material = f.material;
00141 visible = f.visible;
00142 tempw = f.tempw;
00143 temp3 = f.temp3;
00144 temp4 = f.temp4;
00145 vehicle = f.vehicle;
00146 building = f.building;
00147 if ( f.resourceview ) {
00148 resourceview = new Resourceview;
00149 *resourceview = *f.resourceview;
00150 } else
00151 resourceview = NULL;
00152 mines = f.mines;
00153 objects = f.objects;
00154 connection = f.connection;
00155 bdt = f.bdt;
00156 for ( int i = 0; i < 8; i++ )
00157 view[i] = f.view[i];
00158 }
00159
00160
00161 const TerrainType* MapField::getTerrainType() const
00162 {
00163 return typ->terraintype;
00164 }
00165
00166 void MapField::changeTerrainType( const TerrainType* terrain )
00167 {
00168 int weather = getWeather();
00169 if ( terrain->weather[weather] )
00170 typ = terrain->weather[weather];
00171 else
00172 typ = terrain->weather[0];
00173
00174 setparams ();
00175 }
00176
00177
00178 int MapField :: mineattacks ( const Vehicle* veh )
00179 {
00180 int i = 1;
00181 for ( MineContainer::iterator m = mines.begin(); m != mines.end(); m++, i++ )
00182 if ( m->attacksunit ( veh ))
00183 return i;
00184
00185 return 0;
00186 }
00187
00188 Mine& MapField::getMine ( int n )
00189 {
00190 int c = 0;
00191 MineContainer::iterator i;
00192 for ( i = mines.begin(); c < n; i++,c++ );
00193 return *i;
00194 }
00195
00196 bool MapField :: addobject( const ObjectType* obj, int dir, bool force, MapField::ObjectRemovalStrategy* objectRemovalStrategy )
00197 {
00198 if ( !obj )
00199 return false;
00200
00201 Object* i = checkForObject ( obj );
00202 if ( !i ) {
00203 int buildable = obj->buildable ( this );
00204 if ( !buildable )
00205 if ( force )
00206 buildable = 1;
00207
00208 if ( buildable ) {
00209 Object o ( obj );
00210 if ( dir != -1 )
00211 o.dir = dir;
00212 else
00213 o.dir = 0;
00214
00215 objects.push_back ( o );
00216
00217 sortobjects();
00218 if ( dir == -1 )
00219 calculateobject( getx(), gety(), true, obj, gamemap );
00220
00221 if ( objectRemovalStrategy )
00222 setparams( objectRemovalStrategy );
00223 else
00224 setparams();
00225 return true;
00226 } else
00227 return false;
00228
00229 } else {
00230 if ( dir != -1 )
00231 i->dir |= dir;
00232
00233 i->lifetimer = obj->lifetime;
00234 sortobjects();
00235 return true;
00236 }
00237 }
00238
00239
00240 bool MapField :: removeObject( const ObjectType* obj, bool force, ObjectRemovalStrategy* objectRemovalStrategy )
00241 {
00242 if ( !force && building )
00243 return false;
00244
00245 #ifndef karteneditor
00246 if ( !force )
00247 if ( vehicle )
00248 if ( vehicle->getOwner() != gamemap->actplayer )
00249 return false;
00250 #endif
00251
00252 bool removed = false;
00253
00254 if ( !obj ) {
00255 if ( objects.size() ) {
00256 obj = objects.rbegin()->typ;
00257 objects.pop_back();
00258 removed = true;
00259 }
00260 } else
00261 for ( ObjectContainer::iterator o = objects.begin(); o != objects.end(); )
00262 if ( o->typ == obj ) {
00263 o = objects.erase( o );
00264 removed = true;
00265 } else
00266 o++;
00267
00268 if ( objectRemovalStrategy )
00269 setparams( objectRemovalStrategy );
00270 else
00271 setparams();
00272
00273 if ( obj )
00274 calculateobject( getx(), gety(), true, obj, gamemap );
00275
00276 return removed;
00277 }
00278
00279 void MapField :: deleteeverything ( void )
00280 {
00281 if ( vehicle ) {
00282 delete vehicle;
00283 vehicle = NULL;
00284 }
00285
00286 if ( building ) {
00287 delete building;
00288 building = NULL;
00289 }
00290
00291 setparams();
00292 }
00293
00294
00295 bool MapField :: unitHere ( const Vehicle* veh )
00296 {
00297 if ( vehicle == veh )
00298 return true;
00299
00300 if ( vehicle && veh && vehicle->networkid == veh->networkid )
00301 return true;
00302 return false;
00303 }
00304
00305 Building* MapField::getBuildingEntrance()
00306 {
00307 if ( building && (bdt & getTerrainBitType(cbbuildingentry)).any() )
00308 return building;
00309 else
00310 return NULL;
00311 }
00312
00313
00314
00315 ContainerBase* MapField :: getContainer()
00316 {
00317 if ( vehicle )
00318 return vehicle;
00319 else
00320 return building;
00321 }
00322
00323 const ContainerBase* MapField :: getContainer() const
00324 {
00325 if ( vehicle )
00326 return vehicle;
00327 else
00328 return building;
00329 }
00330
00331
00332 void MapField :: removeBuilding()
00333 {
00334 if ( building )
00335 delete building;
00336 }
00337
00338 void MapField :: removeUnit()
00339 {
00340 if ( vehicle ) {
00341 delete vehicle;
00342 vehicle = NULL;
00343 }
00344 }
00345
00346
00347 int MapField :: getWeather ( void )
00348 {
00349 if ( !typ )
00350 return 0;
00351 for ( int w = 0; w < cwettertypennum; w++ )
00352 if ( typ == typ->terraintype->weather[w] )
00353 return w;
00354 return -1;
00355 }
00356
00357 void MapField :: setWeather ( int weather )
00358 {
00359 if ( weather < 0 || weather >= cwettertypennum )
00360 return;
00361
00362 if (typ->terraintype->weather[ weather ] ) {
00363 typ = typ->terraintype->weather[ weather ];
00364 setparams();
00365 } else {
00366 if ( weather == 2 )
00367 setWeather(1);
00368 else
00369 if ( weather == 5 )
00370 setWeather(4);
00371 else
00372 if (weather==4)
00373 setWeather(3);
00374 else {
00375 typ = typ->terraintype->weather[ 0 ];
00376 setparams();
00377 }
00378 }
00379 }
00380
00381 void MapField::setVisibility ( VisibilityStates valtoset, int actplayer )
00382 {
00383 int newval = (valtoset ^ 3) << ( 2 * actplayer );
00384 int oneval = 3 << ( 2 * actplayer );
00385
00386 visible |= oneval;
00387 visible ^= newval;
00388 };
00389
00390 void MapField::resetView( GameMap* gamemap, int playersToReset )
00391 {
00392 int mask = 0;
00393 for ( int i = 0; i < gamemap->getPlayerCount(); ++i )
00394 if ( !(playersToReset & (1 << i)))
00395 mask |= 3 << (2*i);
00396
00397 int l = 0;
00398 for ( int y = 0; y < gamemap->ysize; ++y )
00399 for ( int x = 0; x < gamemap->xsize; ++x ) {
00400 MapField& fld = gamemap->field[l++];
00401 fld.visible &= mask;
00402 }
00403
00404 }
00405
00406
00407
00408 bool compareObjectHeight ( const Object& o1, const Object& o2 )
00409 {
00410 return o1.typ->imageHeight < o2.typ->imageHeight;
00411 }
00412
00413 void MapField :: sortobjects ( void )
00414 {
00415 sort ( objects.begin(), objects.end(), compareObjectHeight );
00416 }
00417
00418 bool MapField :: putmine( int owner, MineTypes typ, int strength )
00419 {
00420 if ( mineowner() >= 0 && mineowner() != owner )
00421 return false;
00422
00423 if ( mines.size() >= gamemap->getgameparameter ( cgp_maxminesonfield ))
00424 return false;
00425
00426 Mine mymine ( typ, strength, owner, gamemap );
00427 mines.push_back ( mymine );
00428 return true;
00429 }
00430
00431 int MapField :: mineowner( void )
00432 {
00433 if ( mines.empty() )
00434 return -1;
00435 else
00436 return mines.begin()->player;
00437 }
00438
00439
00440 void MapField :: removemine( int num )
00441 {
00442 if ( num == -1 )
00443 num = mines.size() - 1;
00444
00445 int i = 0;
00446 for ( MineContainer::iterator m = mines.begin(); m != mines.end(); i++)
00447 if ( i == num )
00448 m = mines.erase ( m );
00449 else
00450 m++;
00451 }
00452
00453
00454 int MapField :: getx( void )
00455 {
00456 int n = this - gamemap->field;
00457 return n % gamemap->xsize;
00458 }
00459
00460 int MapField :: gety( void )
00461 {
00462 int n = this - gamemap->field;
00463 return n / gamemap->xsize;
00464 }
00465
00466
00467 int MapField :: getattackbonus ( void )
00468 {
00469 int a = typ->attackbonus;
00470 for ( ObjectContainer::iterator o = objects.begin(); o != objects.end(); o++ ) {
00471 if ( o->typ->attackbonus_abs != -1 )
00472 a = o->typ->attackbonus_abs;
00473 else
00474 a += o->typ->attackbonus_plus;
00475 }
00476
00477 if ( a > -8 )
00478 return a;
00479 else
00480 return -7;
00481 }
00482
00483 int MapField :: getdefensebonus ( void )
00484 {
00485 int a = typ->defensebonus;
00486 for ( ObjectContainer::iterator o = objects.begin(); o != objects.end(); o++ ) {
00487 if ( o->typ->defensebonus_abs != -1 )
00488 a = o->typ->defensebonus_abs;
00489 else
00490 a += o->typ->defensebonus_plus;
00491 }
00492
00493 if ( a > -8 )
00494 return a;
00495 else
00496 return -7;
00497 }
00498
00499 ASCString MapField :: getName()
00500 {
00501 ASCString a = typ->terraintype->name;
00502 for ( ObjectContainer::iterator o = objects.begin(); o != objects.end(); o++ ) {
00503 if ( o->typ->namingMethod == ObjectType::ReplaceTerrain )
00504 a = o->typ->getName();
00505 else
00506 if ( o->typ->namingMethod == ObjectType::AddToTerrain )
00507 a += ", " + o->typ->getName();
00508 }
00509
00510 return a;
00511 }
00512
00513
00514 int MapField :: getjamming ( void )
00515 {
00516 int a = typ->basicjamming;
00517 for ( ObjectContainer::iterator o = objects.begin(); o != objects.end(); o++ ) {
00518 if ( o->typ->basicjamming_abs >= 0 )
00519 a = o->typ->basicjamming_abs;
00520 else
00521 a += o->typ->basicjamming_plus;
00522 }
00523 if ( a > 0 )
00524 return a;
00525 else
00526 return 0;
00527 }
00528
00529 int MapField :: getmovemalus ( const Vehicle* veh )
00530 {
00531 int mnum = mines.size();
00532 if ( mnum ) {
00533 int movemalus = __movemalus.at(veh->typ->movemalustyp);
00534 int col = mineowner();
00535 if ( veh->color == col*8 )
00536 movemalus += movemalus * mine_movemalus_increase * mnum / 100;
00537
00538 if ( movemalus < minmalq )
00539 fatalError ( "invalid movemalus for terraintype ID %d used on field %d / %d" , typ->terraintype->id, getx(), gety() );
00540
00541 return movemalus;
00542 } else {
00543 int mm = __movemalus.at(veh->typ->movemalustyp);
00544 if ( mm < minmalq )
00545 fatalError ( "invalid movemalus for terraintype ID %d used on field %d / %d" , typ->terraintype->id, getx(), gety() );
00546 return mm;
00547 }
00548 }
00549
00550 int MapField :: getmovemalus ( int type )
00551 {
00552 return __movemalus.at(type);
00553 }
00554
00555 MapCoordinate MapField :: getPosition()
00556 {
00557 return MapCoordinate( getx(), gety() );
00558 }
00559
00560
00561 class SimpleObjectRemoval : public MapField::ObjectRemovalStrategy {
00562 public:
00563 virtual void removeObject( MapField* fld, const ObjectType* obj )
00564 {
00565 for ( MapField::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); ) {
00566 if ( o->typ == obj )
00567 o = fld->objects.erase( o );
00568 else
00569 ++o ;
00570 }
00571 }
00572 };
00573
00574
00575
00576 void MapField :: setparams ( )
00577 {
00578 SimpleObjectRemoval sor;
00579 setparams( &sor );
00580 }
00581
00582 void MapField :: setparams ( ObjectRemovalStrategy* objectRemovalStrategy )
00583 {
00584 int i;
00585 bdt = typ->art;
00586
00587 for ( i = 0; i < cmovemalitypenum; i++ ) {
00588 __movemalus.at(i) = typ->move_malus[i];
00589 if ( __movemalus[i] < minmalq )
00590 fatalError ( "invalid movemalus for terraintype ID %d used on field %d / %d" , typ->terraintype->id, getx(), gety() );
00591 }
00592
00593 viewbonus = 0;
00594
00595 for ( ObjectContainer::iterator o = objects.begin(); o != objects.end(); o++ ) {
00596 if ( gamemap->getgameparameter ( cgp_objectsDestroyedByTerrain ))
00597 if ( o->typ->getFieldModification(getWeather()).terrainaccess.accessible( bdt ) == -1 ) {
00598 objectRemovalStrategy->removeObject( this, o->typ );
00599 setparams( objectRemovalStrategy );
00600 return;
00601 }
00602
00603 bdt &= o->typ->getFieldModification(getWeather()).terrain_and;
00604 bdt |= o->typ->getFieldModification(getWeather()).terrain_or;
00605
00606 for ( i = 0; i < cmovemalitypenum; i++ ) {
00607 __movemalus[i] += o->typ->getFieldModification(getWeather()).movemalus_plus[i];
00608 if ( (o->typ->getFieldModification(getWeather()).movemalus_abs[i] != 0) && (o->typ->getFieldModification(getWeather()).movemalus_abs[i] != -1) )
00609 __movemalus[i] = o->typ->getFieldModification(getWeather()).movemalus_abs[i];
00610 if ( __movemalus[i] < minmalq )
00611 __movemalus[i] = minmalq;
00612 }
00613
00614 viewbonus += o->typ->viewbonus_plus;
00615 if ( o->typ->viewbonus_abs != -1 )
00616 viewbonus = o->typ->viewbonus_plus;
00617 }
00618
00619 if ( building )
00620 if ( this == building->getField( building->typ->entry ))
00621 bdt |= getTerrainBitType(cbbuildingentry);
00622
00623 }
00624
00625 Object* MapField :: checkForObject ( const ObjectType* o )
00626 {
00627 for ( ObjectContainer::iterator i = objects.begin(); i != objects.end(); i++ )
00628 if ( i->typ == o )
00629 return &(*i);
00630
00631 return NULL;
00632 }
00633
00634
00635 MapField::Resourceview :: Resourceview ( void )
00636 {
00637 visible = 0;
00638 memset ( &fuelvisible, 0, sizeof ( fuelvisible ));
00639 memset ( &materialvisible, 0, sizeof ( materialvisible ));
00640 }
00641
00642
00643 int MapField :: getMemoryFootprint() const
00644 {
00645 int size = sizeof(*this);
00646 return size;
00647 }
00648
00649
00650 MapField :: ~MapField()
00651 {
00652 if ( resourceview ) {
00653 delete resourceview;
00654 resourceview = NULL;
00655 }
00656 }
00657
00658