moveunit.cpp

Go to the documentation of this file.
00001 /*
00002      This file is part of Advanced Strategic Command; http://www.asc-hq.de
00003      Copyright (C) 1994-2010  Martin Bickel  and  Marc Schellenberger
00004  
00005      This program is free software; you can redistribute it and/or modify
00006      it under the terms of the GNU General Public License as published by
00007      the Free Software Foundation; either version 2 of the License, or
00008      (at your option) any later version.
00009  
00010      This program is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013      GNU General Public License for more details.
00014  
00015      You should have received a copy of the GNU General Public License
00016      along with this program; see the file COPYING. If not, write to the 
00017      Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
00018      Boston, MA  02111-1307  USA
00019 */
00020 
00021 #include <cmath>
00022 
00023 #include "moveunit.h"
00024 #include "unitfieldregistration.h"
00025 #include "changeunitproperty.h"
00026 #include "consumeresource.h"
00027 #include "changeview.h"
00028 #include "convertcontainer.h"
00029 #include "discoverresources.h"
00030 #include "changeunitmovement.h"
00031 #include "action-registry.h"
00032 
00033 #include "../vehicle.h"
00034 #include "../gamemap.h"
00035 #include "../reactionfire.h"
00036 #include "../soundList.h"
00037 #include "../controls.h"
00038 #include "../gameoptions.h"
00039 #include "../mapdisplayinterface.h"
00040 #include "../viewcalculation.h"
00041 #include "../spfst.h"
00042 #include "../gameeventsystem.h"
00043      
00044      
00045 void printTimer( int i )
00046 {
00047 #if 0
00048    static int lastTimer = 0;
00049    if ( i == 1 )
00050       lastTimer = SDL_GetTicks();
00051    else {
00052       printf("%d - %d : %d \n", i-1, i, SDL_GetTicks() - lastTimer);
00053       lastTimer = SDL_GetTicks();
00054    }
00055 #endif
00056 }
00057      
00058      
00059 MoveUnit::MoveUnit( Vehicle* veh, AStar3D::Path& pathToMove, bool dontInterrupt )
00060    : UnitAction( veh->getMap(), veh->networkid )
00061 {
00062    this->pathToMove = pathToMove;
00063    this->dontInterrupt = dontInterrupt;
00064    this->originalUnitMovement = veh->getMovement(false,false);
00065 }
00066       
00067       
00068 ASCString MoveUnit::getDescription() const
00069 {
00070    ASCString res = "Move unit ";
00071    if ( getUnit(false) ) 
00072       res += getUnit(false)->getName();
00073    
00074    return  res;
00075 }
00076       
00077       
00078 static const int moveUnitStreamVersion = 2;      
00079       
00080 void MoveUnit::readData ( tnstream& stream ) 
00081 {
00082    UnitAction::readData( stream );
00083    int version = stream.readInt();
00084    if ( version < 1 || version > moveUnitStreamVersion )
00085       throw tinvalidversion ( "ChangeUnitMovement", moveUnitStreamVersion, version );
00086    
00087    dontInterrupt = stream.readInt();
00088    readClassContainerStaticConstructor( pathToMove, stream );   
00089    if ( version >= 2 )
00090       originalUnitMovement = stream.readInt();
00091    else
00092       originalUnitMovement = -1;
00093 };
00094       
00095       
00096 void MoveUnit::writeData ( tnstream& stream ) const
00097 {
00098    UnitAction::writeData( stream );
00099    stream.writeInt( moveUnitStreamVersion );
00100    stream.writeInt( dontInterrupt );
00101    writeClassContainer( pathToMove, stream );
00102    stream.writeInt( originalUnitMovement );
00103 };
00104 
00105 
00106 GameActionID MoveUnit::getID() const
00107 {
00108    return ActionRegistry::MoveUnit;
00109 }
00110 
00111 
00112 ActionResult MoveUnit::runAction( const Context& context )
00113 {
00114    Vehicle* vehicle = getUnit();
00115    
00116    
00117    auto_ptr<WindMovement> wind;
00118 
00119    if ( (vehicle->typ->height & ( chtieffliegend | chfliegend | chhochfliegend )) && getMap()->weather.windSpeed ) {
00120       wind.reset( new WindMovement ( vehicle ) );
00121    } 
00122    
00123    MapField* oldfield = getMap()->getField( vehicle->getPosition() );
00124 
00125    AStar3D::Path::iterator pos = pathToMove.begin();
00126    AStar3D::Path::iterator stop = pathToMove.end()-1;
00127 
00128    tsearchreactionfireingunits srfu( getMap() );
00129    treactionfire* rf = &srfu;
00130 
00131    int orgMovement = vehicle->getMovement( false );
00132    int orgHeight = vehicle->height;
00133 
00134    rf->init( vehicle, pathToMove );
00135 
00136    if ( oldfield->vehicle == vehicle) 
00137       (new UnitFieldRegistration( vehicle, vehicle->getPosition(), UnitFieldRegistration::RemoveView ))->execute( context );
00138 
00139    
00140    (new UnitFieldRegistration( vehicle, vehicle->getPosition(), UnitFieldRegistration::UnregisterOnField ))->execute( context );
00141    
00142    int soundHeight = -1;
00143    if ( pos->getRealHeight() >= 0 )
00144       soundHeight = pos->getRealHeight();
00145    else
00146       soundHeight = stop->getRealHeight();
00147 
00148    SoundLoopManager slm ( SoundList::getInstance().getSound( SoundList::moving, vehicle->typ->movemalustyp, vehicle->typ->movementSoundLabel, soundHeight ), false );
00149 
00150    int cancelmovement = 0;
00151 
00152    int movedist = 0;
00153    int fueldist = 0;
00154    int networkID = vehicle->networkid;
00155    int operatingPlayer = context.actingPlayer->getPosition();
00156 
00157    bool viewInputChanged= false;
00158    bool mapDisplayUpToDate = true;
00159    bool finalRedrawNecessary = false;
00160 
00161    bool inhibitAttack = false;
00162    while ( pos != stop  && vehicle && cancelmovement!=1 ) {
00163 
00164       if ( cancelmovement > 1 )
00165          cancelmovement--;
00166 
00167       AStar3D::Path::iterator next = pos+1;
00168 
00169 
00170       bool container2container = pos->getNumericalHeight()==-1 && next->getNumericalHeight() == -1;
00171       pair<int,int> mm = calcMoveMalus( *pos, next->getRealPos(), vehicle, wind.get(), &inhibitAttack, container2container );
00172       movedist += mm.first;
00173       fueldist += mm.second;
00174 
00175       if ( next->hasAttacked )
00176          vehicle->setAttacked( true, context );
00177 
00178 
00179       if ( next->getRealHeight() != pos->getRealHeight() && next->getRealHeight() >= 0 )
00180          (new ChangeUnitProperty( vehicle, ChangeUnitProperty::Height, 1 << next->getRealHeight() ))->execute( context );
00181 
00182       int pathStepNum = beeline ( *pos, *next ) / maxmalq;
00183       int pathStep = 0;
00184       if ( !pathStepNum )
00185          pathStepNum = 1;
00186 
00187       MapCoordinate3D to = *pos;
00188       do {
00189          MapCoordinate3D from;
00190          from.setnum ( to.x, to.y, pos->getRealHeight() );
00191          if ( next->x != from.x || next->y != from.y )
00192             to = getNeighbouringFieldCoordinate ( to, getdirection ( to, *next ));
00193          to.setnum ( to.x, to.y, next->getRealHeight() );
00194 
00195          MapField* dest = getMap()->getField ( to );
00196 
00197 
00198          if ( vehicle ) {
00199             vehicle->setnewposition(to, context );            
00200             (new UnitFieldRegistration( vehicle, to, UnitFieldRegistration::AddView ))->execute( context );
00201             if ( vehicle->typ->hasFunction( ContainerBaseType::DetectsMineralResources  ) )
00202                (new DiscoverResources(vehicle))->execute(context);
00203          }
00204 
00205          
00206          printTimer(1);
00207          
00208          {
00209             int dir = getdirection( from, to );
00210             if ( dir >= 0 && dir <= 5 ) 
00211                (new ChangeUnitProperty( vehicle, ChangeUnitProperty::Direction, dir ))->execute( context );
00212          }
00213          
00214          
00215          if ( context.display ) {
00216             // displaymap();
00217             if ( next == stop && to.x==next->x && to.y==next->y) // the unit will reach its destination
00218                slm.fadeOut ( CGameOptions::Instance()->movespeed * 10 );
00219             context.display->displayMovingUnit ( from, to, vehicle, pathStep, pathStepNum, MapDisplayInterface::SoundStartCallback( &slm, &SoundLoopManager::activate ), context.display->getUnitMovementDuration() );
00220             finalRedrawNecessary = true;
00221             mapDisplayUpToDate = false;
00222          }
00223          pathStep++;
00224 
00225          printTimer(4);
00226 
00227          if ( vehicle ) {
00228             if ( vehicle->spawnMoveObjects( from, to, context ) )
00229                mapDisplayUpToDate = false;
00230             
00231             
00232             if ( inhibitAttack )
00233                vehicle->setAttacked( true, context );
00234          }
00235 
00236          
00237          printTimer(5);
00238          {
00239             dest->secondvehicle = vehicle;
00240             int fieldsWidthChangedVisibility; 
00241             if ( context.viewingPlayer >= 0 ) 
00242                fieldsWidthChangedVisibility = evaluateviewcalculation ( getMap(), 1 << context.viewingPlayer, false, &context );
00243             else 
00244                fieldsWidthChangedVisibility = evaluateviewcalculation ( getMap(), 0, false, &context );
00245             
00246             
00247             if ( fieldsWidthChangedVisibility )
00248                mapDisplayUpToDate = false;
00249             
00250             dest->secondvehicle = NULL;
00251             printTimer(6);
00252          }
00253 
00254          viewInputChanged = false;
00255 
00256          if ( vehicle ) {
00257 
00258             if ( context.display && fieldvisiblenow ( dest, vehicle, context.viewingPlayer ) ) {
00259                // here comes an ugly hack to get the shadow of starting / descending aircraft right
00260 
00261                int oldheight = vehicle->height;
00262                if ( next->getRealHeight() > pos->getRealHeight() && pathStep < pathStepNum )
00263                   vehicle->height = 1 << pos->getRealHeight();
00264                
00265                if ( !mapDisplayUpToDate ) {
00266                   context.display->displayMap( vehicle );
00267                   mapDisplayUpToDate = true;
00268                   finalRedrawNecessary = false;
00269                }
00270 
00271                vehicle->height = oldheight;
00272             }
00273             
00274             dest->secondvehicle = vehicle;
00275             if ( rf->checkfield ( to, vehicle, context )) {
00276                cancelmovement = 1;
00277                vehicle = getMap()->getUnit ( networkID );
00278             }
00279 
00280             if ( vehicle && dest->mineattacks ( vehicle )) {
00281                tmineattacksunit battle ( to, -1, vehicle );
00282 
00283                if ( context.display && (fieldvisiblenow ( dest, context.viewingPlayer) || dest->mineowner() == context.viewingPlayer ))
00284                   context.display->showBattle( battle );
00285                else
00286                   battle.calc();
00287 
00288                battle.setresult ( context );
00289                if ( battle.dv.damage >= 100 ) {
00290                   vehicle = NULL;
00291                   viewInputChanged = true;
00292                }
00293                
00294                updateFieldInfo();
00295                cancelmovement = 1;
00296                mapDisplayUpToDate = false;
00297            }
00298            dest->secondvehicle = NULL;
00299 
00300 
00301 
00302             if ( !vehicle && context.display ) {
00303                context.display->displayMap();
00304                mapDisplayUpToDate = true;
00305                finalRedrawNecessary = false;
00306                
00307                viewInputChanged = true;
00308             }
00309          } else
00310             if ( context.display ) {
00311                context.display->displayMap();
00312                mapDisplayUpToDate = true;
00313                finalRedrawNecessary = false;
00314              }
00315 
00316          printTimer(7);
00317             
00318             
00319 
00320          if ( vehicle )
00321             if ( !(stop->x == to.x && stop->y == to.y && next == stop ))
00322                (new UnitFieldRegistration( vehicle, to, UnitFieldRegistration::RemoveView ))->execute( context );
00323 
00324          if ( cancelmovement == 1 )
00325             if ( dest->vehicle || dest->building )
00326                cancelmovement++;
00327 
00328          if ( vehicle )
00329             if ( dontInterrupt )
00330                cancelmovement = 0;
00331 
00332          if ( vehicle ) {
00333             dest->secondvehicle = vehicle;
00334             if ( dest->connection & cconnection_areaentered_anyunit )
00335                fieldCrossed( context );
00336 
00337             if ((dest->connection & cconnection_areaentered_specificunit ) && ( vehicle->connection & cconnection_areaentered_specificunit ))
00338                fieldCrossed( context );
00339             dest->secondvehicle = NULL;
00340          }
00341          printTimer(8);
00342       } while ( (to.x != next->x || to.y != next->y) && vehicle );
00343 
00344       pos = next;
00345    }
00346 
00347    MapField* fld = getMap()->getField ( pos->x, pos->y );
00348 
00349    if ( vehicle ) {
00350 
00351       int newMovement = orgMovement - pos->dist;
00352 
00353       vehicle->setnewposition( *pos, context );
00354 
00355       if ( vehicle->typ->movement[getFirstBit(orgHeight)] ) {
00356          if ( orgHeight != vehicle->height )  {
00357             // first we are converting the original movement to the new height
00358             int move = int(floor(vehicle->maxMovement() * float(orgMovement) / float(vehicle->typ->movement[getFirstBit(orgHeight)]) + 0.5));
00359             (new ChangeUnitMovement( vehicle, move, false, ChangeUnitMovement::NONE ))->execute(context);
00360          }
00361          
00362          
00363          int nm = int(floor(vehicle->maxMovement() * float(newMovement) / float(vehicle->typ->movement[getFirstBit(orgHeight)]) + 0.5));
00364          
00365          (new ChangeUnitMovement( vehicle, nm, false, ChangeUnitMovement::NORMAL))->execute(context);
00366          
00367          // the unit will be shaded if movement is exhausted
00368          if ( vehicle->getMovement() < 10 )
00369             finalRedrawNecessary = true;
00370       }
00371 
00372 
00373       (new ConsumeResource( vehicle, Resources(0,0,fueldist * vehicle->typ->fuelConsumption / maxmalq )))->execute( context );
00374 
00375       if ( fld->vehicle || fld->building ) {
00376          (new ChangeUnitMovement( vehicle, 0, false, ChangeUnitMovement::NONE))->execute(context);
00377          vehicle->setAttacked( false, context );
00378       }
00379 
00380       if ( vehicle ) {
00381          if ((fld->vehicle == NULL) && (fld->building == NULL)) {
00382             if ( !vehicle->isViewing() ) {
00383                (new UnitFieldRegistration( vehicle, *pos, UnitFieldRegistration::AddView ))->execute( context );
00384                viewInputChanged = true;
00385 
00386                // do we really need this check?
00387                /*
00388                if ( rf->checkfield ( *pos, vehicle, context )) {
00389                   vehicle = getMap()->getUnit ( networkID );
00390                }
00391                */
00392                
00393                (new UnitFieldRegistration( vehicle, *pos, UnitFieldRegistration::RegisterOnField ))->execute( context );
00394 
00395             } else {
00396                (new UnitFieldRegistration( vehicle, *pos, UnitFieldRegistration::RegisterOnField ))->execute( context );
00397                int orgVisibility = fld->visible;
00398                for ( int i = 0; i < getMap()->getPlayerCount(); ++i )
00399                   evaluatevisibilityfield ( getMap(), fld, i, -1, getMap()->getgameparameter ( cgp_initialMapVisibility ) );
00400                
00401                if ( fld->visible != orgVisibility ) {
00402                   ChangeView::ViewState viewState;
00403                   viewState[MapCoordinate(pos->x,pos->y)] = fld->visible;
00404                   fld->visible = orgVisibility;
00405                   (new ChangeView(getMap(),viewState))->execute(context);
00406                }
00407             }
00408 
00409          } else {
00410             ContainerBase* cn = fld->getContainer();
00411             if ( vehicle->isViewing() ) {
00412                (new UnitFieldRegistration( vehicle, *pos, UnitFieldRegistration::RemoveView ))->execute( context );
00413                viewInputChanged = true;
00414             }
00415             
00416             (new UnitFieldRegistration( vehicle, *pos, UnitFieldRegistration::RegisterOnField ))->execute( context );
00417             
00418             if (cn->getOwner() != vehicle->getOwner() && fld->building && getMap()->getPlayer(fld->building).diplomacy.isHostile( vehicle) ) {
00419                (new ConvertContainer( fld->building, vehicle->getOwner()))->execute(context);
00420                if ( fieldvisiblenow ( fld, context.viewingPlayer ) || context.viewingPlayer  == vehicle->getOwner() )
00421                   SoundList::getInstance().playSound ( SoundList::conquer_building, 0 );
00422                viewInputChanged = true;
00423            }
00424            mapDisplayUpToDate = false;
00425 
00426          }
00427 
00428       }
00429    }
00430 
00431    if ( rf->finalCheck( operatingPlayer, context ))
00432       finalRedrawNecessary = true;
00433    
00434    // we do it anyway 
00435    finalRedrawNecessary = true;
00436    
00437    if ( viewInputChanged ) {
00438       int fieldschanged;
00439       if ( context.viewingPlayer >= 0 )
00440          fieldschanged = evaluateviewcalculation ( getMap(), 1 << context.viewingPlayer, false, &context );
00441       else
00442          fieldschanged = evaluateviewcalculation ( getMap(), 0, false, &context );
00443       
00444       if ( fieldschanged )
00445          mapDisplayUpToDate = false;
00446          
00447    }
00448 
00449    if ( context.display ) {
00450       context.display->resetMovement();
00451       // if ( fieldschanged > 0 )
00452       if (finalRedrawNecessary || !mapDisplayUpToDate)
00453          context.display->displayMap();
00454       // else
00455       //   mapDisplay->displayPosition ( pos->x, pos->y );
00456    }
00457    
00458    return ActionResult(0);
00459 }
00460 
00461 
00462 ActionResult MoveUnit::undoAction( const Context& context )
00463 {
00464    if ( originalUnitMovement != -1 )
00465       getUnit()->setMovement( originalUnitMovement, 0 );
00466    
00467    return ActionResult(0);
00468 }
00469 
00470 ActionResult MoveUnit::preCheck()
00471 {
00472    return ActionResult(0);
00473 }
00474 
00475 ActionResult MoveUnit::postCheck()
00476 {
00477    return ActionResult(0);
00478 }
00479 
00480 
00481 
00482 namespace {
00483    const bool r1 = registerAction<MoveUnit> ( ActionRegistry::MoveUnit );
00484 }

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