/*! \file viewcalculation.cpp \brief functions for calculating the view of units and buildings */ /*************************************************************************** viewcalculation.cpp - description ------------------- begin : Thu Oct 5 2000 copyright : (C) 2000 by Martin Bickel email : bickel@asc-hq.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "global.h" #include "viewcalculation.h" #include "mapalgorithms.h" #include "vehicletype.h" #include "buildingtype.h" #include "errors.h" #ifdef sgmain // #include "gameevents.h" #endif SigC::Signal0 buildingSeen; void tcomputeview::initviewcalculation( int view, int jamming, int sx, int sy, int _mode, int _height ) // mode: +1 = add view ; -1 = remove view { height = _height; if ( view < 0 ) view = 0; if ( view > 255 ) viewdist = 255; else viewdist = view; jamdist = jamming; mode = _mode; int md; if ( viewdist > jamdist ) md = viewdist / minmalq + 1; else md = jamdist / minmalq + 1; initsearch( MapCoordinate(sx, sy), md, 0 ); } void tcomputeview::testfield( const MapCoordinate& mc ) { int f = beeline(startPos, mc); pfield efield = gamemap->getField(mc); if ( viewdist && ( f <= 15 ) && (gamemap->getgameparameter( cgp_disableDirectView) == 0 || f < 10 ) ) efield->view[player].direct += mode; int str = viewdist; if ( f ) { int freefields = 0; if ( height > chhochfliegend ) freefields = 5; else if ( height == chhochfliegend ) freefields = 3; else if ( height == chfliegend ) freefields = 2; else if ( height == chtieffliegend ) freefields = 1; tdrawgettempline lne ( freefields, gamemap ); if ( startPos.x == -1 || startPos.y == -1 ) fatalError("error in tcomputeview::testfield" ); lne.start ( startPos.x, startPos.y, mc.x, mc.y ); str -= f; str -= lne.tempsum; } if ( str > 0 ) { efield->view[player].view += str * mode; if ( sonar ) efield->view[player].sonar += mode; if ( satellitenview ) efield->view[player].satellite += mode; if ( minenview ) efield->view[player].mine += mode; } if ( rangeJamming || !f ) { int jamloss = f * gamemap->getgameparameter ( cgp_jammingSlope ) / 10; int jamstrength = jamdist * gamemap->getgameparameter ( cgp_jammingAmplifier ) / 100; if ( jamstrength >= jamloss ) efield->view[player].jamming += (jamstrength - jamloss) * mode; } #ifdef DEBUGVIEW if ( efield->view[player].view < 0 || efield->view[player].sonar < 0 || efield->view[player].satellite < 0 || efield->view[player].jamming < 0 || efield->view[player].mine < 0 ) displaymessage ( "Warning: inconsistency in view calculation !!\n Please report this bug !", 1 ); #endif } void tcomputevehicleview::init( const pvehicle eht, int _mode ) // mode: +1 = add view ; -1 = remove view ); ) { player = eht->color / 8; if ( player >= 8 ) fatalError ( "ComputeVehicleView::init - invalid player "); if ( eht->height == chsatellit ) satellitenview = 1; else satellitenview = !!(eht->typ->functions & cfsatellitenview); sonar = !!(eht->typ->functions & cfsonar); minenview = !!(eht->typ->functions & cfmineview); if ( eht->typ->functions & cfownFieldJamming ) rangeJamming = false; if ( (eht->typ->functions & cfautodigger) && _mode == 1 ) eht->searchForMineralResources(); int view = eht->typ->view+1; if ( eht->height <= chfahrend) { view += actmap->getField ( eht->getPosition() )->viewbonus; if ( view < 1 ) view = 1; } tcomputeview::initviewcalculation( view, eht->typ->jamming, eht->xpos, eht->ypos, _mode, eht->height ); // testfield( eht->getPosition() ); } void tcomputebuildingview::init( const pbuilding bld, int _mode ) { player = bld->color / 8; if ( player >= 8 ) fatalError ( "ComputeBuildingView::init - invalid player "); int c, j ; if (bld->getCompletion() == bld->typ->construction_steps - 1) { c = bld->typ->view + 1; if ( bld->typ->buildingheight <= chfahrend ) { c += actmap->getField ( bld->getEntry() )->viewbonus; if ( c < 1 ) c = 1; } j = bld->typ->jamming; } else { c = 15; j = 0; } initviewcalculation( c, j, bld->getEntry().x, bld->getEntry().y, _mode, bld->typ->buildingheight ); sonar = !!(bld->typ->special & cgsonarb); minenview = false; satellitenview = !!(bld->typ->special & cgsatviewb); building = bld; for ( int a = 0; a < 4; a++) for (int b = 0; b < 6; b++) if ( building->getpicture ( BuildingType::LocalCoordinate( a, b ) )) { pfield efield = building->getField ( BuildingType::LocalCoordinate( a, b ) ); if ( minenview ) efield->view[player].mine += _mode; efield->view[player].direct += _mode; } } void clearvisibility( pmap actmap, int reset ) { if (!actmap || (actmap->xsize <= 0) || (actmap->ysize <= 0)) return; for ( int p = 0; p < 8; p++ ) for ( tmap::Player::VehicleList::iterator i = actmap->player[p].vehicleList.begin(); i != actmap->player[p].vehicleList.end(); i++ ) if ( (*i)->isViewing()) (*i)->removeview(); int l = 0; for ( int x = 0; x < actmap->xsize ; x++) for ( int y = 0; y < actmap->ysize ; y++) { pfield fld = &actmap->field[l]; memset ( fld->view, 0, sizeof ( fld->view )); l++; } } int evaluatevisibilityfield ( pmap actmap, pfield fld, int player, int add, int initial ) { int originalVisibility; if ( initial == 2 ) { fld->setVisibility(visible_all, player); return 0; } else { originalVisibility = (fld->visible >> (player * 2)) & 3; if ( originalVisibility >= visible_ago || initial == 1) fld->setVisibility(visible_ago, player); } if ( add == -1 ) { add = 0; if ( actmap->shareview ) for ( int i = 0; i < 8; i++ ) if ( actmap->shareview->mode[i][player] ) add |= 1 << i; } add |= 1 << player; int sight = 0; int jamming = 0; int mine = 0; int satellite = 0; int direct = 0; int sonar = 0; for ( int i = 0; i < 8; i++ ){ if ( add & ( 1 << i )) { sight += fld->view[i].view; mine += fld->view[i].mine; satellite += fld->view[i].satellite; direct += fld->view[i].direct; sonar += fld->view[i].sonar; } else jamming += fld->view[i].jamming; } if ( sight > jamming || direct ) { #ifdef sgmain if ( fld->building && (fld->building->connection & cconnection_seen)) buildingSeen(); #endif if (( fld->vehicle && ( fld->vehicle->color == player * 8 ) && false ) || ( fld->vehicle && ( fld->vehicle->height < chschwimmend ) && sonar ) || ( fld->building && ( fld->building->typ->buildingheight < chschwimmend ) && sonar ) || ( !fld->mines.empty() && ( mine || fld->mineowner() == player)) || ( fld->vehicle && ( fld->vehicle->height >= chsatellit ) && satellite )) { fld->setVisibility( visible_all, player); return originalVisibility != visible_all; } else { fld->setVisibility( visible_now, player); return originalVisibility != visible_now; } } return 0; } int evaluateviewcalculation ( pmap actmap, int player_fieldcount_mask ) { int initial = actmap->getgameparameter ( cgp_initialMapVisibility ); int fieldsChanged = 0; for ( int player = 0; player < 8; player++ ) if ( actmap->player[player].exist() ) { int add = 0; if ( actmap->shareview ) for ( int i = 0; i < 8; i++ ) if ( actmap->player[i].exist() && i != player ) if ( actmap->shareview->mode[i][player] ) add |= 1 << i; int nm = actmap->xsize * actmap->ysize; if ( player_fieldcount_mask & (1 << player )) for ( int i = 0; i < nm; i++ ) fieldsChanged += evaluatevisibilityfield ( actmap, &actmap->field[i], player, add, initial ); else for ( int i = 0; i < nm; i++ ) evaluatevisibilityfield ( actmap, &actmap->field[i], player, add, initial ); } return fieldsChanged; } int evaluateviewcalculation ( pmap actmap, const MapCoordinate& pos, int distance, int player_fieldcount_mask ) { distance = (distance+maxmalq-1)/maxmalq; int x1 = pos.x - distance; if ( x1 < 0 ) x1 = 0; int y1 = pos.y - distance*2; if ( y1 < 0 ) y1 = 0; int x2 = pos.x + distance; if ( x2 >= actmap->xsize ) x2 = actmap->xsize-1; int y2 = pos.y + distance*2; if ( y2 >= actmap->ysize ) y2 = actmap->ysize-1; int initial = actmap->getgameparameter ( cgp_initialMapVisibility ); int fieldsChanged = 0; for ( int player = 0; player < 8; player++ ) if ( actmap->player[player].exist() ) { int add = 0; if ( actmap->shareview ) for ( int i = 0; i < 8; i++ ) if ( actmap->player[i].exist() && i != player ) if ( actmap->shareview->mode[i][player] ) add |= 1 << i; for ( int yy = y1; yy <= y2; yy++ ) for ( int xx = x1; xx <= x2; xx++ ) { pfield fld = actmap->getField ( xx, yy ); if ( player_fieldcount_mask & (1 << player )) fieldsChanged += evaluatevisibilityfield ( actmap, fld, player, add, initial ); else evaluatevisibilityfield ( actmap, fld, player, add, initial ); } } return fieldsChanged; } int computeview( pmap actmap, int player_fieldcount_mask ) { if ((actmap->xsize == 0) || (actmap->ysize == 0)) return 0; clearvisibility( actmap, 1 ); for ( int a = 0; a < 8; a++) if (actmap->player[a].exist() ) { for ( tmap::Player::VehicleList::iterator i = actmap->player[a].vehicleList.begin(); i != actmap->player[a].vehicleList.end(); i++ ) { pvehicle actvehicle = *i; if ( actvehicle == actmap->getField(actvehicle->xpos,actvehicle->ypos)->vehicle) actvehicle->addview(); } for ( tmap::Player::BuildingList::iterator i = actmap->player[a].buildingList.begin(); i != actmap->player[a].buildingList.end(); i++ ) (*i)->addview(); } return evaluateviewcalculation ( actmap, player_fieldcount_mask ); }