00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 }
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
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