00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "jumpdrivecommand.h"
00023
00024 #include "../vehicle.h"
00025 #include "../mapfield.h"
00026 #include "../gamemap.h"
00027 #include "../viewcalculation.h"
00028 #include "../spfst.h"
00029 #include "changeunitmovement.h"
00030 #include "../mapdisplayinterface.h"
00031 #include "action-registry.h"
00032 #include "../reactionfire.h"
00033 #include "../soundList.h"
00034 #include "consumeresource.h"
00035 #include "servicecommand.h"
00036 #include "unitfieldregistration.h"
00037 #include "changeunitproperty.h"
00038
00039 ActionAvailability JumpDriveCommand :: available( const Vehicle* unit )
00040 {
00041 ActionAvailability avail;
00042 if ( !unit )
00043 return avail.set( ActionAvailability::notAtAll, "No unit selected");
00044
00045 if ( !unit->typ->jumpDrive.height )
00046 return avail.set( ActionAvailability::notAtAll, "Unit has no jump drive");
00047
00048 if ( unit->hasMoved() )
00049 avail.set( ActionAvailability::partially, "Unit has already moved" );
00050
00051 if ( unit->attacked )
00052 avail.set( ActionAvailability::partially, "Unit has already attacked" );
00053
00054 if ( (unit->reactionfire.getStatus() != Vehicle::ReactionFire::off) && !unit->typ->hasFunction(VehicleType::MoveWithReactionFire ) )
00055 avail.set( ActionAvailability::partially, "Unit has reaction fire enabled" );
00056
00057 if ( !(unit->height & unit->typ->jumpDrive.height) )
00058 avail.set( ActionAvailability::partially, "Unit needs to be on this height: " + heightToString(unit->typ->jumpDrive.height) );
00059
00060 if ( unit->getResource( unit->typ->jumpDrive.consumption ) < unit->typ->jumpDrive.consumption )
00061 avail.set( ActionAvailability::partially, "Unit is missing resources. Required: " + unit->typ->jumpDrive.consumption.toString() );
00062
00063 return avail;
00064 }
00065
00066 JumpDriveCommand :: JumpDriveCommand ( Vehicle* unit)
00067 : UnitCommand ( unit )
00068 {
00069
00070 }
00071
00072
00073 bool JumpDriveCommand::fieldReachable( const MapCoordinate& dest )
00074 {
00075 MapField* fld = getMap()->getField( dest );
00076 if ( beeline( dest, getUnit()->getPosition()) <= getUnit()->typ->jumpDrive.maxDistance )
00077 if ( !fld->vehicle && !fld->building )
00078 if ( fieldvisiblenow( fld, getUnit()->getOwner() ))
00079 if ( getUnit()->typ->jumpDrive.targetterrain.accessible( fld->bdt ) > 0 )
00080 return true;
00081
00082 return false;
00083 }
00084
00085
00086 vector<MapCoordinate> JumpDriveCommand::getDestinations()
00087 {
00088 vector<MapCoordinate> fields;
00089
00090 if ( !available( getUnit() ).ready() )
00091 return fields;
00092
00093 GameMap* gamemap = getMap();
00094
00095 for ( int y = 0; y < gamemap->ysize; ++y )
00096 for (int x = 0; x < gamemap->xsize; ++x ) {
00097 MapCoordinate dest (x,y);
00098 if ( fieldReachable( dest))
00099 fields.push_back( dest );
00100
00101 }
00102 return fields;
00103 }
00104
00105 void JumpDriveCommand::setDestination( const MapCoordinate& position )
00106 {
00107 if ( fieldReachable( position )) {
00108 destination = position;
00109 setState( SetUp );
00110 }
00111 }
00112
00113
00114 ActionResult JumpDriveCommand::go ( const Context& context )
00115 {
00116 if ( getState() != SetUp )
00117 return ActionResult(22000);
00118
00119 Vehicle* unit = getUnit();
00120
00121 if ( !available( unit ).ready() )
00122 return ActionResult( 22600 );
00123
00124 if ( !fieldReachable( destination ))
00125 return ActionResult( 22601 );
00126
00127
00128 auto_ptr<ConsumeResource> cr ( new ConsumeResource( unit, unit->typ->jumpDrive.consumption ));
00129 ActionResult res = cr->execute( context );
00130 if ( !res.successful() )
00131 return res;
00132 else
00133 cr.release();
00134
00135 auto_ptr<UnitFieldRegistration> ufr1 ( new UnitFieldRegistration( unit, unit->getPosition(), UnitFieldRegistration::RemoveView ));
00136 res = ufr1->execute( context );
00137 if ( !res.successful() )
00138 return res;
00139 else
00140 ufr1.release();
00141
00142 auto_ptr<UnitFieldRegistration> ufr2 ( new UnitFieldRegistration( unit, unit->getPosition(), UnitFieldRegistration::UnregisterOnField ));
00143 res = ufr2->execute( context );
00144 if ( !res.successful() )
00145 return res;
00146 else
00147 ufr2.release();
00148
00149
00150 MapCoordinate3D dest3D (destination, unit->height );
00151
00152 tsearchreactionfireingunits srfu( getMap() );
00153 srfu.init( unit , dest3D );
00154
00155
00156 auto_ptr<UnitFieldRegistration> ufr3( new UnitFieldRegistration( unit, dest3D, UnitFieldRegistration::Position3D ));
00157 res = ufr3->execute( context );
00158 if ( !res.successful() )
00159 return res;
00160 else
00161 ufr3.release();
00162
00163 auto_ptr<UnitFieldRegistration> ufr4 ( new UnitFieldRegistration( unit, dest3D, UnitFieldRegistration::RegisterOnField ));
00164 res = ufr4->execute( context );
00165 if ( !res.successful() )
00166 return res;
00167 else
00168 ufr4.release();
00169
00170
00171 if ( context.display )
00172 context.display->playPositionalSound( dest3D, SoundList::getInstance().getSound( SoundList::jumpdrive ));
00173
00174 auto_ptr<ChangeUnitMovement> cum ( new ChangeUnitMovement( unit, 0, false, ChangeUnitMovement::ALLFULL ));
00175 res = cum->execute( context );
00176 if ( !res.successful() )
00177 return res;
00178 else
00179 cum.release();
00180
00181 auto_ptr<ChangeUnitProperty> cup ( new ChangeUnitProperty( unit, ChangeUnitProperty::AttackedFlag, 1 ));
00182 res = cup->execute( context );
00183 if ( !res.successful() )
00184 return res;
00185 else
00186 cup.release();
00187
00188
00189 auto_ptr<UnitFieldRegistration> ufr5( new UnitFieldRegistration( unit, dest3D, UnitFieldRegistration::AddView ));
00190 res = ufr5->execute( context );
00191 if ( !res.successful() )
00192 return res;
00193 else
00194 ufr5.release();
00195
00196 computeview( getMap(), 0, false, &context );
00197
00198
00199 int unitOwner = unit->getOwner();
00200 srfu.checkfield( dest3D, unit, context );
00201 srfu.finalCheck( unitOwner, context );
00202
00203
00204 if ( context.display )
00205 context.display->repaintDisplay();
00206
00207 if ( res.successful() )
00208 setState( Finished );
00209 else
00210 setState( Failed );
00211
00212 return res;
00213 }
00214
00215
00216
00217 static const int JumpDriveCommandVersion = 1;
00218
00219 void JumpDriveCommand :: readData ( tnstream& stream )
00220 {
00221 UnitCommand::readData( stream );
00222 int version = stream.readInt();
00223 if ( version > JumpDriveCommandVersion )
00224 throw tinvalidversion ( "JumpDriveCommand", JumpDriveCommandVersion, version );
00225 destination.read( stream );
00226 }
00227
00228 void JumpDriveCommand :: writeData ( tnstream& stream ) const
00229 {
00230 UnitCommand::writeData( stream );
00231 stream.writeInt( JumpDriveCommandVersion );
00232 destination.write( stream );
00233 }
00234
00235
00236 ASCString JumpDriveCommand :: getCommandString() const
00237 {
00238 ASCString c;
00239 c.format("unitJump ( map, %d, asc.MapCoordinate( %d, %d ) )", getUnitID(), destination.x, destination.y );
00240 return c;
00241
00242 }
00243
00244 GameActionID JumpDriveCommand::getID() const
00245 {
00246 return ActionRegistry::JumpDriveCommand;
00247 }
00248
00249 ASCString JumpDriveCommand::getDescription() const
00250 {
00251 ASCString s = "Jump ";
00252
00253 if ( getUnit())
00254 s += getUnit()->getName();
00255
00256 s += " to " + destination.toString();
00257 return s;
00258 }
00259
00260 namespace
00261 {
00262 const bool r1 = registerAction<JumpDriveCommand> ( ActionRegistry::JumpDriveCommand );
00263 }
00264