00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "global.h"
00023 #include "viewcalculation.h"
00024 #include "mapalgorithms.h"
00025
00026 #include "vehicletype.h"
00027 #include "buildingtype.h"
00028 #include "errors.h"
00029 #include "gameeventsystem.h"
00030
00031 SigC::Signal0<void> buildingSeen;
00032
00033
00034 void tcomputeview::initviewcalculation( int view, int jamming, int sx, int sy, int _mode, int _height )
00035 {
00036 height = _height;
00037
00038 if ( view < 0 )
00039 view = 0;
00040
00041 if ( view > 255 )
00042 viewdist = 255;
00043 else
00044 viewdist = view;
00045 jamdist = jamming;
00046 mode = _mode;
00047
00048 int md;
00049 if ( viewdist > jamdist )
00050 md = viewdist / minmalq + 1;
00051 else
00052 md = jamdist / minmalq + 1;
00053
00054 initsearch( MapCoordinate(sx, sy), md, 0 );
00055 }
00056
00057
00058
00059 void tcomputeview::testfield( const MapCoordinate& mc )
00060 {
00061 int f = beeline(startPos, mc);
00062 tfield* efield = gamemap->getField(mc);
00063
00064 if ( viewdist && ( f <= 15 ) && (gamemap->getgameparameter( cgp_disableDirectView) == 0 || f < 10 ) )
00065 efield->view[player].direct += mode;
00066
00067 int str = viewdist;
00068 if ( f ) {
00069 int freefields = 0;
00070 #if 0
00071 if ( height > chhochfliegend )
00072 freefields = 5;
00073 else
00074 if ( height == chhochfliegend )
00075 freefields = 3;
00076 else
00077 if ( height == chfliegend )
00078 freefields = 2;
00079 else
00080 if ( height == chtieffliegend )
00081 freefields = 1;
00082 #endif
00083 if ( height > chhochfliegend )
00084 baseJammingMultiplier = 33;
00085 else
00086 if ( height == chhochfliegend )
00087 baseJammingMultiplier = 50;
00088 else
00089 if ( height == chfliegend )
00090 baseJammingMultiplier = 66;
00091 else
00092 baseJammingMultiplier = 100;
00093
00094
00095 tdrawgettempline lne ( freefields, gamemap );
00096
00097 if ( startPos.x == -1 || startPos.y == -1 )
00098 fatalError("error in tcomputeview::testfield" );
00099
00100 lne.start ( startPos.x, startPos.y, mc.x, mc.y );
00101 str -= f;
00102 str -= lne.tempsum * baseJammingMultiplier / 100;
00103 }
00104
00105 if ( str > 0 ) {
00106 efield->view[player].view += str * mode;
00107
00108 if ( sonar )
00109 efield->view[player].sonar += mode;
00110
00111 if ( satellitenview )
00112 efield->view[player].satellite += mode;
00113
00114 if ( minenview )
00115 efield->view[player].mine += mode;
00116 }
00117
00118 if ( rangeJamming || !f ) {
00119 int jamloss = f * gamemap->getgameparameter ( cgp_jammingSlope ) / 10;
00120 int jamstrength = jamdist * gamemap->getgameparameter ( cgp_jammingAmplifier ) / 100;
00121 if ( jamstrength >= jamloss )
00122 efield->view[player].jamming += (jamstrength - jamloss) * mode;
00123 }
00124
00125 #ifdef DEBUGVIEW
00126 if ( efield->view[player].view < 0 ||
00127 efield->view[player].sonar < 0 ||
00128 efield->view[player].satellite < 0 ||
00129 efield->view[player].jamming < 0 ||
00130 efield->view[player].mine < 0 )
00131 displaymessage ( "Warning: inconsistency in view calculation !!\n Please report this bug !", 1 );
00132 #endif
00133 }
00134
00135
00136
00137 void tcomputevehicleview::init( const Vehicle* eht, int _mode )
00138 {
00139 player = eht->getOwner();
00140
00141 if ( player >= eht->getMap()->getPlayerCount() )
00142 fatalError ( "ComputeVehicleView::init - invalid player ");
00143
00144 if ( eht->height == chsatellit )
00145 satellitenview = 1;
00146 else
00147 satellitenview = eht->typ->hasFunction( ContainerBaseType::SatelliteView );
00148
00149 sonar = eht->typ->hasFunction( ContainerBaseType::Sonar );
00150 minenview = eht->typ->hasFunction( ContainerBaseType::MineView );
00151 if ( eht->typ->hasFunction( ContainerBaseType::JamsOnlyOwnField ) )
00152 rangeJamming = false;
00153
00154 if ( eht->typ->hasFunction( ContainerBaseType::DetectsMineralResources ) && _mode == 1 )
00155 eht->searchForMineralResources();
00156
00157 int view = eht->typ->view+1;
00158 if ( eht->height <= chfahrend) {
00159 view += gamemap->getField ( eht->getPosition() )->viewbonus;
00160 if ( view < 1 )
00161 view = 1;
00162 }
00163
00164
00165 tcomputeview::initviewcalculation( view, eht->typ->jamming, eht->xpos, eht->ypos, _mode, eht->height );
00166
00167
00168 }
00169
00170
00171
00172 void tcomputebuildingview::init( const Building* bld, int _mode )
00173 {
00174 player = bld->getOwner();
00175
00176 if ( player >= bld->getMap()->getPlayerCount() )
00177 fatalError ( "ComputeBuildingView::init - invalid player ");
00178
00179 int c, j ;
00180
00181 if (bld->getCompletion() == bld->typ->construction_steps - 1) {
00182 c = bld->typ->view + 1;
00183 if ( bld->typ->buildingheight <= chfahrend ) {
00184 c += gamemap->getField ( bld->getEntry() )->viewbonus;
00185 if ( c < 1 )
00186 c = 1;
00187 }
00188 j = bld->typ->jamming;
00189 } else {
00190 c = 15;
00191 j = 0;
00192 }
00193
00194 initviewcalculation( c, j, bld->getEntry().x, bld->getEntry().y, _mode, bld->typ->buildingheight );
00195
00196 if ( bld->typ->buildingheight == chsatellit )
00197 satellitenview = 1;
00198 else
00199 satellitenview = bld->typ->hasFunction( ContainerBaseType::SatelliteView );
00200
00201 sonar = bld->typ->hasFunction( ContainerBaseType::Sonar );
00202 minenview = bld->typ->hasFunction( ContainerBaseType::MineView );
00203 if ( bld->typ->hasFunction( ContainerBaseType::JamsOnlyOwnField ) )
00204 rangeJamming = false;
00205
00206 building = bld;
00207
00208 for ( int a = 0; a < 4; a++)
00209 for (int b = 0; b < 6; b++)
00210 if ( building->typ->fieldExists ( BuildingType::LocalCoordinate( a, b ) )) {
00211 tfield* efield = building->getField ( BuildingType::LocalCoordinate( a, b ) );
00212 if ( minenview )
00213 efield->view[player].mine += _mode;
00214 efield->view[player].direct += _mode;
00215 }
00216 }
00217
00218
00219
00220
00221
00222 void clearvisibility( GameMap* gamemap, int reset )
00223 {
00224 if (!gamemap || (gamemap->xsize <= 0) || (gamemap->ysize <= 0))
00225 return;
00226
00227 for ( int p = 0; p < gamemap->getPlayerCount() ; p++ )
00228 for ( Player::VehicleList::iterator i = gamemap->player[p].vehicleList.begin(); i != gamemap->player[p].vehicleList.end(); i++ )
00229 if ( (*i)->isViewing())
00230 (*i)->removeview();
00231
00232 int l = 0;
00233 for ( int x = 0; x < gamemap->xsize ; x++)
00234 for ( int y = 0; y < gamemap->ysize ; y++) {
00235 tfield* fld = &gamemap->field[l];
00236 memset ( fld->view, 0, sizeof ( fld->view ));
00237 l++;
00238 }
00239
00240
00241 }
00242
00243
00244 VisibilityStates calcvisibilityfield ( GameMap* gamemap, tfield* fld, int player, int add, int initial, int additionalEnemyJamming )
00245 {
00246 if ( player == -1 )
00247 return visible_all;
00248
00249 if ( player <= -2 )
00250 return visible_not;
00251
00252 if ( gamemap->player[player].stat == Player::supervisor )
00253 return visible_all;
00254
00255 if ( initial == 2 )
00256 return visible_all;
00257
00258
00259 VisibilityStates view = visible_not;
00260
00261 if ( ((fld->visible >> (player * 2)) & 3) >= visible_ago || initial == 1)
00262 view = visible_ago;
00263
00264 if ( add == -1 )
00265 add = getPlayersWithSharedViewMask( player, gamemap );
00266
00267 add |= 1 << player;
00268
00269 int sight = 0;
00270 int jamming = 0;
00271 int mine = 0;
00272 int satellite = 0;
00273 int direct = 0;
00274 int sonar = 0;
00275 for ( int i = 0; i < gamemap->getPlayerCount(); i++ ){
00276 if ( add & ( 1 << i )) {
00277 sight += fld->view[i].view;
00278 mine += fld->view[i].mine;
00279 satellite += fld->view[i].satellite;
00280 direct += fld->view[i].direct;
00281 sonar += fld->view[i].sonar;
00282 } else
00283 jamming += fld->view[i].jamming;
00284 }
00285 if ( sight > (jamming + additionalEnemyJamming ) || direct ) {
00286 if (( fld->vehicle && ( fld->vehicle->getOwner() == player ) && false ) ||
00287 ( fld->vehicle && ( fld->vehicle->height < chschwimmend ) && sonar ) ||
00288 ( fld->building && ( fld->building->typ->buildingheight < chschwimmend ) && sonar ) ||
00289 ( !fld->mines.empty() && ( mine || fld->mineowner() == player)) ||
00290 ( fld->vehicle && ( fld->vehicle->height >= chsatellit ) && satellite )) {
00291 return visible_all;
00292 } else {
00293 return visible_now;
00294 }
00295 } else
00296 return view;
00297 }
00298
00299 int evaluatevisibilityfield ( GameMap* gamemap, tfield* fld, int player, int add, int initial )
00300 {
00301 if ( player < 0 )
00302 return 0;
00303
00304 int originalVisibility;
00305 if ( initial == 2 ) {
00306 fld->setVisibility(visible_all, player);
00307 return 0;
00308 } else {
00309 originalVisibility = (fld->visible >> (player * 2)) & 3;
00310 if ( originalVisibility >= visible_ago || initial == 1)
00311 fld->setVisibility(visible_ago, player);
00312 }
00313
00314 VisibilityStates view = calcvisibilityfield( gamemap, fld, player, add, initial, 0 );
00315 fld->setVisibility( view, player );
00316 if ( view >= visible_now )
00317 if ( fld->building && (fld->building->connection & cconnection_seen))
00318 buildingSeen();
00319 return view != originalVisibility;
00320 }
00321
00322
00323 int evaluateviewcalculation ( GameMap* gamemap, int player_fieldcount_mask, bool disableShareView )
00324 {
00325 int initial = gamemap->getgameparameter ( cgp_initialMapVisibility );
00326 int fieldsChanged = 0;
00327 for ( int player = 0; player < gamemap->getPlayerCount(); player++ )
00328 if ( gamemap->player[player].exist() ) {
00329 int add = 0;
00330 if ( !disableShareView )
00331 add += getPlayersWithSharedViewMask( player, gamemap );
00332
00333 int nm = gamemap->xsize * gamemap->ysize;
00334 if ( player_fieldcount_mask & (1 << player ))
00335 for ( int i = 0; i < nm; i++ )
00336 fieldsChanged += evaluatevisibilityfield ( gamemap, &gamemap->field[i], player, add, initial );
00337 else
00338 for ( int i = 0; i < nm; i++ )
00339 evaluatevisibilityfield ( gamemap, &gamemap->field[i], player, add, initial );
00340 }
00341 return fieldsChanged;
00342 }
00343
00344 int evaluateviewcalculation ( GameMap* gamemap, const MapCoordinate& pos, int distance, int player_fieldcount_mask, bool disableShareView )
00345 {
00346 distance = (distance+maxmalq-1)/maxmalq;
00347 int x1 = pos.x - distance;
00348 if ( x1 < 0 )
00349 x1 = 0;
00350
00351 int y1 = pos.y - distance*2;
00352 if ( y1 < 0 )
00353 y1 = 0;
00354
00355 int x2 = pos.x + distance;
00356 if ( x2 >= gamemap->xsize )
00357 x2 = gamemap->xsize-1;
00358
00359 int y2 = pos.y + distance*2;
00360 if ( y2 >= gamemap->ysize )
00361 y2 = gamemap->ysize-1;
00362
00363 int initial = gamemap->getgameparameter ( cgp_initialMapVisibility );
00364 int fieldsChanged = 0;
00365 for ( int player = 0; player < gamemap->getPlayerCount(); player++ )
00366 if ( gamemap->player[player].exist() ) {
00367 int add = 0;
00368 if ( !disableShareView )
00369 for ( int i = 0; i < gamemap->getPlayerCount(); i++ )
00370 if ( gamemap->player[i].exist() && i != player )
00371 if ( gamemap->player[i].diplomacy.sharesView( player) )
00372 add |= 1 << i;
00373
00374 for ( int yy = y1; yy <= y2; yy++ )
00375 for ( int xx = x1; xx <= x2; xx++ ) {
00376 tfield* fld = gamemap->getField ( xx, yy );
00377 int result = evaluatevisibilityfield ( gamemap, fld, player, add, initial );
00378 if ( player_fieldcount_mask & (1 << player ))
00379 fieldsChanged += result;
00380 }
00381 }
00382 return fieldsChanged;
00383 }
00384
00385
00386
00387 int computeview( GameMap* gamemap, int player_fieldcount_mask, bool disableShareView )
00388 {
00389 if ( !gamemap || (gamemap->xsize == 0) || (gamemap->ysize == 0))
00390 return 0;
00391
00392 clearvisibility( gamemap, 1 );
00393
00394 for ( int a = 0; a < gamemap->getPlayerCount(); a++)
00395 if (gamemap->player[a].exist() ) {
00396
00397 for ( Player::VehicleList::iterator i = gamemap->player[a].vehicleList.begin(); i != gamemap->player[a].vehicleList.end(); i++ ) {
00398 Vehicle* actvehicle = *i;
00399 if ( actvehicle == gamemap->getField(actvehicle->getPosition())->vehicle)
00400 actvehicle->addview();
00401 }
00402
00403 for ( Player::BuildingList::iterator i = gamemap->player[a].buildingList.begin(); i != gamemap->player[a].buildingList.end(); i++ )
00404 (*i)->addview();
00405 }
00406
00407
00408 return evaluateviewcalculation ( gamemap, player_fieldcount_mask, disableShareView );
00409 }
00410
00411
00412 int getPlayersWithSharedViewMask( int player, GameMap* gamemap )
00413 {
00414 if ( player < 0 )
00415 return 0;
00416
00417 int add = 0;
00418 for ( int i = 0; i < gamemap->getPlayerCount(); i++ )
00419 if ( gamemap->player[i].exist() && i != player )
00420 if ( gamemap->player[i].diplomacy.sharesView( player) )
00421 add |= 1 << i;
00422
00423 return add;
00424 }
00425
00426 #if 0
00427 VisibilityStates fieldVisibility( tfield* pe, int player, GameMap* gamemap, int additionalEnemyJamming )
00428 {
00429 evaluatevisibilityfield( gamemap, pe, player, getPlayersWithSharedViewMask(player,gamemap), gamemap->getgameparameter ( cgp_initialMapVisibility ), additionalEnemyJamming );
00430 #ifdef karteneditor
00431 player = 0;
00432 #endif
00433 if ( pe && player >= 0 ) {
00434 VisibilityStates c = VisibilityStates((pe->visible >> ( player * 2)) & 3);
00435 #ifdef karteneditor
00436 c = visible_all;
00437 #endif
00438
00439 if ( c < gamemap->getInitialMapVisibility( player ) )
00440 c = gamemap->getInitialMapVisibility( player );
00441
00442 return c;
00443 } else
00444 return visible_not;
00445 }
00446 #endif
00447
00448
00449 RecalculateAreaView :: RecalculateAreaView( GameMap* gamemap, const MapCoordinate& pos, int range ) : active(false)
00450 {
00451 position = pos;
00452 this->range = range;
00453 this->gamemap = gamemap;
00454 }
00455
00456 void RecalculateAreaView::removeView()
00457 {
00458 circularFieldIterator( gamemap, position, 0, range, FieldIterationFunctor( this, &RecalculateAreaView::removeFieldView ));
00459 active = true;
00460 }
00461
00462 void RecalculateAreaView::addView()
00463 {
00464 circularFieldIterator( gamemap, position, 0, range, FieldIterationFunctor( this, &RecalculateAreaView::addFieldView ));
00465 evaluateviewcalculation( gamemap, position, range );
00466 active = false;
00467 }
00468
00469 void RecalculateAreaView::removeFieldView( const MapCoordinate& pos )
00470 {
00471 tfield* fld = gamemap->getField(pos);
00472 if ( fld && fld->getContainer() && fld->getContainer()->getOwner() < fld->getContainer()->getMap()->getPlayerCount() )
00473 fld->getContainer()->removeview();
00474 }
00475
00476 void RecalculateAreaView::addFieldView( const MapCoordinate& pos )
00477 {
00478 tfield* fld = gamemap->getField(pos);
00479 if ( fld && fld->getContainer() && fld->getContainer()->getOwner() < fld->getContainer()->getMap()->getPlayerCount() )
00480 fld->getContainer()->addview();
00481 }
00482
00483 RecalculateAreaView::~RecalculateAreaView()
00484 {
00485 if ( active )
00486 addView();
00487 }