File: buildingcapture.cpp

package info (click to toggle)
asc 2.4.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 75,080 kB
  • ctags: 24,943
  • sloc: cpp: 155,023; sh: 8,829; ansic: 6,890; makefile: 650; perl: 138
file content (340 lines) | stat: -rw-r--r-- 13,246 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/***************************************************************************
                          buildingcapture.cpp  -  description
                             -------------------
    begin                : Fri Mar 30 2001
    copyright            : (C) 2001 by Martin Bickel
    email                : bickel@asc-hq.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "ai_common.h"

#include "../actions/moveunitcommand.h"

float AI :: getCaptureValue ( const Building* bld, Vehicle* veh  )
{
   HiddenAStar ast ( this, veh );
   HiddenAStar::Path path;
   ast.findPath ( path, bld->getEntry().x, bld->getEntry().y );
   if ( ast.getTravelTime() >= 0 )
      // everything else being equal, prefer cheapest unit
      // TODO: factor 0.0001 should be made configurable
      return getCaptureValue ( bld, ast.getTravelTime() )-0.0001*veh->aiparam[getPlayerNum()]->getValue() ;
   else
      return -1;
      // return minfloat; // this makes no sense as minfloat>0!
}


void AI :: BuildingCapture :: write ( tnstream& stream ) const
{
  stream.writeInt( 20 );
  stream.writeInt ( state );
  stream.writeInt ( unit );
  for ( vector<int>::const_iterator i = guards.begin(); i  != guards.end(); i++ ) {
     stream.writeInt ( 1 );
     stream.writeInt ( *i );
  }
  stream.writeInt ( 0 );
  stream.writeFloat ( captureValue );
  stream.writeInt ( nearestUnit );
}

void AI :: BuildingCapture :: read ( tnstream& stream )
{
  stream.readInt(); // version
  state = BuildingCaptureState( stream.readInt ( ));
  unit = stream.readInt ( );
  int i = stream.readInt ();
  while ( i ) {
     guards.push_back ( stream.readInt() );
     i = stream.readInt();
  }
  captureValue = stream.readFloat ();
  nearestUnit = stream.readInt ();
}



class  SearchReconquerBuilding : public SearchFields {
                                protected:
                                   AI& ai;
                                   Building* buildingToCapture;
                                   int mode;        // (1): nur fusstruppen; (2): 1 und transporter; (3): 2 und geb�ude
                                   vector<Vehicle*> enemyUnits; // that can conquer the building
                                   float getThreatValueOfUnit ( Vehicle* veh );
                                public:
                                   void testfield ( const MapCoordinate& mc );
                                   bool returnresult ( );
                                   void unitfound ( Vehicle* eht );
                                   bool canUnitCapture ( Vehicle* veh );
                                   SearchReconquerBuilding ( AI& _ai, Building* bld ) : SearchFields ( _ai.getMap() ), ai ( _ai ), buildingToCapture ( bld ), mode(3) {};
                                };

bool SearchReconquerBuilding :: returnresult( )
{
  return !enemyUnits.empty();
}


void         SearchReconquerBuilding :: unitfound(Vehicle*     eht)
{
  enemyUnits.push_back ( eht );
  buildingToCapture->aiparam[ai.getPlayerNum()]->setAdditionalValue ( buildingToCapture->aiparam[ai.getPlayerNum()]->getValue() );
}

bool SearchReconquerBuilding :: canUnitCapture( Vehicle* eht )
{
   return (eht->typ->hasFunction( ContainerBaseType::ConquerBuildings ) )
           && fieldAccessible ( buildingToCapture->getEntryField(), eht) == 2 ;

}

void         SearchReconquerBuilding :: testfield(const MapCoordinate& mc)
{
      Vehicle* eht = gamemap->getField(mc)->vehicle;
      if ( eht )
         if ( ai.getPlayer().diplomacy.isHostile( eht->getOwner() ) ) {
            if ( canUnitCapture ( eht )) {
               if ( MoveUnitCommand::avail( eht )) {
                  MoveUnitCommand muc ( eht );
                  muc.searchFields();
                  if( muc.isFieldReachable( startPos, false ))
                     unitfound(eht);
               }
               
            }
            else
               if (mode >= 2)
                  if (eht->typ->maxLoadableUnits > 0)
                     for ( ContainerBase::Cargo::const_iterator i = eht->getCargo().begin(); i != eht->getCargo().end(); ++i )
                        if ( *i )
                           if ( canUnitCapture ( *i ))
                              if (eht->maxMovement() + (*i)->maxMovement() >= beeline(mc, startPos))
                                 unitfound(eht);

         }
/*
      if ( bld )
         if ( mode >= 3 )
            if (getdiplomaticstatus(bld->color) != capeace)
               for ( int w = 0; w <= 31; w++)
                  if ( bld->loading[w] )
                     if ( canUnitCapture ( bld->loading[w] ))
                        if ( bld->loading[w]->typ->movement[log2(bld->loading[w]->height)] <= beeline(xp,yp,startx,starty))
                           unitfound ( bld->loading[w] );

*/
}


float AI :: getCaptureValue ( const Building* bld, int traveltime  )
{
   if ( traveltime < 0 )
      traveltime = 0;
   return float(bld->aiparam[getPlayerNum()]->getValue()) / float(traveltime+1);
}


bool AI :: checkReConquer ( Building* bld, Vehicle* veh )
{
   SearchReconquerBuilding srb ( *this, bld );
   srb.initsearch ( bld->getEntry(), (maxTransportMove + maxUnitMove/2) / maxmalq + 1, 1 );
   srb.startsearch();
   bool enemyNear = srb.returnresult();

   if ( enemyNear && veh ) {
      float f = 0;
      for ( ContainerBase::Cargo::const_iterator i = bld->getCargo().begin(); i != bld->getCargo().end(); ++i )
         if ( *i )
            if ( (*i)->getMovement() )
               f += (*i)->aiparam[ getPlayerNum()]->getValue();

      //! if the units inside the building are more worth than the own unit, capture the building regardless of whether it can be recaptured
      if ( f > veh->aiparam[getPlayerNum()]->getValue())
         return false;
      else
         return true;
   }
   
   return false;
}


struct CaptureTriple {
  Building* bld;
  Vehicle* veh;
  float val;
};

typedef struct CaptureTriple* pCaptureTriple;

typedef vector<pCaptureTriple> CaptureList;

class CaptureTripleComp : public binary_function<pCaptureTriple,pCaptureTriple,bool> {
public:
  explicit CaptureTripleComp() {};
  bool operator() (const pCaptureTriple t1, const pCaptureTriple t2) const {
    return t1->val > t2->val;
  }
};

void AI :: checkConquer( )
{
   // remove all capture orders for buildings which are no longer controlled by the enemy

   for ( BuildingCaptureContainer::iterator bi = buildingCapture.begin(); bi != buildingCapture.end(); ) {
      BuildingCaptureContainer::iterator nxt = bi;
      ++nxt;
      Vehicle* veh= getMap()->getUnit ( bi->second.unit );
      Building* bld = getMap()->getField( bi->first )->building;
      if ( !bld ) {
         buildingCapture.erase ( bi );
         bi = nxt;
         continue;
      }

      if ( !getPlayer(bld->getOwner()).diplomacy.isHostile( getPlayerNum() ) 
           || !( veh && fieldAccessible ( getMap()->getField( bi->first ), veh ) == 2 )) {

         if ( veh ) {
            veh->aiparam[getPlayerNum()]->resetTask ();
            veh->aiparam[getPlayerNum()]->setNextJob();
         }
         buildingCapture.erase ( bi );
      } else
         if ( veh && veh->color != getPlayerNum()*8 )
            buildingCapture.erase ( bi );

      bi = nxt;
   }

   displaymessage2("check for capturing buildings ... ");

   // check for stagnation
   int num_reachable_buildings=0;
   for ( BuildingCaptureContainer::iterator bi = buildingCapture.begin(); bi != buildingCapture.end(); bi++ ) 
      if ( bi->second.state!=BuildingCapture::conq_unreachable ) num_reachable_buildings++;
   // if all blds are marked as unreachable, reevaluate in hope for a map-change
   if ( buildingCapture.size()>0 && num_reachable_buildings==0 ) {
      for ( BuildingCaptureContainer::iterator bi = buildingCapture.begin(); bi != buildingCapture.end(); bi++ ) 
        bi->second.state=BuildingCapture::conq_noUnit;
   }
   
   CaptureList captureList;

   int buildingCounter = 0;

   for ( int c = 0; c <= 8; c++ ) {
      if ( c<8 ) {
         if ( !getPlayer(c).exist() ) continue;
         if ( !getPlayer().diplomacy.isHostile( c)  ) continue;
      }
      for ( Player::BuildingList::iterator bi = getPlayer(c).buildingList.begin(); bi != getPlayer(c).buildingList.end(); bi++ ) {
         Building* bld = *bi;
         int reachable = 0;
         if ( buildingCapture[ bld->getEntry() ].state != BuildingCapture::conq_noUnit ) continue;
         bool enemyNear = checkReConquer ( bld, 0 );

         ++buildingCounter;
         displaymessage2("check for capturing building %d ", buildingCounter);

         for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); vi++ ) {
            Vehicle* veh = *vi;
            if ( !veh->canMove() ) continue;
            if ( fieldAccessible ( bld->getEntryField(), veh ) != 2 ) continue;
            if ( c!=8 && !(veh->typ->hasFunction( ContainerBaseType::ConquerBuildings  )) ) continue;
            if ( veh->aiparam[getPlayerNum()]->hasJob( AiParameter::job_conquer)  &&
                 veh->aiparam[getPlayerNum()]->getTask() != AiParameter::tsk_nothing ) continue;

            // here, units can be excluded from capturing
            if ( c!=8 ) {
                if( !veh->aiparam[getPlayerNum()]->hasJob(AiParameter::job_conquer)  ) continue;
                if( veh->aiparam[getPlayerNum()]->getTask() != AiParameter::tsk_nothing ) continue;
            }

            // any further factors should be incorporated into getCaptureValue
            float val=getCaptureValue( bld, veh );

            // malus if enemy is near (relevant if we are short of capture-units
            // or building is practically worthless)
            // TODO: should be made an optional parameter to getCaptureValue
            if ( val>0 && enemyNear ) val -= 0.1*veh->aiparam[getPlayerNum()]->getValue();


            if ( val > 0 ) {
               pCaptureTriple triple = new CaptureTriple;
               triple->bld=bld;
               triple->veh=veh;
               triple->val=val;
               captureList.push_back( triple );
               reachable = true;
            }
         }
         if ( reachable==0 )
            buildingCapture[ bld->getEntry() ].state = BuildingCapture::conq_unreachable;
      }
   }

   sort ( captureList.begin(), captureList.end(), CaptureTripleComp() );

   for ( CaptureList::iterator i = captureList.begin(); i != captureList.end(); i++ ) {
      Building* bld = (*i)->bld;
      Vehicle* veh = (*i)->veh;
      // float val = (*i)->val;
      delete (*i);

      // check whether bld and veh are still available
      if ( buildingCapture[ bld->getEntry() ].state != BuildingCapture::conq_noUnit ) continue;
      if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer &&
           veh->aiparam[getPlayerNum()]->getTask() != AiParameter::tsk_nothing ) continue;

      // dispatch capture order
      BuildingCapture& bc = buildingCapture[ bld->getEntry() ];
      if ( veh->typ->hasFunction( ContainerBaseType::ConquerBuildings  ))
         bc.state = BuildingCapture::conq_conqUnit;
      else
         bc.state = BuildingCapture::conq_unitNotConq;
      bc.unit = veh->networkid;
      
      veh->aiparam[getPlayerNum()]->setJob ( AiParameter::job_conquer );
      veh->aiparam[getPlayerNum()]->setTask ( AiParameter::tsk_move );
      veh->aiparam[getPlayerNum()]->dest.setnum( bld->getEntry().x, bld->getEntry().y, -1 );
   }

   // execute capture orders
   for ( BuildingCaptureContainer::iterator bi = buildingCapture.begin(); bi != buildingCapture.end(); ) {
      BuildingCaptureContainer::iterator nxt = bi;
      ++nxt;
      Vehicle* veh = getMap()->getUnit ( bi->second.unit );
      if ( veh ) {
         MapCoordinate3D dest = veh->aiparam[getPlayerNum()]->dest;
         int nwid = veh->networkid;
         moveUnit ( veh, dest, true );
         if ( getMap()->getUnit ( nwid ) && veh->getPosition() == dest ) {
            veh->aiparam[getPlayerNum()]->resetTask ();
            buildingCapture.erase ( bi );
         }
      } else
         buildingCapture.erase ( bi );
      checkKeys();
      bi = nxt;
   }

   // do something useful with units that are not used for capturing buildings
   for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); vi++ )
      if ( (*vi)->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer &&
           (*vi)->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_nothing )
           (*vi)->aiparam[getPlayerNum()]->setNextJob();

}