Advanced Strategic Command
ai/misc.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  misc.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 
19 #include <iostream>
20 #include "ai_common.h"
21 #include "../actions/attackcommand.h"
22 #include "../actions/constructunitcommand.h"
23 #include "../actions/moveunitcommand.h"
24 #include "../actions/servicecommand.h"
25 
26 bool AI :: runUnitTask ( Vehicle* veh )
27 {
28  if ( veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_move || veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat ) {
29  bool moveIntoBuildings = false;
30  if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer ||
32  veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_script )
33  moveIntoBuildings = true;
34 
35  int nwid = veh->networkid;
36  moveUnit ( veh, veh->aiparam[getPlayerNum()]->dest, moveIntoBuildings );
37  if ( getMap()->getUnit( nwid ))
38  if ( veh->getPosition() == veh->aiparam[getPlayerNum()]->dest ) {
39  veh->aiparam[getPlayerNum()]->resetTask ();
40  return true;
41  }
42  }
43 
44  return false;
45 }
46 
47 
48 
49 int AI :: getBestHeight ( Vehicle* veh )
50 {
51  int heightNum = 0;
52  for ( int i = 0; i < 8; i++ )
53  if ( veh->typ->height & ( 1 << i ))
54  heightNum++;
55  if ( heightNum == 1 )
56  return veh->typ->height;
57 
58  int bestHeight = -1;
59  float bestHeightValue = minfloat;
60 
61  float maxAvgFieldThreat = minfloat;
62  float minAvgFieldThreat = maxfloat;
63  float secminAvgFieldThreat = maxfloat;
64 
65 
66  for ( int k = 0; k < 8; k++ )
67  if ( veh->typ->height & ( 1 << k )) {
68  float t = sections.getForCoordinate( veh->xpos, veh->ypos ).avgFieldThreat.threat[ veh->getValueType(1<<k) ];
69 
70  if ( maxAvgFieldThreat < t )
71  maxAvgFieldThreat = t;
72 
73  if ( minAvgFieldThreat > t )
74  minAvgFieldThreat = t;
75 
76  if ( t )
77  if ( secminAvgFieldThreat > t )
78  secminAvgFieldThreat = t;
79  }
80 
81 
82  for ( int j = 0; j < 8; j++ )
83  if ( veh->typ->height & ( 1 << j )) {
84  // we save the unit, because we modify a lot of it that should be undone later
85  TemporaryContainerStorage tus (veh);
86  veh->height = 1<<j;
87 
88  // calculating the new threat of the unit
89  calculateThreat ( veh );
90  Section& sec = sections.getForCoordinate( veh->xpos, veh->ypos );
91 
92  float value = veh->aiparam[getPlayerNum()]->getValue();
93  if ( veh->typ->movement[j] )
94  value *= log( double(veh->typ->movement[j]) );
95 
96  float threat = sec.avgFieldThreat.threat[ veh->aiparam[getPlayerNum()]->valueType ];
97  if ( minAvgFieldThreat > 0 ) {
98  if ( threat && threat != 1 )
99  value *= ( log ( minAvgFieldThreat ) / log ( threat ) );
100  } else {
101  if ( secminAvgFieldThreat < maxfloat) {
102  if ( threat && threat != 1 )
103  value *= ( log ( secminAvgFieldThreat ) / log ( threat ) );
104  else
105  value *= 1.5; // no threat
106  }
107  }
108 
109  if ( value > bestHeightValue ) {
110  bestHeightValue = value;
111  bestHeight = 1 << j;
112  }
113  tus.restore();
114  }
115 
116  return bestHeight;
117 }
118 
119 
120 
122  int m;
123  Vehicle* unit;
124  public:
126  unit = veh;
127  npush ( unit->xpos );
128  npush ( unit->ypos );
129  npush ( unit->height );
130  m = unit->getMovement();
131  npush ( unit->attacked );
132  };
134  npop ( unit->attacked );
135  unit->setMovement ( m, 0 );
136  npop ( unit->height );
137  npop ( unit->ypos );
138  npop ( unit->xpos );
139  };
140 };
141 
142 
143 
144 void AI::RefuelConstraint::findPath( bool markTemps )
145 {
146  if ( !ast ) {
147 
148  int dist;
149  if ( maxMove == -1 ) {
150  if ( veh->typ->fuelConsumption )
151  dist = veh->getResource(maxint, 2, true) / veh->typ->fuelConsumption * maxmalq;
152  else
153  dist = maxint;
154 
155  dist = min( dist, 1000 );
156  } else
157  dist = maxMove;
158 
159  ast = new AStar3D ( ai.getMap(), veh, markTemps, dist );
160  ast->findAllAccessibleFields ( );
161  // tanker planes may have a very large range; that's why we top the distance at 100 fields
162  }
163 }
164 
165 MapCoordinate3D AI::RefuelConstraint::getNearestRefuellingPosition ( bool buildingRequired, bool refuel, bool repair )
166 {
167  findPath();
168 
169  /*
170  int fuel = veh->getResource(maxint, 2, true);
171  int x1,y1,x2,y2;
172  x1 = max(veh->xpos - fuel / veh->typ->fuelConsumption, 0 );
173  y1 = max(veh->ypos - fuel / veh->typ->fuelConsumption, 0 );
174  x2 = min(veh->xpos + fuel / veh->typ->fuelConsumption, ai.getMap()->xsize );
175  y2 = min(veh->ypos + fuel / veh->typ->fuelConsumption, ai.getMap()->ysize );
176  */
177 
178  for ( AStar3D::VisitedContainer::iterator i = ast->visited.begin(); i != ast->visited.end(); i++ ) {
179  AStar3D::Node n = *i;
180  int dist = int(n.gval );
181  if ( n.h.getNumericalHeight() == -1 ) {
182  MapField* fld = ai.getMap()->getField( n.h.x, n.h.y );
183  if ( fld->building && fld->building->color == veh->color )
184  reachableBuildings[ dist ] = fld->building;
185  }
186  // aircraft carriers should be supported too....
187  // external loading of buildings too....
188  // turrets too .....
189 
190 
191  // let's check for landing
192  if ((veh->height > chfahrend) && (n.h.getNumericalHeight() == chfahrend) ) {
193  // we don't want to land in hostile territory
194  FieldInformation& fi = ai.getFieldInformation ( n.h.x, n.h.y );
195  if ( fi.control == -1 || !ai.getMap()->player[fi.control].diplomacy.isHostile( ai.getPlayerNum() ) )
196  landingPositions[dist] = n.h;
197  }
198  }
199 
200 
201  /*
202  for ( int x = x1; x < x2; x++ )
203  for ( int y = y1; y < y2; y++ )
204  for ( int h = 0; h < 8; h++ )
205  if ( veh->typ->height & ( 1 << h)) {
206 
207  tfield* fld = getfield( x,y );
208  const AStar3D::Node* node = ast->fieldVisited( MapCoordinate3D( x,y, 1 << h));
209  if ( node ) {
210  int dist = int(node->gval);
211  if ( fld->building && fld->building->color == veh->color )
212  reachableBuildings[ dist ] = fld->building;
213 
214  // aircraft carriers should be supported too....
215  // external loading of buildings too....
216  // turrets too .....
217 
218 
219  // let's check for landing
220  if ((veh->height > chfahrend) && (fld->a.temp & chfahrend) && ( 1 << h) == chfahrend ) {
221  // we don't want to land in hostile territory
222  FieldInformation& fi = ai.getFieldInformation ( x, y );
223  if ( fi.control == -1 || getdiplomaticstatus2 ( fi.control * 8, ai.getPlayerNum()*8 ) == capeace )
224  landingPositions[dist] = MapCoordinate3D( x,y,chfahrend);
225  }
226  }
227  }
228  */
229 
230  if ( buildingRequired ) {
231  for ( ReachableBuildings::iterator rb = reachableBuildings.begin(); rb != reachableBuildings.end(); rb++ ) {
232  if ( !repair || (rb->second->typ->hasFunction( ContainerBaseType::InternalUnitRepair )))
233  return rb->second->getPosition3D();
234  }
235  }
236  if ( !reachableBuildings.empty() && !landingPositions.empty()) {
237  if ( reachableBuildings.begin()->first < landingPositions.begin()->first )
238  return reachableBuildings.begin()->second->getPosition3D();
239  else
240  return landingPositions.begin()->second;
241  }
242 
243  if ( !landingPositions.empty() )
244  return landingPositions.begin()->second;
245  else
246  return MapCoordinate3D();
247 }
248 
249 bool AI::RefuelConstraint::returnFromPositionPossible ( const MapCoordinate3D& pos, int theoreticalFuel )
250 {
251  if ( !veh->typ->fuelConsumption )
252  return true;
253 
254  if ( theoreticalFuel < 0 )
255  theoreticalFuel = veh->getResource(maxint, 2, true );
256 
257  findPath();
258  if ( !positionsCalculated ) {
259  getNearestRefuellingPosition ( true, true, false );
260  positionsCalculated = true;
261  }
262 
263  const AStar3D::Node* n = ast->visited.find(pos);
264  if (!n)
265  return false;
266  const int dist = (int)n->gval;
267  int dist2;
268  if ( !reachableBuildings.empty() ) {
269  ReachableBuildings::iterator rb = reachableBuildings.begin();
270  dist2 = beeline ( pos, rb->second->getPosition() );
271  rb++;
272  while ( rb != reachableBuildings.end() ) {
273  int d = beeline ( pos, rb->second->getPosition() );
274  if ( d < dist2 ) {
275  dist2 = d;
276  }
277  rb++;
278  }
279  } else {
280  if ( !landingPositions.empty() ) {
281  LandingPositions::iterator lp = landingPositions.begin();
282  dist2 = beeline ( pos, lp->second );
283  MapCoordinate3D dest = lp->second;
284  lp++;
285  while ( lp != landingPositions.end() ) {
286  int d = beeline ( pos, lp->second );
287  if ( d < dist2 ) {
288  dist2 = d;
289  dest = lp->second;
290  }
291  lp++;
292  }
293  } else /*
294  if ( veh->height > chfahrend )
295  dist2 = maxint;
296  else */
297  return true;
298  }
299 
300  if ( theoreticalFuel - (dist + dist2) / maxmalq * veh->typ->fuelConsumption > 0.2 * veh->getStorageCapacity().fuel )
301  return true;
302  else
303  return false;
304 
305 }
306 
307 bool AI::RefuelConstraint::necessary (const Vehicle* veh, AI& ai )
308 {
309  if ( !veh->typ->fuelConsumption )
310  return false;
311  if ( !(veh->height & (chtieffliegend | chfliegend | chhochfliegend))) {
312  ServiceOrder so ( &ai, ServiceOrder::srv_resource, veh->networkid, 2 );
313  if ( so.serviceUnitExists() )
314  return false;
315  else
316  return true;
317  }
318 
319  return true;
320 }
321 
322 
323 AI::VehicleTypeEfficiencyCalculator::VehicleTypeEfficiencyCalculator( AI& _ai, Vehicle* _attacker, Vehicle* _target )
324  : ai ( _ai ), attacker( _attacker ), target( _target)
325 {
326  ownValue = attacker->aiparam[ai.getPlayerNum()]->getValue();
327  ownTypeID = attacker->typ->id;
328  enemyValue = target->aiparam[ai.getPlayerNum()]->getValue();
329  orgOwnDamage = attacker->damage;
330  orgEnemyDamage = target->damage;
331  enemyID = target->networkid;
332  ownID = attacker->networkid;
333 }
334 
335 
336 void AI::VehicleTypeEfficiencyCalculator::calc()
337 {
338  int newOwnDamage;
339  if ( ai.getMap()->getUnit(ownID) )
340  newOwnDamage = attacker->damage;
341  else
342  newOwnDamage = 100;
343 
344  int newEnemyDamage;
345  if ( ai.getMap()->getUnit(enemyID) )
346  newEnemyDamage = target->damage;
347  else
348  newEnemyDamage = 100;
349 
350  ai.unitTypeSuccess[ownTypeID].first += enemyValue * (newEnemyDamage - orgEnemyDamage) * 0.01;
351  ai.unitTypeSuccess[ownTypeID].second += ownValue * (newOwnDamage - orgOwnDamage ) * 0.01;
352 }
353 
354 AI::AiResult AI :: container ( ContainerBase* cb )
355 {
356  AiResult result;
357 
358  // move idle units out
359  std::vector<Vehicle*> idleUnits;
360  for ( vector<Vehicle*>::const_iterator j = cb->getCargo().begin(); j != cb->getCargo().end(); ++j ) {
361  Vehicle* veh = *j;
362  if ( veh )
363  if ( veh->canMove() && veh->getOwner() == getPlayerNum() )
366  idleUnits.push_back ( veh );
367  }
368 
369  // move the most important unit first, to get the best position
370  sort ( idleUnits.begin(), idleUnits.end(), vehicleValueComp );
371 
372  for ( std::vector<Vehicle*>::iterator i = idleUnits.begin(); i != idleUnits.end(); i++ ) {
373 
374  checkKeys();
375 
376  // Vehicle* veh = *i;
377 
378  int preferredHeight = getBestHeight ( *i );
379 
380  auto_ptr<MoveUnitCommand> muc ( new MoveUnitCommand( *i ));
381  muc->searchFields();
382 
383  if ( muc->getReachableFields().size() ) {
384 
385  int moved = 0;
386  if ( AttackCommand::avail ( *i )) {
387  TargetVector tv;
388 
389  AStar3D ast ( getMap(), *i, false, (*i)->getMovement() );
391 
392  getAttacks ( ast, *i, tv, 0, false, false );
393 
394  if ( tv.size() ) {
395  AiResult res = executeMoveAttack ( *i, tv );
396  result += res;
397  if ( !res.unitsDestroyed )
398  (*i)->aiparam[ getPlayerNum() ]->setTask( AiParameter::tsk_tactics );
399 
400  moved = 1;
401  } else {
402  AStar3D ast ( getMap(), *i, false, (*i)->maxMovement()*3 );
404 
405  getAttacks ( ast, *i, tv, 0, false, false );
406 
407  if ( tv.size() ) {
408  MoveVariant* mv = *max_element( tv.begin(), tv.end(), moveVariantComp );
409  if ( moveUnit ( *i, mv->movePos ) )
410  moved = 1;
411  }
412  }
413 
414  }
415  if ( !moved ) {
416  AiResult res = moveToSavePlace ( *i, preferredHeight );
417  result += res;
418  if ( !res.unitsDestroyed )
419  (*i)->aiparam[ getPlayerNum() ]->resetTask();
420  }
421  }
422  }
423  return result;
424 }
425 
426 
427 AI::AiResult AI::buildings( int process )
428 {
429  AiResult result;
430 
431  displaymessage2("checking buildings ... ");
432 
433  int buildingCounter = 0;
434  for ( Player::BuildingList::iterator bi = getPlayer().buildingList.begin(); bi != getPlayer().buildingList.end(); bi++ ) {
435  buildingCounter++;
436  displaymessage2("processing building %d", buildingCounter );
437 
438  int unitCounter = 0;
439  for ( vector<Vehicle*>::const_iterator j= (*bi)->getCargo().begin(); j != (*bi)->getCargo().end(); j++ ) {
440  Vehicle* veh = *j;
441  if ( veh ) {
442  ++unitCounter;
443  displaymessage2("processing building %d (unit %d)", buildingCounter, unitCounter );
444 
445  auto_ptr<ServiceCommand> sc ( new ServiceCommand( *bi ));
446  sc->setDestination( veh );
447  if ( veh->aiparam[ getPlayerNum() ]->getJob() != AiParameter::job_supply )
448  sc->getTransferHandler().fillDestAmmo();
449  else
450  sc->getTransferHandler().fillDest();
451 
452  sc->saveTransfers();
453  ActionResult res = sc->execute( getContext() );
454  if ( res.successful() )
455  sc.release();
456 
457  }
458  }
459 
460  result += container ( *bi );
461 
462  checkKeys();
463  }
464 
465  displaymessage2("building check completed... ");
466  return result;
467 }
468 
469 
470 AI::AiResult AI::transports( int process )
471 {
472  AiResult result;
473 
474  displaymessage2("checking transports ... ");
475 
476  int transportCounter = 0;
477  for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); vi++ ) {
478  Vehicle* veh = *vi;
479  transportCounter++;
480  displaymessage2("processing unit %d for transportation ", transportCounter );
481 
482  result += container ( veh );
483 
484  checkKeys();
485  }
486 
487  displaymessage2("transport check completed... ");
488  return result;
489 }
490 
491 
492 
493 bool AI :: moveUnit ( Vehicle* veh, const MapCoordinate3D& destination, bool intoBuildings, bool intoTransports )
494 {
495  if ( veh->getPosition3D() == destination )
496  return true;
497 
498  AStar3D* ast = NULL;
500  ast = new HiddenAStar3D ( this, veh );
501  else
502  if ( beeline ( veh->getPosition(), destination) > veh->maxMovement() )
503  ast = new StratAStar3D ( this, veh );
504  else
505  ast = new AntiMineAStar3D ( this, veh );
506 
507  auto_ptr<AStar3D> ap ( ast );
508 
509  AStar3D::Path path;
510  ast->findPath ( path, destination );
511 
512  if ( path.empty() )
513  return false;
514 
515  auto_ptr<MoveUnitCommand> mum ( new MoveUnitCommand( veh ));
516  mum->searchFields();
517  // CODE DUPLICATION: MoveUnitCommand::findPath()
518  const AStar3D::Node* n;
519  for (n = ast->visited.find(path.back()); n != NULL; n = n->previous) {
520  if ( (n->gval <= veh->getMovement() ) && n->canStop ) {
521  MapField* fld = getMap()->getField ( n->h );
522  if ( fld->getContainer() ) {
523  if ( n->h != path.back() ) {
524  continue;
525  }
526  } else {
527  if ( ( fld->building && !intoBuildings ) || ( fld->vehicle && !intoTransports ) ) {
528  continue;
529  }
530  }
531  mum->setDestination( n->h );
532  break;
533  }
534  }
535  if ( n == NULL )
536  return false;
537 
538  mum->setFlags( MoveUnitCommand::NoInterrupt );
539 
540  int nwid = veh->networkid;
541  int oldHeight = veh->getPosition3D().getNumericalHeight();
542 
543  if ( getMap()->getField ( n->h )->building )
544  if ( checkReConquer ( getMap()->getField ( n->h )->building, veh ) )
545  return false;
546 
547  ActionResult res = mum->execute( getContext() );
548  if ( res.successful() ) {
549  mum.release();
550  if ( getMap()->getUnit ( nwid ) && (oldHeight != veh->getPosition3D().getNumericalHeight()) )
551  veh->aiparam[ getPlayerNum()]->setNewHeight();
552  } else {
553  displaymessage ( "AI :: moveUnit (path) \n error in movement step 3 with unit %d", 1, veh->networkid );
554  return false;
555  }
556 
558  if ( ! getMap()->getUnit ( nwid ))
559  return true;
560 
561  if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
562  if ( getMap()->getField ( veh->getPosition() )->building )
563  veh->aiparam[getPlayerNum()]->clearJobs();
564 
565  return true;
566 
567 // }
568 }
569 
570 AI:: CheckFieldRecon :: CheckFieldRecon ( AI* _ai ) : SearchFields ( _ai->getMap() ), player(_ai->getPlayerNum()), ai ( _ai )
571 {
572  for( int i = 0; i < 3; i++ ) {
573  ownFields[i] = 0;
574  enemyFields[i] = 0;
575  }
576 }
577 
578 int AI:: CheckFieldRecon :: run ( int x, int y)
579 {
580  initsearch ( MapCoordinate(x, y), 1 , 2 );
581  startsearch();
582  if ( ownFields[1] && !enemyFields[1] ) {
583  if ( enemyFields[2] > ownFields[2] )
584  return 0;
585  else
586  if ( enemyFields[2] )
587  return 1;
588  }
589  return -1;
590 }
591 
592 void AI::CheckFieldRecon :: testfield ( const MapCoordinate& mc )
593 {
594  FieldInformation& fi = ai->getFieldInformation ( mc.x, mc.y );
595  if( fi.control != -1 ) {
596  if ( !ai->getMap()->player[player].diplomacy.isHostile( fi.control ) )
597  ownFields[dist]++;
598  else
599  enemyFields[dist]++;
600  }
601 }
602 
603 void AI :: calcReconPositions()
604 {
605  displaymessage2("calculating reconnaissance positions ... ");
606  for ( int y = 0; y < getMap()->ysize; y++ )
607  for ( int x = 0; x < getMap()->xsize; x++ ) {
608  FieldInformation& fi = getFieldInformation ( x, y );
609  MapField* fld = getMap()->getField(x,y);
610  if ( fi.control == getPlayerNum() && !fld->building && ( !fld->vehicle || fld->vehicle->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon )) {
611  CheckFieldRecon cfr ( this );
612  int qual = cfr.run(x,y);
613  if ( qual>= 0 )
614  reconPositions[MapCoordinate ( x, y )] = qual;
615 
616  }
617  }
618 }
619 
620 void AI :: runReconUnits ( )
621 {
622 
623  vector<int> reconUnits;
624 
625  Player::VehicleList::iterator nvi;
626  for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); ++vi) {
627  Vehicle* veh = *vi;
628  if ( veh->aiparam[getPlayerNum()] && veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon )
629  reconUnits.push_back( veh->networkid );
630  }
631 
632  for ( vector<int>::iterator ru = reconUnits.begin(); ru != reconUnits.end(); ++ru ) {
633  Vehicle* veh = getMap()->getUnit(*ru);
634  if ( veh ) {
635  int maxUnitMovement = veh->typ->maxSpeed();
636 
637  // the threat posed should be enemy units should be considered for position choosing too...
638  if ( veh->aiparam[getPlayerNum()] && veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon ) {
639  if ( reconPositions.find ( veh->getPosition()) == reconPositions.end()) {
640  // the unit is not standing on a reconposition
641  int mindist = maxint;
642  MapCoordinate mc;
643  if ( !reconPositions.empty() ) {
644  AStar3D ast ( getMap(), veh, false, maxUnitMovement );
646  for ( ReconPositions::iterator i = reconPositions.begin(); i != reconPositions.end(); i++ ) {
647  MapField* fld = getMap()->getField( i->first );
648  if ( !fld->vehicle && !fld->building ) {
649  if ( ast.getFieldAccess( i->first ) ) {
650  int vdist = beeline ( veh->getPosition(), i->first )*(1+i->second/2);
651  if( vdist < mindist ) {
652  mindist = vdist;
653  mc = i->first;
654  }
655  }
656  }
657  }
658  }
659  if( mindist < maxint ) {
660  veh->aiparam[getPlayerNum()]->dest = MapCoordinate3D(mc, veh->height);
662  runUnitTask ( veh );
663  }
664  }
665  }
666  }
667  }
668 }
669 
670 AI::UnitDistribution::Group AI::getUnitDistributionGroup ( VehicleType* vt )
671 {
672  switch ( chooseJob ( vt ).front() ) {
673  case AiParameter::job_supply : return UnitDistribution::service;
674  case AiParameter::job_recon : return UnitDistribution::recon;
675  case AiParameter::job_conquer: return UnitDistribution::conquer;
677  case AiParameter::job_guard: {
678  bool range = false;
679  for ( int w = 0; w < vt->weapons.count; w++ )
680  if ( vt->weapons.weapon[w].offensive() )
681  if ( vt->weapons.weapon[w].maxdistance >= 2 * minmalq )
682  range = true;
683  if ( range )
684  return UnitDistribution::rangeattack;
685  else
687  }
688  default:;
689  } //switch job
690  return UnitDistribution::other;
691 }
692 
693 
694 AI::UnitDistribution::Group AI::getUnitDistributionGroup ( Vehicle* veh )
695 {
696  if ( veh->aiparam[getPlayerNum()] )
697  switch ( veh->aiparam[getPlayerNum()]->getJob() ) {
698  case AiParameter::job_supply : return UnitDistribution::service;
699  case AiParameter::job_recon : return UnitDistribution::recon;
700  case AiParameter::job_conquer: return UnitDistribution::conquer;
702  case AiParameter::job_guard: {
703  bool range = false;
704  for ( int w = 0; w < veh->typ->weapons.count; w++ )
705  if ( veh->typ->weapons.weapon[w].offensive() )
706  if ( veh->typ->weapons.weapon[w].maxdistance >= 2 * minmalq )
707  range = true;
708  if ( range )
709  return UnitDistribution::rangeattack;
710  else
712  }
713  default:;
714  } //switch job
715  return UnitDistribution::other;
716 }
717 
718 void AI::UnitDistribution::read ( tnstream& stream )
719 {
720  int version = stream.readInt();
721  if ( version == 15000 ) {
722  int gc = stream.readInt();
723  calculated = stream.readInt();
724  for ( int i = 0; i< gc; i++ )
725  group[i] = stream.readFloat();
726 
727  for ( int i = gc; i < groupCount; i++ )
728  group[i] = 0;
729  }
730 }
731 
732 void AI::UnitDistribution::write ( tnstream& stream ) const
733 {
734  stream.writeInt ( 15000 );
735  stream.writeInt ( groupCount );
736  stream.writeInt ( calculated );
737  for ( int i = 0; i < groupCount; i++ )
738  stream.writeFloat ( group[i] );
739 }
740 
741 
742 AI::UnitDistribution AI::calcUnitDistribution ()
743 {
744  UnitDistribution unitDistribution;
745  int unitCount = getPlayer().vehicleList.size();
746  if ( unitCount ) {
747  float inc = float(1) / float(unitCount);
748  for ( Player::VehicleList::iterator i = getPlayer().vehicleList.begin(); i != getPlayer().vehicleList.end(); i++ )
749  unitDistribution.group[ getUnitDistributionGroup ( *i )] += inc;
750 
751  }
752  unitDistribution.calculated = true;
753  return unitDistribution;
754 }
755 
756 
757 void AI::production()
758 {
759  /*
760  int unitCount = getPlayer().vehicleList.size();
761  float inc;
762  if ( unitCount )
763  inc = float(1) / float(unitCount);
764  else
765  inc = 1;
766  */
767 
768  // UnitDistribution currentUnitDistribution = calcUnitDistribution();
769 
770  // we can't have enough attacking units
771  // currentUnitDistribution.group[ UnitDistribution::attack ] = 0;
772 
773  displaymessage2("producing units ... ");
774 
775  AiThreat enemyThreat;
776  float enemyValue[aiValueTypeNum];
777  for ( int i = 0; i < aiValueTypeNum; i++ )
778  enemyValue[i] = 0;
779 
780  for ( int p = 0; p < 8; p++ )
781  if ( getMap()->player[p].diplomacy.isHostile( getPlayerNum() ) )
782  for ( Player::VehicleList::iterator vli = getMap()->player[p].vehicleList.begin(); vli != getMap()->player[p].vehicleList.end(); vli++ ) {
783  if ( (*vli)->aiparam[getPlayerNum()] ) {
784  enemyThreat += (*vli)->aiparam[getPlayerNum()]->threat;
785  enemyValue[(*vli)->aiparam[getPlayerNum()]->valueType] += (*vli)->aiparam[getPlayerNum()]->getValue();
786  }
787  }
788 
789 
790  int emptyCount = 0;
791  for ( int i = 0; i < aiValueTypeNum; i++ )
792  if ( enemyValue[i] == 0)
793  emptyCount++;
794 
795  // there are no enemies; the ai doesn't know what to produce
796  if ( emptyCount == aiValueTypeNum )
797  return ;
798 
799 
800 
801  typedef multimap<float,ProductionRating> Produceable;
802  Produceable produceable;
803 
804  for ( Player::BuildingList::iterator bli = getPlayer().buildingList.begin(); bli != getPlayer().buildingList.end(); bli ++ ) {
805  Building* bld = *bli;
806  for ( int i = 0; i < bld->getProduction().size(); i++ )
807  if ( bld->getProduction()[i] && bld->vehicleUnloadable ( bld->getProduction()[i] )) {
808  const VehicleType* typ = bld->getProduction()[i];
809  float rating = 0;
810  for ( int j = 0; j < aiValueTypeNum; j++ )
811  rating += enemyValue[j] * typ->aiparam[getPlayerNum()]->threat.threat[j];
812 
813  int danger = 1;
814  if ( typ->aiparam[getPlayerNum()]->getValue() ) {
815  if ( typ->aiparam[getPlayerNum()]->getValue() < enemyThreat.threat[ typ->aiparam[getPlayerNum()]->valueType] )
816  danger = enemyThreat.threat[ typ->aiparam[getPlayerNum()]->valueType] / typ->aiparam[getPlayerNum()]->getValue();
817  }
818 
819  rating /= 1 + log ( double(danger) );
820 
821  UnitTypeSuccess::iterator uts = unitTypeSuccess.find ( bld->getProduction()[i]->id );
822  if ( uts != unitTypeSuccess.end() ) {
823  if ( uts->second.second >= 1 )
824  rating *= uts->second.first / uts->second.second;
825  }
826 
827 
828  int cost = 0;
829  for ( int j = 0; j < resourceTypeNum; j++ )
830  cost += typ->productionCost.resource(j);
831 
832  if ( cost )
833  rating /= cost;
834 
835  ProductionRating pr = { typ, bld, rating };
836  produceable.insert ( make_pair(rating, pr));
837  }
838  }
839 
840  if ( !produceable.empty() ) {
841 
843 
844  bool produced;
845  do {
846  produced = false;
847 // for ( int i = 0; i < UnitDistribution::groupCount; i++ ) {
848 // if ( currentUnitDistribution.group[i] < originalUnitDistribution.group[i] ) {
849  for ( Produceable::reverse_iterator p = produceable.rbegin(); p != produceable.rend(); p++ ) {
850 // if ( getUnitDistributionGroup ( p->second.vt) == i ) {
851  ProductionRating& pr = p->second;
852 
853  if ( find ( lockedBuildings.begin(), lockedBuildings.end(), pr.bld ) == lockedBuildings.end()) {
854  ContainerConstControls bc( pr.bld );
855  int lack = bc.unitProductionPrerequisites( pr.vt, true );
856  if ( !lack && pr.bld->vehicleUnloadSystem ( pr.vt, 255 ) ) {
857  try {
858  ConstructUnitCommand* cuc = new ConstructUnitCommand( pr.bld );
860  cuc->setVehicleType( pr.vt );
861  cuc->execute( getContext() );
862  Vehicle* veh = cuc->getProducedUnit();
863  if ( veh ) {
864 
865  auto_ptr<ServiceCommand> sc ( new ServiceCommand( pr.bld ));
866  sc->setDestination( veh );
867  sc->getTransferHandler().fillDest();
868  sc->saveTransfers();
869  ActionResult res = sc->execute( getContext() );
870  if ( res.successful() )
871  sc.release();
872 
873  calculateThreat ( veh );
874  container ( pr.bld );
875  // currentUnitDistribution.group[i] += inc;
876  produced = true;
877  break; // exit produceable loop
878  }
879  } catch ( ActionResult res ) {
880  // just ignore any errors
881  }
882  } else {
883 
884  // the ai will save for move expensive units
885  if ( !(lack & ( 1<<10 ))) {
886  if ( pr.bld->getResource ( pr.vt->productionCost, 1 ) + pr.bld->netResourcePlus( ) * config.waitForResourcePlus >= pr.vt->productionCost )
887  for ( int r = 0; r < resourceTypeNum; r++ )
888  if ( lack & (1 << r )) {
889  GetConnectedBuildings gcb ( lockedBuildings, getMap(), r );
890  gcb.start ( pr.bld->getEntry().x, pr.bld->getEntry().y );
891  }
892  sort ( lockedBuildings.begin(), lockedBuildings.end());
893  unique( lockedBuildings.begin(), lockedBuildings.end());
894  }
895  }
896  }
897  // } // else
898  // printf(" %s \n", p->second.vt->description );
899  }
900  // }
901  // }
902  } while ( produced );
903  }
904 
905 }
906 
907 
void findAllAccessibleFields()
searches for all fields that are within the range of maxDist and marks them.
Definition: astar2.cpp:562
int fuel
Definition: typen.h:101
SaveUnitMovement(Vehicle *veh)
Definition: ai/misc.cpp:125
int xsize
the size of the map
Definition: gamemap.h:201
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
int getValueType(int uheight) const
For the AI: calculating the ValueType if the unit was on the height uheight.
Definition: vehicle.h:389
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
void setVehicleType(const VehicleType *type)
GameMap * getMap(void)
returns the map this AI runson
Definition: ai.h:486
#define npush(a)
Definition: stack.h:53
the unit will not interrupt the movement if it runs onto a mine of into reaction fire ...
Vehicle * vehicle
Definition: mapfield.h:89
bool isHostile(PlayerID towardsPlayer) const
Definition: player.h:80
A 3D path finding algorithm which tries to keep the units hidden from view.
Definition: ai_common.h:96
#define minfloat
Definition: typen.h:466
AiParameter * aiparam[8]
Definition: vehicle.h:182
static bool moveVariantComp(const AI::MoveVariant *mv1, const AI::MoveVariant *mv2)
Definition: tactics.cpp:178
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
VisitedContainer visited
Definition: astar2.h:122
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 ...
DiplomaticStateVector diplomacy
Definition: player.h:209
void setMovement(int newmove, double cargoDivisor=-1)
sets a new distance that the unit can move
Definition: vehicle.cpp:527
int getOwner() const
returns the number of the player this vehicle/building belongs to
int getNumericalHeight() const
Definition: typen.h:242
MapCoordinate3D getPosition() const
returns the units position
Definition: vehicle.cpp:1552
#define chhochfliegend
Definition: typen.h:416
storage_t::iterator iterator
Definition: astar2.h:104
SingleWeapon weapon[16]
Definition: vehicletype.h:170
ContainerBase * getContainer()
returns a pointer to the ContainerBase of the field or NULL if there is none
Definition: mapfield.cpp:331
The interface for all kinds of IO stream.
a single field of the map
Definition: mapfield.h:26
Definition: ai.h:44
if(!yyg->yy_init)
Definition: scanner.cpp:695
int threat[aiValueTypeNum]
void setNewHeight()
Definition: gamemap.cpp:2135
friend class CheckFieldRecon
Definition: ai.h:198
const Production & getProduction() const
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
const int aiValueTypeNum
how many different target types are there?
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
virtual float readFloat(void)
Reads a flaot variable.
Definition: basestrm.cpp:328
#define maxfloat
Definition: typen.h:465
int getPlayerNum(void)
returns the number of the player which is controlled by this ai
Definition: ai.h:490
The class describing properties that are common to all vehicles of a certain kind.
Definition: vehicletype.h:177
#define maxmalq
Constants that specify the layout of ASC.
Definition: typen.h:429
MapCoordinate3D getPosition3D() const
returns the units position; if inside building then Height is -1
Definition: vehicle.cpp:1557
const Node * previous
Definition: astar2.h:63
void clearJobs()
Definition: gamemap.cpp:2163
int vehicleUnloadable(const VehicleType *vehicleType, int carrierHeight=-1) const
checks the unloading of a unit type
VehicleList vehicleList
a list of all units
Definition: player.h:135
ActionResult execute(const Context &context)
Definition: action.cpp:41
void setTask(Task t)
const int resourceTypeNum
The number of different resources that ASC uses.
Definition: typen.h:77
void log(const Vehicle *attacker, const Vehicle *attackee)
Definition: attack.cpp:417
friend class Section
Definition: ai.h:448
#define chtieffliegend
Definition: typen.h:414
GameMap * getMap() const
Definition: mapfield.h:38
Coordinate on the twodimensional map.
Definition: typen.h:202
the threat that a unit poses against other units.
Player & getPlayer(void)
Definition: ai.h:492
bool canStop
Definition: astar2.h:68
A 3D path finding algorithm which avoids units to jam; used by the AI's strategy module.
Definition: ai_common.h:64
void displaymessage(const char *formatstring, int num,...)
displays a dialog box with a message
Definition: dlg_box.cpp:1849
searches fields in hexagonal "circles" around a field and calls testfield for each field ...
Definition: mapalgorithms.h:28
static bool avail(Vehicle *eht)
int maxdistance
the maximum distance the weapon can shoot
Definition: vehicletype.h:111
void resetTask()
Definition: gamemap.cpp:2097
int getValue()
bool successful() const
#define chfahrend
Definition: typen.h:413
AiThreat threat
Vehicle * getUnit(int x, int y, int nwid)
Definition: gamemap.cpp:1215
Player player[9]
Definition: gamemap.h:253
#define npop(a)
Definition: stack.h:54
int ysize
Definition: gamemap.h:201
void attack(Vehicle *veh, const MapCoordinate &target)
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
AiValue * aiparam[8]
some information the AI stores about this unit
Definition: vehicletype.h:265
void displaymessage2(const char *formatstring,...)
displays a message in the status line of ASC
int color
The owner of the container.
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 getFieldAccess(int x, int y)
Definition: astar2.cpp:582
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
bool offensive(void) const
virtual void writeFloat(float f)
Write a floating point variable.
Definition: basestrm.cpp:385
A 3D path finding algorithm, based on the 2D algorithm by Amit J. Patel.
Definition: astar2.h:19
#define maxint
Definition: typen.h:462
The parent class of Vehicle and Building; The name Container originates from Battle Isle...
Definition: containerbase.h:40
An actual building on the map, which references a BuildingType Buildings have an owner,.
Definition: buildings.h:38
const T & min(const T &a, const T &b, const T &c)
Definition: misc.h:80
const Node * find(const MapCoordinate3D &pos)
Definition: astar2.h:110
MapCoordinate3D dest
const Cargo & getCargo() const
int ypos
Definition: vehicle.h:124
int maxSpeed() const
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
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
A 3D path finding algorithm which avoids units to jam; used by the AI's strategy module.
Definition: ai_common.h:79
#define minmalq
Definition: typen.h:430
MapField * getField(int x, int y)
Definition: gamemap.h:465
vector< Building * > BuildingContainer
Definition: resourcenet.h:69
MapCoordinate3D h
Definition: astar2.h:64