Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

spfst.cpp

Go to the documentation of this file.
00001 
00005 /*
00006     This file is part of Advanced Strategic Command; http://www.asc-hq.de
00007     Copyright (C) 1994-2005  Martin Bickel  and  Marc Schellenberger
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU General Public License for more details.
00018 
00019     You should have received a copy of the GNU General Public License
00020     along with this program; see the file COPYING. If not, write to the 
00021     Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
00022     Boston, MA  02111-1307  USA
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    if ( c == visible_all)
00145       if ( field->mines.size() )
00146          for ( int i = 0; i < field->mines.size(); i++ )
00147             if ( field->getMine(i).attacksunit( vehicle ))
00148                return 0;
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 {   // building
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       int maxresearch = 0;
00266       bool found = false;
00267       for ( GameMap::Player::BuildingList::iterator i = actmap->player[color/8].buildingList.begin(); i != actmap->player[ color/8].buildingList.end(); i++ ) {
00268          Building* bld = *i;
00269          if ( bld->typ == gbde->typ  && bld != gbde ) {
00270             found = true;
00271 
00272             for ( int r = 0; r < 3; r++ ) {
00273                if ( bld->maxplus.resource(r) > maxplus.resource(r) )
00274                  maxplus  = bld->maxplus;
00275 
00276                if ( bld->bi_resourceplus.resource(r) > biplus.resource(r) )
00277                   biplus = bld->bi_resourceplus;
00278 
00279                if ( bld->plus.resource(r) > actplus.resource(r) )
00280                   actplus = bld->plus;
00281             }
00282 
00283             if ( bld->maxresearchpoints > maxresearch )
00284                maxresearch = bld->maxresearchpoints;
00285          }
00286       }
00287 
00288       gbde->damage = 0;
00289       if ( found ) {
00290          if ( actmap->_resourcemode == 1 ) {
00291             gbde->plus.energy = biplus.energy;
00292             gbde->plus.material = biplus.material;
00293             gbde->plus.fuel = biplus.fuel;
00294          } else {
00295             gbde->plus.energy = maxplus.energy;
00296             gbde->plus.material = maxplus.material;
00297             gbde->plus.fuel = maxplus.fuel;
00298          }
00299          gbde->maxplus = maxplus;
00300          gbde->bi_resourceplus = biplus;
00301       } else {
00302          gbde->plus = gbde->defaultProduction;
00303          gbde->maxplus = gbde->defaultProduction;
00304          gbde->bi_resourceplus = gbde->defaultProduction;
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              /* if the unit was a transport and had other units loaded, these units have been deleted as well.
00381                 We don't know which elements of the container are still valid, so we start from the beginning again. */
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 ) //    || ((eht->height == chfahrend) && ( field->typ->art & cbwater ))) ) 
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 void tdrawline8 :: start ( int x1, int y1, int x2, int y2 )
00425 {
00426    x1 += x1 + (y1 & 1);
00427    x2 += x2 + (y2 & 1);
00428    tdrawline::start ( x1, y1, x2, y2 );
00429 }
00430 
00431 void tdrawline8 :: putpix ( int x, int y )
00432 {
00433        if ( (x & 1) == (y & 1) )
00434           putpix8( x/2, y );
00435 }
00436 */
00437 /*
00438 void EllipseOnScreen :: paint ( void )
00439 {
00440    if ( active )
00441       ellipse ( x1, y1, x2, y2, color, precision );
00442 }
00443 
00444 void EllipseOnScreen :: read( tnstream& stream )
00445 {
00446   x1 = stream.readInt();
00447   y1 = stream.readInt();
00448   x2 = stream.readInt();
00449   y2 = stream.readInt();
00450   color = stream.readInt();
00451   precision = stream.readFloat();
00452   active = stream.readInt();
00453 }
00454 
00455 void EllipseOnScreen :: write ( tnstream& stream )
00456 {
00457    stream.writeInt( x1 );
00458    stream.writeInt( y1 );
00459    stream.writeInt( x2 );
00460    stream.writeInt( y2 );
00461    stream.writeInt( color );
00462    stream.writeFloat( precision );
00463    stream.writeInt( active );
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       // ForestCalculation::calculateforest( actmap, obj );
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             // if the field opposite of the border field is connected to, make a straight line out of the map.
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    // vector<ObjectType*> forestObjects;
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              // if ( !(i->typ->netBehaviour & ObjectType::SpecialForest) )
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 

Generated on Tue Jun 24 01:27:52 2008 for Advanced Strategic Command by  doxygen 1.4.2