attackcommand.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 
00022 #include "attackcommand.h"
00023 
00024 #include "../vehicle.h"
00025 #include "../mapfield.h"
00026 #include "../gamemap.h"
00027 #include "../viewcalculation.h"
00028 #include "../spfst.h"
00029 #include "../mapdisplayinterface.h"
00030 #include "vehicleattack.h"
00031 #include "action-registry.h"
00032 
00033 
00034 bool AttackCommand :: avail ( Vehicle* eht )
00035 {
00036    if ( eht )
00037       if ( eht->attacked == false )
00038          if ( eht->weapexist() )
00039             if (eht->typ->wait == false  ||  !eht->hasMoved() )
00040                   return true;
00041    return false;
00042 }
00043 
00044 
00045 AttackCommand :: AttackCommand ( Vehicle* unit )
00046    : UnitCommand ( unit ), targetUnitID(-1), weapon(-1), kamikaze(false)
00047 {
00048    
00049 }
00050 
00051 ActionResult AttackCommand::searchTargets()
00052 {
00053    if ( !getUnit() ) 
00054       return ActionResult(201);
00055 
00056    Vehicle* unit = getUnit();
00057    
00058    int weaponCount = 0;
00059    int shootableWeaponCount = 0;
00060    for ( int w = 0; w < getUnit()->typ->weapons.count; w++ )
00061       if ( unit->typ->weapons.weapon[w].shootable() ) {
00062             weaponCount++;
00063             if ( unit->typ->weapons.weapon[w].sourceheight & unit->height )
00064                shootableWeaponCount++;
00065       }
00066 
00067    if ( weaponCount == 0 )
00068       return ActionResult(214);
00069 
00070    if ( shootableWeaponCount == 0 )
00071       return ActionResult(213);
00072    
00073    
00074    
00075    if (fieldvisiblenow( getMap()->getField( unit->getPosition() ), getMap()->actplayer ) == false)
00076       return ActionResult(1);
00077 
00078    if (unit->attacked)
00079       return ActionResult(202);
00080    
00081 
00082    if ( unit->typ->weapons.count == 0)
00083       return ActionResult(204);
00084 
00085    if ( unit->typ->wait && getUnit()->hasMoved() && unit->reactionfire.getStatus() != Vehicle::ReactionFire::ready )
00086       return ActionResult(215);
00087 
00088 
00089    attackableUnits.clear();
00090    attackableUnitsKamikaze.clear();
00091    attackableBuildings.clear();
00092    attackableObjects.clear();
00093    
00094    
00095    int d = 0;
00096    int maxdist = 0;
00097    int mindist = 20000;
00098    for ( int a = 0; a < unit->typ->weapons.count; a++)
00099       if ( unit->ammo[a] > 0) {
00100          d++;
00101          maxdist = max( maxdist, unit->typ->weapons.weapon[a].maxdistance / maxmalq );
00102          mindist = min ( mindist, (unit->typ->weapons.weapon[a].mindistance + maxmalq - 1) / maxmalq);
00103       }
00104 
00105 
00106    if (d == 0)
00107       return ActionResult(204);
00108 
00109    circularFieldIterator( getMap(), unit->getPosition(), maxdist, mindist, FieldIterationFunctor( this, &AttackCommand::fieldChecker ));
00110          
00111    if ( attackableUnits.size() + attackableBuildings.size() + attackableObjects.size() + attackableUnitsKamikaze.size() ) {
00112       setState(Evaluated);
00113       return ActionResult(0);
00114    } else
00115       return ActionResult(206);
00116 }
00117 
00118 void AttackCommand :: fieldChecker( const MapCoordinate& pos )
00119 {
00120    if ( fieldvisiblenow( getMap()->getField(pos)) ) {
00121       if ( !kamikaze ) {
00122          AttackWeap* atw = attackpossible( getUnit(), pos.x, pos.y );
00123          if (atw->count > 0) { 
00124             switch ( atw->target ) {
00125                case AttackWeap::vehicle:  attackableUnits[pos] = *atw ;
00126                   break;                                    
00127                case AttackWeap::building: attackableBuildings[pos] = *atw;
00128                   break;
00129                case AttackWeap::object:   attackableObjects[pos] = *atw;
00130                   break;
00131                default:;
00132             } /* endswitch */
00133          } 
00134          delete atw;
00135       } else {
00136           MapField* fld = getMap()->getField(pos);
00137           if (fieldvisiblenow( fld )) {
00138              Vehicle* eht = fld->vehicle;
00139              if (eht != NULL) 
00140                 if (((getUnit()->height >= chtieffliegend) && (eht->height <= getUnit()->height) && (eht->height >= chschwimmend)) 
00141                   || ((getUnit()->height == chfahrend) && (eht->height == chfahrend)) 
00142                   || ((getUnit()->height == chschwimmend) && (eht->height == chschwimmend))
00143                   || ((getUnit()->height == chgetaucht) && (eht->height >=  chgetaucht) && (eht->height <= chschwimmend))) {
00144                   attackableUnitsKamikaze.push_back ( pos );   
00145                 } 
00146           } 
00147       }
00148    } 
00149 }
00150 
00151 
00152 void AttackCommand :: setTarget( const MapCoordinate& target, int weapon )
00153 {
00154    
00155  //  if ( getState() == Evaluated ) {
00156       this->weapon = weapon;
00157       this->target  = target;
00158       MapField* fld = getMap()->getField( target );
00159       if ( fld->vehicle )
00160          targetUnitID = fld->vehicle->networkid;
00161       else
00162          targetBuilding = target;
00163       
00164       setState( SetUp );
00165  //  }
00166 }
00167 
00168 ActionResult AttackCommand::go ( const Context& context )
00169 {
00170    MapCoordinate targetPosition;
00171    
00172    if ( getState() != SetUp )
00173       return ActionResult(22000);
00174    
00175    searchTargets();
00176    
00177    AttackWeap* atw = NULL;
00178    
00179    if ( targetUnitID > 0 ) {
00180       Vehicle* veh = getMap()->getUnit( targetUnitID );
00181       if ( !veh )
00182          return ActionResult(21001);
00183       
00184       targetPosition = veh->getPosition();
00185       if ( attackableUnits.find(targetPosition) == attackableUnits.end() )
00186          return ActionResult(208);
00187       
00188       atw = &attackableUnits[targetPosition];
00189    } else
00190       if ( targetBuilding.valid() && getMap()->getField(targetBuilding)->building ) {
00191          if ( attackableBuildings.find(targetBuilding) == attackableBuildings.end() )
00192             return ActionResult(217);
00193          atw = &attackableBuildings[targetBuilding];
00194          targetPosition = targetBuilding;
00195       } else {
00196          if ( attackableObjects.find(targetBuilding) == attackableObjects.end() )
00197             return ActionResult(217);
00198          atw = &attackableObjects[target];
00199          targetPosition = target;
00200       }
00201    
00202 
00203    if ( !atw ) 
00204       return ActionResult(217);
00205    
00206    ActionResult res = (new VehicleAttackAction(getMap(), getUnitID(), targetPosition, weapon ))->execute( context );
00207    if ( res.successful() )
00208       setState( Finished );
00209    else
00210       setState( Failed );
00211    return res;
00212     
00213 }
00214 
00215 static const int attackCommandVersion = 2;
00216 
00217 void AttackCommand :: readData ( tnstream& stream )
00218 {
00219    UnitCommand::readData( stream );
00220    int version = stream.readInt();
00221    if ( version > attackCommandVersion )
00222       throw tinvalidversion ( "AttackCommand", attackCommandVersion, version );
00223    target.read( stream );
00224    targetUnitID = stream.readInt();
00225    targetBuilding.read( stream );
00226    weapon = stream.readInt();
00227    if ( version >= 2 )
00228       kamikaze = stream.readInt();
00229    else
00230       kamikaze = false;
00231 }
00232 
00233 void AttackCommand :: writeData ( tnstream& stream ) const
00234 {
00235    UnitCommand::writeData( stream );
00236    stream.writeInt( attackCommandVersion );
00237    target.write( stream );
00238    stream.writeInt( targetUnitID );
00239    targetBuilding.write( stream );
00240    stream.writeInt( weapon );
00241    stream.writeInt( kamikaze );   
00242 }
00243 
00244 ASCString AttackCommand :: getCommandString() const {
00245    ASCString c;
00246    c.format("unitAttack ( map, %d, asc.MapCoordinate(%d, %d), %d )", getUnitID(), target.x, target.y, weapon );
00247    return c;
00248    
00249 }
00250 
00251 GameActionID AttackCommand::getID() const 
00252 {
00253    return ActionRegistry::AttackCommand;   
00254 }
00255 
00256 ASCString AttackCommand::getDescription() const
00257 {
00258    ASCString s = "Attacking "; 
00259    s += " " + target.toString();
00260    if ( getUnit() ) {
00261       s += " with " + getUnit()->getName();
00262    }
00263    return s;
00264 }
00265 
00266 namespace {
00267    const bool r1 = registerAction<AttackCommand> ( ActionRegistry::AttackCommand );
00268 }
00269 

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