Advanced Strategic Command
service.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  service.cpp - description
3  -------------------
4  begin : Fri Mar 30 2001
5  copyright : (C) 2001 by Martin Bickel
6  email : bickel@asc-hq.org
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "ai_common.h"
19 
20 #include "../actions/repairunitcommand.h"
21 #include "../actions/servicing.h"
22 #include "../actions/servicecommand.h"
23 
24 
25 AI :: ServiceOrder :: ServiceOrder ( AI* _ai, AI::ServiceOrder::Service _requiredService, int UnitID, int _pos )
26 {
27  active = false;
28  failure = 0;
29  ai = _ai;
30  targetUnitID = UnitID;
31  requiredService = _requiredService;
32  serviceUnitID = 0;
33  position = _pos;
34  time = ai->getMap()->time;
35 
36  nextServiceBuildingDistance = -1;
37  nextServiceBuilding = NULL;
38  if ( ai->getMap()->getUnit ( UnitID )->canMove()) {
39  MapCoordinate3D sb = ai->findServiceBuilding ( *this, &nextServiceBuildingDistance );
40  if ( sb.valid() )
41  nextServiceBuilding = ai->getMap()->getField( sb )->building;
42  }
43 }
44 
45 AI :: ServiceOrder :: ServiceOrder ( AI* _ai, tnstream& stream )
46 {
47  active = false;
48  failure = 0;
49  ai = _ai;
50  read ( stream );
51 }
52 
53 void AI :: ServiceOrder :: activate( ServiceOrder& so )
54 {
55  so.active = true;
56 }
57 
58 
59 const int currentServiceOrderVersion = 10002;
60 
61 void AI :: ServiceOrder :: read ( tnstream& stream )
62 {
63  int version = stream.readInt( );
64  if ( version > currentServiceOrderVersion )
65  throw tinvalidversion ( "AI :: ServiceOrder", currentServiceOrderVersion, version );
66  targetUnitID = stream.readInt ( );
67  serviceUnitID = stream.readInt ( );
68  position = stream.readInt ( );
69  time.abstime = stream.readInt ( );
70  if ( version >= 10001 ) {
71  int i= stream.readInt();
72  if ( i ) {
73  MapCoordinate3D mc;
74  mc.read ( stream );
75  nextServiceBuilding = ai->getMap()->getField( mc )->building;
76  nextServiceBuildingDistance = stream.readInt();
77  } else
78  nextServiceBuilding = NULL;
79 
80  if ( version >= 10002 )
81  requiredService = ServiceOrder::Service( stream.readInt() );
82  }
83 }
84 
85 void AI :: ServiceOrder :: write ( tnstream& stream ) const
86 {
87  stream.writeInt( currentServiceOrderVersion );
88  stream.writeInt ( targetUnitID );
89  stream.writeInt ( serviceUnitID );
90  stream.writeInt ( position );
91  stream.writeInt ( time.abstime );
92  if ( nextServiceBuilding ) {
93  stream.writeInt ( 1 );
94  nextServiceBuilding->getEntry().write ( stream );
95  stream.writeInt ( nextServiceBuildingDistance );
96  } else {
97  stream.writeInt ( 0 );
98  }
99  stream.writeInt ( requiredService );
100 }
101 
102 bool AI :: ServiceOrder :: completelyFailed ()
103 {
104  return failure > 2 ;
105 }
106 
107 
108 int AI::ServiceOrder::getServiceID() const
109 {
110  if ( requiredService == srv_ammo )
111  return 2000+getTargetUnit()->typ->weapons.weapon[position].getScalarWeaponType();
112 
113  if ( requiredService == srv_resource )
114  return 1000+position;
115 
116  return -1;
117 }
118 
119 
120 int AI::ServiceOrder::possible ( Vehicle* supplier )
121 {
122  if ( !ai->getMap()->getField( getTargetUnit()->getPosition())->unitHere ( getTargetUnit() ))
123  return 0;
124 
125  TransferHandler transferHandler( supplier, getTargetUnit(), TransferHandler::ignoreHeight + TransferHandler::ignoreDistance );
126 
127  int serviceAmount = 0;
128  for ( TransferHandler::Transfers::const_iterator i = transferHandler.getTransfers().begin(); i != transferHandler.getTransfers().end(); ++i ) {
129  if ( (*i)->getID() == getServiceID() ) {
130  int now = (*i)->getAmount(getTargetUnit());
131  int poss = (*i)->getMax( getTargetUnit(), true); // the amound that the servicer can provide
132  int mx = (*i)->getMax( getTargetUnit(), false); // the maximum storage
133  if ( poss > now && mx > now ) {
134  int percentage = 100 * (poss-now) / (mx - now );
135  serviceAmount += percentage;
136  }
137  }
138 
139  }
140  return serviceAmount;
141 }
142 
143 
144 bool AI::ServiceOrder::execute1st ( Vehicle* supplier )
145 {
146  Vehicle* targ = getTargetUnit();
147  MapCoordinate3D meet;
148 
149  vector<MapCoordinate3D> dest;
150  for ( int h = 0; h < 8; h++ ) {
151  if ( supplier->typ->height & ( 1<<h)) {
152  for ( int i = 0; i < sidenum; i++ ) {
153  int x = targ->xpos;
154  int y = targ->ypos;
155  x += getnextdx( i, y );
156  y += getnextdy( i );
157  MapField* fld = ai->getMap()->getField ( x, y );
158  if ( fld && fieldAccessible ( fld, supplier, 1<<h ) == 2 && !fld->building && !fld->vehicle ) {
159  bool result = false;
160  TemporaryContainerStorage tus ( supplier );
161  supplier->xpos = x;
162  supplier->ypos = y;
163  supplier->height = 1 << h;
164 
165 
166  TransferHandler transferHandler( supplier, getTargetUnit() );
167 
168  for ( TransferHandler::Transfers::const_iterator i = transferHandler.getTransfers().begin(); i != transferHandler.getTransfers().end(); ++i )
169  if ( (*i)->getID() == getServiceID() )
170  result = true;
171 
172  tus.restore();
173 
174  if ( result )
175  dest.push_back ( MapCoordinate3D(x, y, 1<<h ));
176  }
177  }
178  }
179  }
180 
181  if ( !dest.size() )
182  return false;
183 
184  AStar3D ast ( ai->getMap(), supplier, true, supplier->typ->maxSpeed()*6 );
185  AStar3D::Path path;
186  ast.findPath( path, dest );
187  if ( path.size() ) {
188  meet = *path.rbegin();
189 
190  int supplySpeed = supplier->maxMovement();
191  if ( !canWait() )
192  supplySpeed += targ->maxMovement();
193  if ( supplySpeed == 0 )
194  fatalError ( "AI::ServiceOrder::execute1st - supplySpeed is 0 ");
195 
196  if ( !targ->maxMovement() || beeline(supplier,targ) / supplySpeed < nextServiceBuildingDistance/targ->maxMovement() || nextServiceBuildingDistance < 0 ) {
197  supplier->aiparam[ai->getPlayerNum()]->dest = meet;
198  supplier->aiparam[ai->getPlayerNum()]->setTask( AiParameter::tsk_move );
199  supplier->aiparam[ai->getPlayerNum()]->dest_nwid = targ->networkid;
200 
201  setServiceUnit ( supplier );
202  return true;
203  }
204  }
205  return false;
206 }
207 
208 void AI::ServiceOrder::setServiceUnit ( Vehicle* veh )
209 {
210  if ( veh )
211  serviceUnitID = veh->networkid;
212  else
213  serviceUnitID = 0;
214 }
215 
216 void AI::ServiceOrder::releaseServiceUnit ( ServiceOrder& so )
217 {
218  Vehicle* veh = so.getServiceUnit();
219  if ( veh ) {
220  so.setServiceUnit ( NULL );
221  veh->aiparam[so.ai->getPlayerNum()]->resetTask();
222  }
223 }
224 
225 
226 bool AI::ServiceOrder::timeOut ( )
227 {
228  GameTime t = time;
229  t.set ( t.turn() + 2, t.move() );
230  return ( t.abstime <= ai->getMap()->time.abstime );
231 }
232 
233 bool AI::ServiceOrder::canWait( )
234 {
235  if ( requiredService == srv_repair )
236  return false;
237 
238  if ( requiredService == srv_ammo ) {
239  if ( getTargetUnit()->ammo[position] )
240  return true;
241 
242  if ( ai->targetsNear( getTargetUnit() ))
243  return true;
244  }
245 
246  bool fuelLack = requiredService == srv_resource && position == 2 ;
247  bool couldWait = fuelLack || !timeOut();
248  if ( couldWait )
249  return serviceUnitExists();
250  else
251  return false;
252 }
253 
254 bool AI::ServiceOrder::serviceUnitExists()
255 {
256  for ( Player::VehicleList::iterator vi = ai->getPlayer().vehicleList.begin(); vi != ai->getPlayer().vehicleList.end(); vi++ )
257  if ( possible ( *vi ))
258  return true;
259  return false;
260 }
261 
262 
263 bool AI::ServiceOrder::valid ( ) const
264 {
265  switch ( requiredService ) {
266  case srv_repair : return getTargetUnit()->damage > 0;
267  case srv_ammo : return getTargetUnit()->ammo[position] < getTargetUnit()->typ->weapons.weapon[position].count;
268  case srv_resource : return getTargetUnit()->getResource(getTargetUnit()->getStorageCapacity().resource(position), position, 1) < getTargetUnit()->getStorageCapacity().resource(position);
269  default: return false;
270  }
271 }
272 
273 bool AI::ServiceOrder::invalid ( const ServiceOrder& so )
274 {
275  return !so.valid();
276 }
277 
278 bool AI::ServiceOrder::operator==( const ServiceOrder& so ) const
279 {
280  return targetUnitID == so.targetUnitID
281  && requiredService == so.requiredService
282  && ai == so.ai
283  && position == so.position;
284 }
285 
286 bool AI::ServiceOrder::operator!=( const ServiceOrder& so ) const
287 {
288  return ! (*this == so);
289 }
290 
291 
292 AI :: ServiceOrder :: ~ServiceOrder ( )
293 {
294  if ( active ) {
295  Vehicle* serv = getServiceUnit();
296  if ( serv )
297  serv->aiparam[ai->getPlayerNum()]->resetTask();
298  }
299 }
300 
301 AI::ServiceOrder& AI :: issueService ( AI::ServiceOrder::Service requiredService, int UnitID, int pos )
302 {
303  ServiceOrder so ( this, requiredService, UnitID, pos );
304  ServiceOrderContainer::iterator soi = find ( serviceOrders.begin(), serviceOrders.end(), so );
305  if ( soi == serviceOrders.end() ) {
306  serviceOrders.push_back ( so );
307  ServiceOrder::activate ( *serviceOrders.rbegin() );
308  return *serviceOrders.rbegin();
309  } else {
310  return *soi;
311  }
312 }
313 
314 
315 
316 void AI :: issueServices ( )
317 {
318  displaymessage2("issuing services ... ");
319  serviceOrders.erase ( remove_if ( serviceOrders.begin(), serviceOrders.end(), ServiceOrder::targetDestroyed ), serviceOrders.end());
320 
321  for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); vi++ ) {
322  Vehicle* veh = *vi;
323  if ( getMap()->getField( veh->getPosition() )->unitHere( veh )) {
324  if ( veh->damage > config.damageLimit )
325  issueService ( ServiceOrder::srv_repair, veh->networkid ) ;
326 
327  for ( int i = 0; i< resourceTypeNum; i++ )
328  if ( veh->maxMovement() ) // stationary units are ignored
329  if ( veh->getResource(maxint, i, 1) < veh->getStorageCapacity().resource(i) * config.resourceLimit.resource(i) / 100 )
330  issueService ( ServiceOrder::srv_resource, veh->networkid, i);
331 
332  for ( int w = 0; w< veh->typ->weapons.count; w++ )
333  if ( veh->typ->weapons.weapon[w].count )
334  if ( veh->ammo[w] <= veh->typ->weapons.weapon[w].count * config.ammoLimit / 100 )
335  issueService ( ServiceOrder::srv_ammo, veh->networkid, w);
336  }
337  }
338 }
339 
340 AI::ServiceOrder& AI :: issueRefuelOrder ( Vehicle* veh, bool returnImmediately )
341 {
342  ServiceOrder& so = issueService ( ServiceOrder::srv_resource, veh->networkid, Resources::Fuel);
343  if ( returnImmediately ) {
344  if ( RefuelConstraint::necessary ( veh, *this )) {
345  RefuelConstraint apl ( *this, veh );
346  veh->aiparam[getPlayerNum()]->dest = apl.getNearestRefuellingPosition ( true, true, false );
347  if ( veh->aiparam[getPlayerNum()]->dest.valid() ) {
349  runUnitTask ( veh );
350  }
351  } else {
352 
353  }
354  }
355  return so;
356 }
357 
358 
359 
360 MapCoordinate3D AI :: findServiceBuilding ( const ServiceOrder& so, int* distance )
361 {
362  Vehicle* veh = so.getTargetUnit();
363  if ( getMap()->getField( veh->getPosition())->unitHere ( veh ))
364  if ( !veh->canMove() )
365  return MapCoordinate3D ( -1, -1, 1 );
366 
367  /*
368  RefuelConstraint* rc = NULL;
369  if ( RefuelConstraint::necessary ( veh, this ))
370  rc = new RefuelConstraint ( veh, this );
371  */
372 
373  int maxMovement = 0;
374  for ( int i = 0; i < 8; i++ )
375  maxMovement = max ( maxMovement, veh->typ->movement[i] );
376 
377 
378  Building* bestBuilding = NULL;
379  int bestDistance = maxint;
380  MapCoordinate3D bestPos;
381 
382  int bestDistance_p = maxint;
383  MapCoordinate3D bestPos_p;
384 
385  for (int factor = 1; factor <= 3; ++factor) {
386  AStar3D astar ( getMap(), veh, true, maxMovement*factor*factor );
387  astar.findAllAccessibleFields ( );
388  for ( Player::BuildingList::iterator bi = getPlayer().buildingList.begin(); bi != getPlayer().buildingList.end(); bi++ ) {
389  Building* bld = *bi;
390  if ( astar.getFieldAccess( bld->getEntry()) ) { // ####TRANS
391  MapCoordinate3D buildingPos = bld->getEntry();
392  buildingPos.setnum ( buildingPos.x, buildingPos.y, -1 );
393  /*
394  if ( !(bld->typ->loadcapability & buildingPos.z))
395  buildingPos.z = 1 << getFirstBit ( astar.getFieldAccess(bld->getEntry()) & bld->typ->loadcapability );
396  */
397 
398  bool loadable = true;
399  if ( loadable ) {
400  int fullfillableServices = 0;
401  int partlyFullfillabelServices = 0;
402  switch ( so.requiredService ) {
403  case ServiceOrder::srv_repair : if ( bld->canRepair( veh ) ) {
404  int mr = bld->getMaxRepair( veh );
405  if ( mr == 0 )
406  fullfillableServices++;
407 
408  if ( mr < veh->damage )
409  partlyFullfillabelServices++;
410 
411  }
412  break;
413  case ServiceOrder::srv_resource: {
414  Resources needed = veh->getStorageCapacity() - veh->getResource(Resources(maxint,maxint,maxint), true);
415  Resources avail = bld->getResource ( needed, 1 );
416  if ( avail < needed )
417  avail += bld->netResourcePlus( ) * config.waitForResourcePlus;
418 
419  int missing = 0;
420  int pmissing = 0;
421  for ( int r = 0; r < resourceTypeNum; r++ ) {
422  if( needed.resource(r) * 75 / 100 > avail.resource(r) )
423  missing ++;
424 
425  if( needed.resource(r) * 10 / 100 > avail.resource(r) )
426  pmissing ++;
427  }
428  if ( missing == 0 )
429  fullfillableServices++;
430 
431  if ( pmissing == 0)
432  partlyFullfillabelServices++;
433  }
434  break;
435  case ServiceOrder::srv_ammo : {
436  int missing = 0;
437  int pmissing = 0;
438  int ammoNeeded[waffenanzahl];
439  for ( int t = 0; t < waffenanzahl; t++ )
440  ammoNeeded[t] = 0;
441 
442  for ( int i = 0; i < veh->typ->weapons.count; i++ )
443  if ( veh->typ->weapons.weapon[i].requiresAmmo() )
444  ammoNeeded[ veh->typ->weapons.weapon[i].getScalarWeaponType() ] += veh->typ->weapons.weapon[i].count - veh->ammo[i];
445 
446  Resources needed;
447  for ( int j = 0; j < waffenanzahl; j++ ) {
448  int n = ammoNeeded[j] - bld->ammo[j];
449  if ( n > 0 ) {
451  for ( int r = 0; r < resourceTypeNum; r++ )
452  needed.resource(r) += (n+4)/5 * ammoProductionCost[j][r];
453  } else
454  missing++;
455  }
456  }
457  Resources avail = bld->getResource ( needed, 1 );
458  if ( avail < needed )
459  avail += bld->netResourcePlus( ) * config.waitForResourcePlus;
460 
461  for ( int r = 0; r < resourceTypeNum; r++ ) {
462  if ( avail.resource(r) < needed.resource (r) )
463  missing++;
464  if ( avail.resource(r) <= needed.resource (r)/3 )
465  pmissing++;
466  }
467 
468  if ( missing == 0 )
469  fullfillableServices++;
470 
471  if ( pmissing == 0)
472  partlyFullfillabelServices++;
473 
474  }
475  break;
476 
477  };
478 
479  if ( fullfillableServices ) {
480  const AStar3D::Node* n = astar.visited.find(buildingPos);
481  if ( n && ( n->gval < bestDistance ) ) {
482  bestDistance = (int)n->gval;
483  bestBuilding = bld;
484  bestPos = buildingPos;
485  }
486  } else {
487  if ( partlyFullfillabelServices ) {
488  const AStar3D::Node* n = astar.visited.find(buildingPos);
489  if ( n && ( n->gval < bestDistance_p ) ) {
490  bestDistance_p = (int)n->gval;
491  bestPos_p = buildingPos;
492  }
493  }
494  }
495  }
496  }
497  }
498  if (bestBuilding)
499  break;
500  }
501  if ( bestBuilding && (bestDistance < bestDistance_p*3)) {
502  if ( distance )
503  *distance = bestDistance;
504  return bestPos;
505  } else {
506  if ( distance )
507  *distance = bestDistance_p;
508  return bestPos_p;
509  }
510 }
511 
512 
513 
514 
515 bool AI :: ServiceTargetEquals :: operator() (const ServiceOrder& so ) const
516 {
517  Vehicle* t = so.getTargetUnit();
518  return target== t;
519 }
520 
521 
522 
523 void AI::removeServiceOrdersForUnit ( const Vehicle* veh )
524 {
525  serviceOrders.erase ( remove_if ( serviceOrders.begin(), serviceOrders.end(), ServiceTargetEquals( veh ) ), serviceOrders.end());
526 }
527 
528 void AI :: runServiceUnit ( Vehicle* supplyUnit )
529 {
530  bool destinationReached = false;
531  typedef multimap<float,ServiceOrder*> ServiceMap;
532  ServiceMap serviceMap;
533 
534  // building a list of all fullfillable service tasks
535  for ( ServiceOrderContainer::iterator i = serviceOrders.begin(); i != serviceOrders.end(); i++ ) {
536  if ( !i->getServiceUnit() && i->getTargetUnit() ) {
537  int poss = i->possible( supplyUnit );
538  if ( poss && beeline( i->getTargetUnit() ,supplyUnit ) ) {
539  float f = i->getTargetUnit()->aiparam[getPlayerNum()]->getValue() * poss/100 / beeline( i->getTargetUnit() ,supplyUnit );
540  serviceMap.insert(make_pair(f,&(*i)));
541  }
542  /*
543  veh->aiparam[getPlayerNum()]->getTask() = AiParameter::tsk_serviceRetreat;
544  Building* bld = findServiceBuilding( **i );
545  if ( bld )
546  veh->aiparam[ getPlayerNum() ]->dest = bld->getEntry ( );
547  */
548  }
549  }
550  int target = 0;
551  int counter = 0;
552  for ( ServiceMap::reverse_iterator ri = serviceMap.rbegin(); ri != serviceMap.rend(); ri++ ) {
553  displaymessage2("test service %d", ++counter);
554  if ( ri->second->execute1st( supplyUnit ) ) {
555  target = supplyUnit->aiparam[getPlayerNum()]->dest_nwid;
556  destinationReached = runUnitTask ( supplyUnit );
557  break;
558  }
559  }
560 
561  Vehicle* targetUnit = getMap()->getUnit(target);
562  if ( destinationReached && targetUnit ) {
563 
564  auto_ptr<ServiceCommand> sc ( new ServiceCommand( supplyUnit ));
565  sc->setDestination( targetUnit );
566  sc->getTransferHandler().fillDest();
567  sc->saveTransfers();
568  ActionResult res = sc->execute( getContext() );
569  if ( res.successful() )
570  sc.release();
571  else
572  displayActionError(res);
573 
574 
575  if ( targetUnit->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat )
576  targetUnit->aiparam[getPlayerNum()]->resetTask();
577 
578  removeServiceOrdersForUnit ( targetUnit );
579 
580  // search for next unit to be serviced
581  runServiceUnit( supplyUnit );
582  }
583 }
584 
585 
586 AI::AiResult AI :: executeServices ( )
587 {
588  // removing all service orders for units which no longer exist
589  removeServiceOrdersForUnit ( NULL );
590  serviceOrders.erase ( remove_if ( serviceOrders.begin(), serviceOrders.end(), ServiceOrder::invalid ), serviceOrders.end());
591 
592  for_each ( serviceOrders.begin(), serviceOrders.end(), ServiceOrder::releaseServiceUnit );
593 
594  AiResult res;
595 
596  vector<int> unitIds;
597  for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); ++vi )
598  unitIds.push_back ( (*vi)->networkid );
599 
600 
601  for ( vector<int>::iterator vi = unitIds.begin(); vi != unitIds.end(); ++vi ) {
602  Vehicle* veh = getMap()->getUnit( *vi );
603  if ( veh ) {
604  checkKeys();
605  if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_supply )
606  runServiceUnit ( veh );
607  }
608  }
609 
610  removeServiceOrdersForUnit ( NULL );
611  int counter = 0;
612  for ( ServiceOrderContainer::iterator i = serviceOrders.begin(); i != serviceOrders.end(); ) {
613  ServiceOrderContainer::iterator nxt = i;
614  ++nxt;
615 
616  if ( !i->canWait() ) {
617  displaymessage2("executing priority service order %d", ++counter);
618  Vehicle* veh = i->getTargetUnit();
619  if ( i->getServiceUnit() ) {
620  if ( veh->canMove() ) {
621  veh->aiparam[ getPlayerNum() ]->dest = i->getServiceUnit()->getPosition();
622  veh->aiparam[ getPlayerNum() ]->dest_nwid = i->getServiceUnit()->networkid;
624  }
625  } else {
627  if ( (veh->height & ( chtieffliegend | chfliegend | chhochfliegend )) && veh->typ->fuelConsumption && false ) {
628  RefuelConstraint apl ( *this, veh );
629  MapCoordinate3D dst = apl.getNearestRefuellingPosition( true, true, false );
630  if ( dst.x != -1 ) {
631  veh->aiparam[ getPlayerNum() ]->dest = dst;
633  }
634  } else {
635  MapCoordinate3D dest = findServiceBuilding( *i );
636  if ( dest.valid() && veh->canMove() ) {
637  veh->aiparam[ getPlayerNum() ]->dest = dest;
639  } else {
640  // displaymessage("warning: no service building found found for unit %s - %d!",1, veh->typ->description, veh->typ->id);
641  }
642  }
643  }
644  }
645 
646  i = nxt;
647  }
648 
649 
650  unitIds.clear();
651  for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); ++vi )
652  unitIds.push_back ( (*vi)->networkid );
653 
654 
655  counter = 0;
656  for ( vector<int>::iterator vi = unitIds.begin(); vi != unitIds.end(); ++vi ) {
657  Vehicle* veh = getMap()->getUnit( *vi );
658  checkKeys();
659 
660  if ( veh && veh->canMove() && veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat ) {
661  displaymessage2("retreating with unit %d", ++counter);
662  int nwid = veh->networkid;
663  moveUnit ( veh, veh->aiparam[ getPlayerNum() ]->dest, true );
664 
665  // the unit may have been shot down
666  Vehicle* veh = getMap()->getUnit ( nwid );
667  if ( veh ) {
668  if ( veh->getPosition3D() == veh->aiparam[ getPlayerNum() ]->dest ) {
669  MapField* fld = getMap()->getField ( veh->xpos, veh->ypos );
670  if ( fld->building ) {
671  auto_ptr<ServiceCommand> sc ( new ServiceCommand( fld->building ));
672  sc->setDestination( veh );
673  sc->getTransferHandler().fillDest();
674  sc->saveTransfers();
675  ActionResult res = sc->execute( getContext() );
676  if ( res.successful() )
677  sc.release();
678  else
679  displayActionError(res);
680 
681 
682  if ( veh->damage ) {
683  if( RepairUnitCommand::avail( fld->building )) {
684  auto_ptr<RepairUnitCommand> ruc ( new RepairUnitCommand( fld->building ));
685  if ( ruc->validTarget( veh )) {
686  ruc->setTarget( veh );
687  ActionResult res = ruc->execute( getContext() );
688  if ( res.successful() )
689  ruc.release();
690  }
691  }
692  }
693 
694  removeServiceOrdersForUnit ( veh );
695 
696  if ( veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat )
697  veh->aiparam[getPlayerNum()]->resetTask();
698 
699  }
700  }
701  }
702  }
703  }
704 
705  /*
706  for ( ServiceOrderContainer::iterator i = serviceOrders.begin(); i != serviceOrders.end(); i++ ) {
707  if ( !i->timeOut() && i->requiredService == VehicleService::srv_repair ) {
708  Vehicle* veh = i->getTargetUnit();
709  veh->aiparam[getPlayerNum()]->getTask() = AiParameter::tsk_serviceRetreat;
710  Building* bld = findServiceBuilding( *i );
711  if ( bld )
712  veh->aiparam[ getPlayerNum() ]->dest = bld->getEntry ( );
713  else {
714  // displaymessage("warning: no service building found found for unit %s - %d!",1, veh->typ->description, veh->typ->id);
715  }
716 
717  }
718  }
719 */
720  return res;
721 
722 }
the time in ASC, measured in turns and moves
Definition: typen.h:178
bool canRepair(const ContainerBase *item) const
checks whether the item can be repaired provided that it is in range
Definition: buildings.cpp:93
bool operator==(const AStar3D::Node &a, const AStar3D::Node &b)
Definition: astar2.cpp:122
int fieldAccessible(const MapField *field, const Vehicle *vehicle, int uheight, const bool *attacked, bool ignoreVisibility)
Definition: spfst.cpp:124
Resources netResourcePlus() const
returns the amount of resources that the net which the building is connected to produces each turn ...
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
const BuildingType * typ
Definition: buildings.h:48
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 getResource(int amount, int resourcetype, bool queryonly, int scope=1, int player=-1)
Definition: vehicle.cpp:328
int getMaxRepair(const ContainerBase *item) const
returns the maximum amount of damage that the given item can be repaired
int damage
Damage. 0 is no damage, when damage reaches 100 the container is destroyed.
GameMap * getMap(void)
returns the map this AI runson
Definition: ai.h:486
Vehicle * vehicle
Definition: mapfield.h:89
const int waffenanzahl
The number of different weapon types.
Definition: typen.h:58
bool valid() const
Definition: typen.h:221
AiParameter * aiparam[8]
Definition: vehicle.h:182
int ammo[16]
Definition: vehicle.h:87
int abstime
Definition: typen.h:183
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
UnitWeapon weapons
The weapons.
Definition: vehicletype.h:248
Resources getStorageCapacity() const
returns the local storage capacity for the given resource, which depends on the resource mode of the ...
bool hasFunction(ContainerFunctions function) const
int turn() const
Definition: typen.h:181
MapCoordinate3D getEntry() const
returns the position of the buildings entry
Definition: buildings.cpp:410
int count
amount of ammunition the unit having this weapon can carry
Definition: vehicletype.h:117
MapCoordinate3D getPosition() const
returns the units position
Definition: vehicle.cpp:1552
#define chhochfliegend
Definition: typen.h:416
SingleWeapon weapon[16]
Definition: vehicletype.h:170
The interface for all kinds of IO stream.
a single field of the map
Definition: mapfield.h:26
Definition: ai.h:44
void read(tnstream &stream)
Definition: typen.h:254
vector< int > movement
the distance a unit can travel each round. One value for each of the 8 levels of height ...
Definition: vehicletype.h:203
int height
the current level of height ( BITMAPPED ! )
Definition: vehicle.h:118
bool findPath(const MapCoordinate3D &dest)
searches for a path from the unit's current position to dest
Definition: astar2.cpp:335
int beeline(const Vehicle *a, const Vehicle *b)
returns the distance between the units a and b
int move() const
Definition: typen.h:180
const int sidenum
the number of sides that a field has; is now fixed at 6;
Definition: typen.h:438
int getPlayerNum(void)
returns the number of the player which is controlled by this ai
Definition: ai.h:490
int getScalarWeaponType(void) const
MapCoordinate3D getPosition3D() const
returns the units position; if inside building then Height is -1
Definition: vehicle.cpp:1557
friend class RefuelConstraint
Definition: ai.h:168
VehicleList vehicleList
a list of all units
Definition: player.h:135
void setTask(Task t)
const int resourceTypeNum
The number of different resources that ASC uses.
Definition: typen.h:77
const int currentServiceOrderVersion
Definition: service.cpp:59
#define chtieffliegend
Definition: typen.h:414
GameMap * getMap() const
Definition: mapfield.h:38
const int ammoProductionCost[weaponTypeNum][3]
Definition: vehicletype.cpp:75
Player & getPlayer(void)
Definition: ai.h:492
friend class ServiceOrder
Definition: ai.h:118
static bool avail(const ContainerBase *servicer)
int ammo[waffenanzahl]
the ammo that is stored in the building
Definition: buildings.h:50
void setnum(int _x, int _y, int numericalz)
Definition: typen.h:250
bool requiresAmmo(void) const
int getnextdx(int dir, int y)
Definition: mapalgorithms.h:77
void resetTask()
Definition: gamemap.cpp:2097
bool successful() const
Vehicle * getUnit(int x, int y, int nwid)
Definition: gamemap.cpp:1215
int getnextdy(int dir)
Definition: mapalgorithms.h:80
int height
the levels of height which this unit can enter
BuildingList buildingList
a list of all units
Definition: player.h:139
bool canMove(void) const
can the unit move from its current position (does not check neighbouring fields)
Definition: vehicle.cpp:599
void displaymessage2(const char *formatstring,...)
displays a message in the status line of ASC
int fuelConsumption
the fuel consumption to move a single field
Definition: vehicletype.h:200
int & resource(int type)
Definition: typen.h:105
int xpos
the position on the map
Definition: vehicle.h:124
deque< PathPoint > Path
Definition: astar2.h:48
const VehicleType * typ
Definition: vehicle.h:83
int getResource(int amount, int resourcetype, bool queryonly, int scope=1, int player=-1)
Definition: controls.cpp:243
Coordinate on the map including height.
Definition: typen.h:238
Building * building
Definition: mapfield.h:102
A 3D path finding algorithm, based on the 2D algorithm by Amit J. Patel.
Definition: astar2.h:19
#define maxint
Definition: typen.h:462
An actual building on the map, which references a BuildingType Buildings have an owner,.
Definition: buildings.h:38
const T & max(const T &a, const T &b, const T &c)
Definition: misc.h:97
static const int ignoreDistance
Definition: servicing.h:111
Resources are basically the currency of ASC.
Definition: typen.h:97
void displayActionError(const ActionResult &result, const ASCString &additionalInfo)
Definition: dialog.cpp:2168
MapCoordinate3D dest
int ypos
Definition: vehicle.h:124
void fatalError(const ASCString &string)
int maxSpeed() const
static const int ignoreHeight
Definition: servicing.h:110
AStar3D::DistanceType gval
Definition: astar2.h:65
#define chfliegend
Definition: typen.h:415
int networkid
a unique identification of the unit that is used everywhere in ASC (and not only the network protocol...
Definition: vehicle.h:140
Context getContext()
Definition: base.cpp:597
GameTime time
the time in the game, mesured in a turns and moves
Definition: gamemap.h:235
void set(int turn, int move)
Definition: typen.h:183
MapField * getField(int x, int y)
Definition: gamemap.h:465