00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026 #include <cstring>
00027 #include <utility>
00028 #include <map>
00029
00030
00031 #include "vehicletype.h"
00032 #include "buildingtype.h"
00033
00034 #include "typen.h"
00035 #include "spfst.h"
00036 #include "attack.h"
00037
00038 #include "mapalgorithms.h"
00039 #include "vehicle.h"
00040 #include "buildings.h"
00041 #include "mapfield.h"
00042
00043 SigC::Signal0<void> repaintMap;
00044 SigC::Signal0<void> repaintDisplay;
00045 SigC::Signal0<void> updateFieldInfo;
00046 SigC::Signal0<void> cursorMoved;
00047 SigC::Signal1<void,ContainerBase*> showContainerInfo;
00048 SigC::Signal1<void,Vehicletype*> showVehicleTypeInfo;
00049 SigC::Signal0<void> viewChanged;
00050 SigC::Signal1<void,GameMap*> mapChanged;
00051 SigC::Signal0<bool> idleEvent;
00052
00053
00054
00055 void displaymap()
00056 {
00057 repaintMap();
00058 }
00059
00060
00061 GameMap* actmap = NULL;
00062
00063 Schriften schriften;
00064
00065
00066
00067 int terrainaccessible ( const tfield* field, const Vehicle* vehicle, int uheight )
00068 {
00069 int res = terrainaccessible2 ( field, vehicle, uheight );
00070 if ( res < 0 )
00071 return 0;
00072 else
00073 return res;
00074 }
00075
00076 int terrainaccessible2 ( const tfield* field, const Vehicle* vehicle, int uheight )
00077 {
00078 if ( uheight == -1 )
00079 uheight = vehicle->height;
00080
00081 if ( !(uheight & vehicle->typ->height))
00082 return 0;
00083
00084
00085 return terrainaccessible2( field, vehicle->typ->terrainaccess, uheight );
00086 }
00087
00088 int terrainaccessible2 ( const tfield* field, const TerrainAccess& terrainAccess, int uheight )
00089 {
00090 if ( uheight >= chtieffliegend)
00091 return 2;
00092 else {
00093 if ( uheight == chtiefgetaucht )
00094 if ( (field->bdt & getTerrainBitType(cbwater3) ).any() )
00095 return 2;
00096 else
00097 return -1;
00098 else
00099 if ( uheight == chgetaucht )
00100 if ( (field->bdt & ( getTerrainBitType(cbwater3) | getTerrainBitType(cbwater2 )) ).any() )
00101 return 2;
00102 else
00103 return -2;
00104 else {
00105 if ( terrainAccess.accessible ( field->bdt ) > 0 ) {
00106 if ( uheight == chschwimmend ) {
00107 if ( (field->bdt & getTerrainBitType(cbwater)).any() )
00108 return 2;
00109 else
00110 return -3;
00111 } else
00112 return 2;
00113 } else
00114 return -3;
00115 }
00116 }
00117 }
00118
00119
00120
00121 int fieldAccessible( const tfield* field,
00122 const Vehicle* vehicle,
00123 int uheight,
00124 const bool* attacked,
00125 bool ignoreVisibility )
00126 {
00127 if ( !field || !vehicle )
00128 return 0;
00129
00130 if ( uheight == -2 )
00131 uheight = vehicle->height;
00132
00133 if ( !ignoreVisibility ) {
00134 int c = fieldVisibility ( field, vehicle->color/8 );
00135
00136 if (field == NULL)
00137 return 0;
00138
00139 if (c == visible_not)
00140 return 0;
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 if ( (!field->vehicle || field->vehicle == vehicle) && !field->building ) {
00153 if ( vehicle->typ->height & uheight )
00154 return terrainaccessible ( field, vehicle, uheight );
00155 else
00156 return 0;
00157 } else {
00158 if (field->vehicle) {
00159 if ( vehicle->getMap()->getPlayer(vehicle).diplomacy.isAllied( field->vehicle->getOwner()) ) {
00160 if ( field->vehicle->vehicleLoadable ( vehicle, uheight ) )
00161 return 2;
00162 else
00163 if ( terrainaccessible ( field, vehicle, uheight ))
00164 return 1;
00165 else
00166 return 0;
00167 }
00168 else
00169 if ( terrainaccessible ( field, vehicle, uheight ) ) {
00170 if (vehicleplattfahrbar(vehicle,field))
00171 return 2;
00172 else
00173 if ( getheightdelta(log2(field->vehicle->height), log2(vehicle->height)) || (attackpossible28(field->vehicle,vehicle) == false) || actmap->player[actmap->actplayer].diplomacy.getState( field->vehicle->getOwner()) >= PEACE )
00174 return 1;
00175 }
00176 }
00177 else {
00178 if ((field->bdt & getTerrainBitType(cbbuildingentry) ).any() && field->building->vehicleLoadable ( vehicle, uheight, attacked ))
00179 return 2;
00180 else
00181 if (uheight >= chtieffliegend || (field->building->typ->buildingheight <= chgetaucht && uheight >= chschwimmend ))
00182 return 1;
00183 else
00184 return 0;
00185 }
00186 }
00187 return 0;
00188 }
00189
00190
00191
00192
00193
00194
00195 tfield* getfield(int x,
00196 int y)
00197 {
00198 if ((x < 0) || (y < 0) || (x >= actmap->xsize) || (y >= actmap->ysize))
00199 return NULL;
00200 else
00201 return ( &actmap->field[y * actmap->xsize + x] );
00202 }
00203
00204
00205
00206 void putbuilding( const MapCoordinate& entryPosition,
00207 int color,
00208 const BuildingType* buildingtyp,
00209 int completion,
00210 int ignoreunits )
00211 {
00212 if ( color & 7 )
00213 fatalError("putbuilding muss eine farbe aus 0,8,16,24,.. uebergeben werden !",2);
00214
00215 for ( int a = 0; a < 4; a++)
00216 for ( int b = 0; b < 6; b++ )
00217 if ( buildingtyp->fieldExists ( BuildingType::LocalCoordinate( a, b ) ) ) {
00218 tfield* field = actmap->getField( buildingtyp->getFieldCoordinate( entryPosition, BuildingType::LocalCoordinate(a,b) ));
00219 if (field == NULL)
00220 return ;
00221 else {
00222 if ( field->vehicle && (!ignoreunits ) )
00223 return;
00224 if (field->building != NULL)
00225 return;
00226 }
00227 }
00228
00229
00230 Building* gbde = new Building ( actmap , entryPosition, buildingtyp, color/8 );
00231
00232 if (completion >= buildingtyp->construction_steps)
00233 completion = buildingtyp->construction_steps - 1;
00234
00235 gbde->setCompletion ( completion );
00236 }
00237
00238
00239 void putbuilding2( const MapCoordinate& entryPosition,
00240 int color,
00241 BuildingType* buildingtyp)
00242 {
00243 if ( color & 7 )
00244 fatalError("putbuilding muss eine farbe aus 0,8,16,24,.. uebergeben werden !",2);
00245
00246 for ( int a = 0; a < 4; a++)
00247 for ( int b = 0; b < 6; b++ )
00248 if ( buildingtyp->fieldExists ( BuildingType::LocalCoordinate( a, b ) ) ) {
00249 tfield* field = actmap->getField( buildingtyp->getFieldCoordinate( entryPosition, BuildingType::LocalCoordinate(a,b) ));
00250 if (field == NULL)
00251 return ;
00252 else {
00253 if ( field->vehicle )
00254 return;
00255 }
00256 }
00257
00258 if ( !actmap->getField(entryPosition)->building ) {
00259 Building* gbde = new Building ( actmap, entryPosition, buildingtyp, color/8 );
00260
00261 Resources maxplus;
00262 Resources actplus;
00263 Resources biplus;
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 gbde->plus = gbde->typ->defaultProduction;
00309 gbde->maxplus = gbde->typ->defaultProduction;
00310 gbde->bi_resourceplus = gbde->typ->defaultProduction;
00311
00312 gbde->actstorage.fuel = 0;
00313 gbde->actstorage.material = 0;
00314 gbde->actstorage.energy = 0;
00315 gbde->netcontrol = 0;
00316 gbde->connection = 0;
00317 gbde->visible = true;
00318 gbde->setCompletion ( 0 );
00319 }
00320 else {
00321 Building* gbde = actmap->getField(entryPosition)->building;
00322 if (gbde->getCompletion() < gbde->typ->construction_steps-1)
00323 gbde->setCompletion( gbde->getCompletion()+1 );
00324
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333 void checkobjectsforremoval ( void )
00334 {
00335 for ( int y = 0; y < actmap->ysize; y++ )
00336 for ( int x = 0; x < actmap->xsize; x++ ) {
00337 tfield* fld = getfield ( x, y );
00338 for ( tfield::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); )
00339 if ( i->typ->getFieldModification(fld->getweather()).terrainaccess.accessible ( fld->bdt ) < 0 ) {
00340 fld->removeobject ( i->typ, true );
00341 i = fld->objects.begin();
00342 } else
00343 i++;
00344 }
00345 }
00346
00347 void checkunitsforremoval ( void )
00348 {
00349 for ( int c=0; c<=8 ;c++ ) {
00350 ASCString msg;
00351 for ( Player::VehicleList::iterator i = actmap->player[c].vehicleList.begin(); i != actmap->player[c].vehicleList.end(); ) {
00352
00353 Vehicle* eht = *i;
00354 tfield* field = getfield(eht->xpos,eht->ypos);
00355 bool erase = false;
00356
00357 ASCString reason;
00358 if (field->vehicle == eht) {
00359 if ( eht->height <= chfahrend )
00360 if ( eht->typ->terrainaccess.accessible ( field->bdt ) < 0 ) {
00361 erase = true;
00362 reason = "was swallowed by the ground";
00363 }
00364 if ( eht )
00365 if ( getmaxwindspeedforunit( eht ) < actmap->weather.windSpeed*maxwindspeed ) {
00366 reason = "was blown away by the wind";
00367 erase = true;
00368 }
00369 }
00370 if ( erase ) {
00371 msg += getUnitReference( eht ) + reason;
00372 msg += "\n\n";
00373
00374 Vehicle* pv = *i;
00375 actmap->player[c].vehicleList.erase ( i );
00376 delete pv;
00377
00378
00379
00380
00381
00382 i = actmap->player[c].vehicleList.begin();
00383 } else
00384 i++;
00385 }
00386
00387 if ( !msg.empty() )
00388 new Message ( msg, actmap, 1<<c);
00389 }
00390 }
00391
00392
00393 int getwindheightforunit ( const Vehicle* eht, int uheight )
00394 {
00395 if ( uheight == -1 )
00396 uheight = eht->height;
00397
00398 if ( uheight == chfliegend )
00399 return 1;
00400 else
00401 if ( uheight == chhochfliegend )
00402 return 2;
00403 else
00404 return 0;
00405 }
00406
00407 int getmaxwindspeedforunit ( const Vehicle* eht )
00408 {
00409 tfield* field = getfield(eht->xpos,eht->ypos);
00410 if ( field->vehicle == eht) {
00411 if (eht->height >= chtieffliegend && eht->height <= chhochfliegend )
00412 return eht->typ->movement[log2(eht->height)] * 256 ;
00413
00414 if ( (field->bdt & getTerrainBitType(cbfestland)).none() && eht->height <= chfahrend && eht->height >= chschwimmend && (field->bdt & getTerrainBitType(cbharbour)).none() && (field->bdt & getTerrainBitType(cbwater0)).none())
00415 return eht->typ->maxwindspeedonwater * maxwindspeed;
00416 }
00417 return maxint;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 int getheightdelta ( const ContainerBase* c1, const ContainerBase* c2 )
00469 {
00470 return getheightdelta( log2(c1->getHeight()), log2(c2->getHeight() ));
00471 }
00472
00473
00474 int getheightdelta ( int height1, int height2 )
00475 {
00476 int ah = height1;
00477 int dh = height2;
00478 int hd = dh - ah;
00479
00480 if ( ah >= 3 && dh <= 2 )
00481 hd++;
00482 if (dh >= 3 && ah <= 2 )
00483 hd--;
00484
00485 return hd;
00486 }
00487
00488 bool fieldvisiblenow( const tfield* pe, int player, Vehicle* veh, GameMap* actmap )
00489 {
00490 if ( player == -1 )
00491 return true;
00492
00493 if ( player < -1 )
00494 return false;
00495
00496 if ( !actmap )
00497 return false;
00498
00499 if ( pe ) {
00500 int c = (pe->visible >> ( player * 2)) & 3;
00501
00502 if ( c < actmap->getInitialMapVisibility( player ) )
00503 c = actmap->getInitialMapVisibility( player );
00504
00505 if (c > visible_ago) {
00506 if ( !veh )
00507 veh = pe->vehicle;
00508
00509 if ( veh ) {
00510 if ((c == visible_all) || (veh->color / 8 == player ) || ((veh->height >= chschwimmend) && (veh->height <= chhochfliegend)))
00511 return true;
00512 }
00513 else
00514 if (pe->building != NULL) {
00515 if ((c == visible_all) || (pe->building->typ->buildingheight >= chschwimmend) || (pe->building->color == player*8))
00516 return true;
00517 }
00518 else
00519 return true;
00520 }
00521 }
00522 return false;
00523 }
00524
00525
00526 bool fieldvisiblenow( const tfield* pe, Vehicle* veh, int player )
00527 {
00528 return fieldvisiblenow( pe, player, veh, veh->getMap());
00529 }
00530
00531 bool fieldvisiblenow( const tfield* pe, int player, GameMap* actmap )
00532 {
00533 return fieldvisiblenow( pe, player, NULL, actmap );
00534
00535 }
00536
00537
00538
00539
00540 VisibilityStates fieldVisibility( const tfield* pe, int player )
00541 {
00542 return fieldVisibility( pe, player, actmap );
00543 }
00544
00545 VisibilityStates fieldVisibility( const tfield* pe, int player, GameMap* gamemap )
00546 {
00547 if ( player < 0 )
00548 return visible_all;
00549
00550 if ( pe ) {
00551 VisibilityStates c = VisibilityStates((pe->visible >> ( player * 2)) & 3);
00552 if ( c < gamemap->getInitialMapVisibility( player ) )
00553 c = gamemap->getInitialMapVisibility( player );
00554
00555 return c;
00556 } else
00557 return visible_not;
00558 }
00559
00560
00561 void calculateobject( const MapCoordinate& pos,
00562 bool mof,
00563 const ObjectType* obj,
00564 GameMap* gamemap )
00565 {
00566 calculateobject( pos.x, pos.y, mof, obj, gamemap );
00567 }
00568
00569
00570 void calculateobject( int x,
00571 int y,
00572 bool mof,
00573 const ObjectType* obj,
00574 GameMap* actmap )
00575 {
00576 if ( obj->netBehaviour & ObjectType::KeepOrientation )
00577 return;
00578
00579 if ( obj->netBehaviour & ObjectType::SpecialForest ) {
00580
00581 return;
00582 }
00583
00584 tfield* fld = actmap->getField(x,y) ;
00585 Object* oi2 = fld-> checkforobject ( obj );
00586
00587 int c = 0;
00588 for ( int dir = 0; dir < sidenum; dir++) {
00589 int a = x;
00590 int b = y;
00591 getnextfield( a, b, dir );
00592 tfield* fld2 = actmap->getField(a,b);
00593
00594 if ( fld2 ) {
00595 if ( obj->netBehaviour & ObjectType::NetToSelf )
00596 if ( fld2->checkforobject ( obj )) {
00597 c |= 1 << dir ;
00598 if ( mof )
00599 calculateobject ( a, b, false, obj, actmap );
00600 }
00601
00602
00603 for ( int oj = 0; oj < int(obj->linkableObjects.size()); oj++ ) {
00604 for ( int id = obj->linkableObjects[oj].from; id <= obj->linkableObjects[oj].to; ++id ) {
00605 Object* oi = fld2->checkforobject ( actmap->getobjecttype_byid ( id ) );
00606 if ( oi ) {
00607 c |= 1 << dir ;
00608 if ( mof )
00609 calculateobject ( a, b, false, oi->typ, actmap );
00610 }
00611 }
00612 }
00613
00614 for ( unsigned int t = 0; t < obj->linkableTerrain.size(); t++ )
00615 for ( int id = obj->linkableTerrain[t].from; id <= obj->linkableTerrain[t].to; ++id )
00616 if ( fld2->typ->terraintype->id == id )
00617 c |= 1 << dir ;
00618
00619 if ( fld2->building && !fld2->building->typ->hasFunction( ContainerBaseType::NoObjectChaining ) ) {
00620 if ( (obj->netBehaviour & ObjectType::NetToBuildingEntry) && (fld2->bdt & getTerrainBitType(cbbuildingentry) ).any() )
00621 c |= 1 << dir;
00622
00623 if ( obj->netBehaviour & ObjectType::NetToBuildings )
00624 c |= 1 << dir;
00625 }
00626
00627 }
00628 else {
00629 if ( obj->netBehaviour & ObjectType::NetToBorder )
00630 c |= 1 << dir;
00631 }
00632 }
00633
00634 if ( obj->netBehaviour & ObjectType::AutoBorder ) {
00635 int autoborder = 0;
00636 int count = 0;
00637 for ( int dir = 0; dir < sidenum; dir++) {
00638 int a = x;
00639 int b = y;
00640 getnextfield( a, b, dir );
00641 tfield* fld2 = actmap->getField(a,b);
00642 if ( !fld2 ) {
00643
00644 if ( c & (1 << ((dir+sidenum/2) % sidenum ))) {
00645 autoborder |= 1 << dir;
00646 count++;
00647 }
00648 }
00649 }
00650 if ( count == 1 )
00651 c |= autoborder;
00652 }
00653
00654 if ( oi2 ) {
00655 oi2->setdir ( c );
00656 fld->setparams();
00657 }
00658
00659 }
00660
00661
00662
00663
00664 void calculateallobjects( GameMap* actmap )
00665 {
00666
00667 for ( int y = 0; y < actmap->ysize ; y++)
00668 for ( int x = 0; x < actmap->xsize ; x++) {
00669 tfield* fld = actmap->getField(x,y);
00670
00671 for ( tfield::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); i++ )
00672
00673 calculateobject( x, y, false, i->typ, actmap );
00674 #if 0
00675 else
00676 if ( find ( forestObjects.begin(), forestObjects.end(), i->typ ) == forestObjects.end())
00677 forestObjects.push_back ( i->typ );
00678 #endif
00679
00680 fld->setparams();
00681 }
00682 #if 0
00683 for ( vector<ObjectType*>::iterator i = forestObjects.begin(); i != forestObjects.end(); i++ )
00684 ForestCalculation::calculateforest( actmap, *i );
00685 #endif
00686 }
00687
00688
00689