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