viewcalculation.cpp

Go to the documentation of this file.
00001 
00005 /***************************************************************************
00006                           viewcalculation.cpp  -  description
00007                              -------------------
00008     begin                : Thu Oct 5 2000
00009     copyright            : (C) 2000 by Martin Bickel
00010     email                : bickel@asc-hq.org
00011  ***************************************************************************/
00012 
00013 /***************************************************************************
00014  *                                                                         *
00015  *   This program is free software; you can redistribute it and/or modify  *
00016  *   it under the terms of the GNU General Public License as published by  *
00017  *   the Free Software Foundation; either version 2 of the License, or     *
00018  *   (at your option) any later version.                                   *
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  )  // mode: +1 = add view  ;  -1 = remove view
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  )   // mode: +1 = add view  ;  -1 = remove view ); )
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    if ( eht->typ->hasFunction( ContainerBaseType::DetectsMineralResources  ) && _mode == 1 )
00157       eht->searchForMineralResources();
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  //  testfield( eht->getPosition() );
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                   // first player in loop, so we save the current state as the 'original' state
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                // we are running under action control, the change shall be done by the action and not here,
00368                // so we are undoing our change for the moment
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             // we are running under action control, the change shall be done by the action and not here,
00434             // so we are undoing our change for the moment
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() ) { //excluding neutral buildings here
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 }

Generated on Mon May 21 01:26:39 2012 for Advanced Strategic Command by  doxygen 1.5.1