Advanced Strategic Command
constructunitcommand.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Advanced Strategic Command; http://www.asc-hq.de
3  Copyright (C) 1994-2010 Martin Bickel and Marc Schellenberger
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; see the file COPYING. If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  Boston, MA 02111-1307 USA
19 */
20 
21 
22 #include "constructunitcommand.h"
23 
24 #include "../vehicle.h"
25 #include "../mapfield.h"
26 #include "../gamemap.h"
27 #include "../viewcalculation.h"
28 #include "../spfst.h"
29 #include "../mapdisplayinterface.h"
30 #include "action-registry.h"
31 #include "../itemrepository.h"
32 #include "../containercontrols.h"
33 #include "consumeresource.h"
34 #include "spawnunit.h"
35 #include "changeunitmovement.h"
36 #include "consumeammo.h"
37 #include "changeunitproperty.h"
38 #include "viewregistration.h"
39 
40 
42 {
43  const Vehicle* vehicle = dynamic_cast<const Vehicle*>(eht);
44  if ( !eht )
45  return false;
46 
47  MapField* fld = vehicle->getMap()->getField ( vehicle->getPosition() );
48  if ( fld && fld->vehicle == vehicle )
49  if (vehicle->getOwner() == vehicle->getMap()->actplayer )
50  if ( vehicle->typ->vehiclesBuildable.size() )
51  if ( !vehicle->attacked )
52  return true;
53  return false;
54 }
55 
57 {
58  if ( eht->getOwner() == eht->getMap()->actplayer )
59  if ( eht->vehiclesLoaded() < eht->baseType->maxLoadableUnits )
61 
62  return false;
63 }
64 
66 {
68 }
69 
70 
71 ConstructUnitCommand :: ConstructUnitCommand ( ContainerBase* container )
72  : ContainerCommand ( container ), mode( undefined ), vehicleTypeID(-1), newUnitID(-1)
73 {
74 
75 }
76 
77 
78 
80 {
81  int l = 0;
82 
83  if ( mode == internal ) {
84  Resources cost = getContainer()->getProductionCost( type );
85  for ( int r = 0; r < resourceTypeNum; r++ )
86  if ( getContainer()->getAvailableResource( cost.resource(r), r ) < cost.resource(r) )
87  l |= 1 << r;
88 
90  l |= Lack::Research;
91 
94  } else
95  if ( mode == external ) {
96 
98  l |= Lack::Research;
99 
100  const Vehicle* veh = dynamic_cast<const Vehicle*>(getContainer());
101  if ( veh->getMovement() < veh->maxMovement() * veh->typ->unitConstructionMoveCostPercentage / 100 )
102  l |= Lack::Movement;
103 
104  Resources cost = veh->getExternalVehicleConstructionCost( type );
105  for ( int r = 0; r < resourceTypeNum; r++ )
106  if ( getContainer()->getAvailableResource( cost.resource(r), r ) < cost.resource(r) )
107  l |= 1 << r;
108 
109  }
110 
111  return Lack(l);
112 }
113 
115 {
116  Producables entries;
117  if ( mode == internal ) {
119  for ( ContainerBase::Production::const_iterator i = prod.begin(); i != prod.end(); ++i )
120  entries.push_back ( ProductionEntry ( *i, getContainer()->getProductionCost( *i ), unitProductionPrerequisites( *i ) ));
121  } else
122  if ( mode == external ) {
123  Vehicle* veh = dynamic_cast<Vehicle*>(getContainer());
124  if ( veh ) {
126  for ( int i = 0; i < veh->typ->vehiclesBuildable.size(); i++ )
127  for ( int j = veh->typ->vehiclesBuildable[i].from; j <= veh->typ->vehiclesBuildable[i].to; j++ )
129  VehicleType* v = veh->getMap()->getvehicletype_byid ( j );
130  if ( v )
131  entries.push_back ( ProductionEntry ( v, veh->getExternalVehicleConstructionCost( v ), unitProductionPrerequisites( v ) ));
132  }
133  }
134  }
135  return entries;
136 }
137 
138 void ConstructUnitCommand :: fieldChecker( const MapCoordinate& pos )
139 {
140  MapField* fld = getMap()->getField(pos);
141  if ( !fld )
142  return;
143 
144  if ( fld->vehicle || fld->building )
145  return;
146 
147  VehicleType* vt = getContainer()->getMap()->getvehicletype_byid( vehicleTypeID );
148 
149  if ( fieldvisiblenow( getMap()->getField(pos)) && vt ) {
150  Vehicle* veh = dynamic_cast<Vehicle*>(getContainer() );
151  if ( veh && veh->vehicleconstructable( vt, pos.x, pos.y ))
152  unitsConstructable[pos].push_back(vehicleTypeID);
153  }
154 }
155 
156 
157 vector<MapCoordinate> ConstructUnitCommand::getFields()
158 {
159  vector<MapCoordinate> fields;
160  Vehicle* veh = dynamic_cast<Vehicle*>(getContainer() );
161  if ( vehicleTypeID > 0 && veh ) {
162  circularFieldIterator( veh->getMap(), veh->getPosition(), veh->typ->unitConstructionMaxDistance, veh->typ->unitConstructionMinDistance, FieldIterationFunctor( this, &ConstructUnitCommand::fieldChecker ) );
163  for ( map<MapCoordinate,vector<int> >::const_iterator i = unitsConstructable.begin(); i != unitsConstructable.end(); ++i )
164  fields.push_back ( i->first );
165  }
166 
167  return fields;
168 }
169 
171 {
172  vector<MapCoordinate> fields = getFields();
173  return find( fields.begin(), fields.end(), pos ) != fields.end() ;
174 }
175 
176 
178 {
179  this->target = pos;
180  MapField* fld = getMap()->getField(target);
181 
182  if( !fld )
183  throw ActionResult(21002);
184 
185  if ( mode != undefined && vehicleTypeID > 0 )
186  setState( SetUp );
187 
188 }
189 
190 
191 
193 {
194  if ( getState() != SetUp )
195  return ActionResult(22000);
196 
197 
199 
200  const VehicleType* vehicleType = NULL;
201  Resources cost;
202  for ( Producables::const_iterator i = prods.begin(); i != prods.end(); ++i ) {
203  if ( i->type->id == vehicleTypeID ) {
204  if ( i->prerequisites.ok() ) {
205  vehicleType = i->type;
206  cost = i->cost;
207  } else
208  return ActionResult( 21702 );
209  }
210  }
211  if ( !vehicleType )
212  return ActionResult( 21701 );
213 
214 
215  if ( mode == external && !isFieldUsable( target ))
216  return ActionResult( 21703 );
217 
218 
219  int height;
220  for ( int j = 0; j < 8; j++ ) {
221  int a = int( getContainer()->getHeight() ) << j;
222  int b = int( getContainer()->getHeight() ) >> j;
223  if ( vehicleType->height & a ) {
224  height = a;
225  break;
226  }
227  if ( vehicleType->height & b ) {
228  height = b;
229  break;
230  }
231  }
232  MapCoordinate3D position ( target, height );
233 
234  if ( mode == external ) {
235 
236  SpawnUnit* spawnUnit = new SpawnUnit(getMap(), position, vehicleTypeID, getContainer()->getOwner() );
237  ActionResult res = spawnUnit->execute( context );
238  if ( !res.successful() )
239  return res;
240 
241  spawnUnit->getUnit()->attacked = true;
242 
243  newUnitID = spawnUnit->getUnit()->networkid;
244 
245 
246  if ( !res.successful() )
247  return res;
248 
249  Vehicle* veh = dynamic_cast<Vehicle*>(getContainer() );
250  if ( veh ) {
251  res = (new ChangeUnitMovement( veh, veh->maxMovement() * veh->typ->unitConstructionMoveCostPercentage/100, true ))->execute( context );
252  if ( !res.successful() )
253  return res;
254  }
255  } else {
256  SpawnUnit* spawnUnit = new SpawnUnit(getMap(), getContainer(), vehicleTypeID );
257  ActionResult res = spawnUnit->execute( context );
258  if ( !res.successful() )
259  return res;
260 
261  spawnUnit->getUnit()->attacked = true;
262 
263  newUnitID = spawnUnit->getUnit()->networkid;
264 
265  if ( getMap()->getgameparameter(cgp_bi3_training) >= 1 ) {
266  int cnt = 0;
267 
268  for ( Player::BuildingList::iterator bi = getMap()->player[getMap()->actplayer].buildingList.begin(); bi != getMap()->player[getMap()->actplayer].buildingList.end(); bi++ )
269  if ( (*bi)->typ->hasFunction( ContainerBaseType::TrainingCenter ) )
270  cnt++;
271 
272  Vehicle* vehicle = spawnUnit->getUnit();
273  int expOff = vehicle->getExperience_offensive() + cnt * getMap()->getgameparameter(cgp_bi3_training);
274  if ( expOff > maxunitexperience )
275  expOff = maxunitexperience;
276  vehicle->setExperience_offensive( expOff );
277 
278  int expDef = vehicle->getExperience_defensive() + cnt * getMap()->getgameparameter(cgp_bi3_training);
279  if ( expDef > maxunitexperience )
280  expDef = maxunitexperience;
281  vehicle->setExperience_offensive( expDef );
282 
283  }
284  }
285 
286  ActionResult res = (new ConsumeResource(getContainer(), cost ))->execute( context );
287 
288  if ( !res.successful() )
289  return res;
290 
291  Vehicle* veh = dynamic_cast<Vehicle*>(getContainer());
292  if ( veh )
293  res = (new ChangeUnitProperty( veh, ChangeUnitProperty::AttackedFlag, 1 ))->execute(context);
294 
295  if ( context.display )
296  context.display->repaintDisplay();
297 
298  if ( res.successful() )
299  setState( Finished );
300  else
301  setState( Failed );
302 
303  return res;
304 }
305 
307 {
308  if ( newUnitID > 0 )
309  return getMap()->getUnit( newUnitID );
310  else
311  return NULL;
312 }
313 
315 {
316  this->mode = mode;
317  if ( mode == internal )
318  target = getContainer()->getPosition();
319 };
320 
321 
322 static const int ConstructUnitCommandVersion = 1;
323 
325 {
326  ContainerCommand::readData( stream );
327  int version = stream.readInt();
328  if ( version > ConstructUnitCommandVersion )
329  throw tinvalidversion ( "ConstructUnitCommand", ConstructUnitCommandVersion, version );
330  target.read( stream );
331  vehicleTypeID = stream.readInt();
332  mode = (Mode) stream.readInt();
333  newUnitID = stream.readInt();
334 }
335 
337 {
338  ContainerCommand::writeData( stream );
339  stream.writeInt( ConstructUnitCommandVersion );
340  target.write( stream );
341  stream.writeInt( vehicleTypeID );
342  stream.writeInt( mode );
343  stream.writeInt( newUnitID );
344 }
345 
347 {
348  vehicleTypeID = type->id;
349 
350  VehicleType* vt = getMap()->getvehicletype_byid( vehicleTypeID );
351  if( !vt )
352  throw ActionResult(21701);
353 
354  if ( mode != undefined && target.valid())
355  setState( SetUp );
356 
357 }
358 
359 
361 {
362  ASCString c;
363  c.format("constructUnit ( map, %d, asc.MapCoordinate( %d, %d), %d )", getContainerID(), target.x, target.y, vehicleTypeID );
364  return c;
365 }
366 
368 {
370 }
371 
373 {
374  ASCString s = "Construct ";
375 
376  const VehicleType* vt = getMap()->getvehicletype_byid( vehicleTypeID );
377  if ( vt )
378  s += vt->name;
379  else
380  s += "unit";
381 
382  if ( getContainer() ) {
383  s += " by " + getContainer()->getName();
384  }
385  s += " at " + target.toString();
386  return s;
387 }
388 
389 namespace
390 {
391  const bool r1 = registerAction<ConstructUnitCommand> ( ActionRegistry::ConstructUnitCommand );
392 }
393 
Lack unitProductionPrerequisites(const VehicleType *type) const
void writeData(tnstream &stream) const
int getExperience_defensive() const
Definition: vehicle.cpp:258
int maxLoadableUnits
the maximum number of units that can be loaded
virtual void writeInt(int i)
Writes a 32 bit signed Integer. In the stream little-endian byte order is used and a translation is p...
Definition: basestrm.cpp:363
vector< IntRange > vehiclesBuildable
the ids of units this unit can construct
Definition: vehicletype.h:230
int maxMovement() const
the maximum distance that the unit can drive in a single turn on the current level of height ...
Definition: vehicle.cpp:1069
int GameActionID
Definition: action.h:35
void setVehicleType(const VehicleType *type)
the command is totally done
Definition: command.h:120
ASCString getDescription() const
Vehicle * vehicle
Definition: mapfield.h:89
bool isFieldUsable(const MapCoordinate &pos)
bool valid() const
Definition: typen.h:221
class GameMap::UnitProduction unitProduction
virtual ASCString getName() const =0
TechAdapterDependency techDependency
virtual int readInt(void)
Reads a 32 bit signed Integer. In the stream little-endian byte order is used and a translation is pe...
Definition: basestrm.cpp:284
bool hasFunction(ContainerFunctions function) const
int getOwner() const
returns the number of the player this vehicle/building belongs to
GameActionID getID() const
State getState() const
Definition: command.h:125
void read(tnstream &stream)
Definition: typen.h:213
MapCoordinate3D getPosition() const
returns the units position
Definition: vehicle.cpp:1552
GameMap * getMap()
Definition: action.h:92
ASCString toString(bool coordinates=false) const
Definition: typen.cpp:304
The interface for all kinds of IO stream.
a single field of the map
Definition: mapfield.h:26
ASCString & format(const charT *pFormat,...)
Definition: ascstring.cpp:78
void readData(tnstream &stream)
The ASCString class provides an abstract way to manipulate strings.
Definition: ascstring.h:14
const Production & getProduction() const
int getContainerID() const
Producables getProduceableVehicles()
bool fieldvisiblenow(const MapField *pe, Vehicle *veh, int player)
{@
Definition: spfst.cpp:399
The class describing properties that are common to all vehicles of a certain kind.
Definition: vehicletype.h:177
int unitConstructionMinDistance
the minimal distance (measured in number of fields) in which units can be externally constructed ...
Definition: vehicletype.h:257
Vehicle * getUnit()
Definition: spawnunit.cpp:154
static const int ConstructUnitCommandVersion
int vehicleUnloadable(const VehicleType *vehicleType, int carrierHeight=-1) const
checks the unloading of a unit type
static bool internalConstructionAvail(const ContainerBase *eht)
ActionResult execute(const Context &context)
Definition: action.cpp:41
const int resourceTypeNum
The number of different resources that ASC uses.
Definition: typen.h:77
void setTargetPosition(const MapCoordinate &pos)
void write(tnstream &stream) const
Definition: typen.h:212
void setExperience_offensive(int experience)
Definition: vehicle.cpp:274
Resources getProductionCost(const VehicleType *unit) const
int unitConstructionMaxDistance
the maximum distance (measured in number of fields) in which units can be externally constructed ...
Definition: vehicletype.h:259
Coordinate on the twodimensional map.
Definition: typen.h:202
void circularFieldIterator(GameMap *gamemap, const MapCoordinate &center, int startDist, int stopDist, FieldIterationFunctor functor)
vector< MapCoordinate > getFields()
int unitConstructionMoveCostPercentage
if this unit constructs another unit externally (for example a turret), it costs this much of its mov...
Definition: vehicletype.h:254
bool vehicleconstructable(const VehicleType *tnk, int x, int y)
checks whether the unit can construct a vehicle of the given type at the given position.
Definition: vehicle.cpp:875
void setState(State state)
Definition: command.cpp:44
signed char actplayer
the player who is currently making his moves (may be human or AI)
Definition: gamemap.h:232
VehicleType * getvehicletype_byid(int id)
Definition: gamemap.cpp:1794
bool successful() const
ASCString getCommandString() const
Vehicle * getUnit(int x, int y, int nwid)
Definition: gamemap.cpp:1215
MapDisplayInterface * display
Definition: context.h:39
Player player[9]
Definition: gamemap.h:253
void writeData(tnstream &stream) const
int vehiclesLoaded(void) const
returns the number of loaded units
int getgameparameter(GameParameter num) const
Definition: gamemap.cpp:1047
int height
the levels of height which this unit can enter
BuildingList buildingList
a list of all units
Definition: player.h:139
const int maxunitexperience
The maximum experience value of a Vehicle.
Definition: typen.h:73
static bool externalConstructionAvail(const ContainerBase *eht)
int & resource(int type)
Definition: typen.h:105
Resources getExternalVehicleConstructionCost(const VehicleType *tnk) const
Definition: vehicle.cpp:900
ContainerBase * getContainer(bool dontThrow=false)
vector< const VehicleType * > Production
Definition: containerbase.h:87
const VehicleType * typ
Definition: vehicle.h:83
bool attacked
did the unit already attack this turn
Definition: vehicle.h:109
Coordinate on the map including height.
Definition: typen.h:238
Building * building
Definition: mapfield.h:102
const ContainerBaseType * baseType
the type descriping all non-instance specific properties of the container
Definition: containerbase.h:80
GameMap * getMap() const
void readData(tnstream &stream)
The parent class of Vehicle and Building; The name Container originates from Battle Isle...
Definition: containerbase.h:40
Resources are basically the currency of ASC.
Definition: typen.h:97
bool available(const Research &research) const
Definition: research.cpp:412
static bool avail(const ContainerBase *eht)
ActionResult go(const Context &context)
int networkid
a unique identification of the unit that is used everywhere in ASC (and not only the network protocol...
Definition: vehicle.h:140
virtual void repaintDisplay()=0
int getMovement(bool checkFuel=true, bool checkRF=true) const
returns the movement points the unit has left for this turn. CheckFuel should almost always be true...
Definition: vehicle.cpp:558
ASCString name
a short name, for example B-52
Loki::Functor< void, LOKI_TYPELIST_1(const MapCoordinate &) > FieldIterationFunctor
Definition: mapalgorithms.h:43
vector< ConstructUnitCommand::ProductionEntry > Producables
MapField * getField(int x, int y)
Definition: gamemap.h:465
virtual MapCoordinate3D getPosition() const =0
int getExperience_offensive() const
Definition: vehicle.cpp:253