Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

controls.cpp

Go to the documentation of this file.
00001 
00007 /*
00008     This file is part of Advanced Strategic Command; http://www.asc-hq.de
00009     Copyright (C) 1994-2005  Martin Bickel  and  Marc Schellenberger
00010 
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with this program; see the file COPYING. If not, write to the 
00023     Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
00024     Boston, MA  02111-1307  USA
00025 */
00026 
00027 #include <stdio.h>           
00028 #include <cstring>
00029 #include <math.h>
00030 #include <stdarg.h>
00031 #include <ctime>
00032 
00033 #include "buildingtype.h"
00034 #include "vehicletype.h"
00035 #include "typen.h"
00036 
00037 #include "newfont.h"
00038 #include "spfst.h"
00039 #include "loaders.h"
00040 #include "misc.h"
00041 #include "controls.h"
00042 #include "stack.h"
00043 #include "dlg_box.h"
00044 #include "dialog.h"
00045 #include "attack.h"
00046 #include "gamedlg.h"
00047 #include "gameoptions.h"
00048 #include "ai/ai.h"
00049 #include "errors.h"
00050 #include "viewcalculation.h"
00051 #include "replay.h"
00052 #include "resourcenet.h"
00053 #include "itemrepository.h"
00054 #include "strtmesg.h"
00055 #include "messagedlg.h"
00056 #include "gameevent_dialogs.h"
00057 #include "cannedmessages.h"
00058 #include "mapdisplay.h"
00059 
00060 #include "dialogs/choosetech.h"
00061 
00062 tmoveparams moveparams;
00063 
00064 void tmoveparams::reset(){
00065    movestatus = 0; 
00066    movesx = 0;
00067    movesy = 0; 
00068    moveerr = 0; 
00069    vehicletomove = NULL; 
00070    newheight = 0; 
00071    oldheight = 0; 
00072    heightdir = 0; 
00073    buildingtobuild = NULL;    
00074    movespeed = 0;
00075    uheight = 0;
00076 }
00077 
00078 
00079 /*
00080   class   tsearchexternaltransferfields : public SearchFields {
00081                       public:
00082                                 Building*            bld;
00083                                 char                    numberoffields;
00084                                 void                    searchtransferfields( Building* building );
00085                                 virtual void            testfield ( const MapCoordinate& mc );
00086                                 tsearchexternaltransferfields ( GameMap* _gamemap ) : SearchFields ( _gamemap ) {};
00087                              };
00088 
00089 void         tsearchexternaltransferfields :: testfield( const MapCoordinate& mc )
00090 { 
00091      tfield* fld  = gamemap->getField ( mc );
00092      if ( fld && fld->vehicle )
00093         if ( fld->vehicle->height & bld->typ->externalloadheight ) {
00094            numberoffields++;
00095            fld->a.temp = 123;
00096         }
00097 }
00098 
00099 
00100 void tsearchexternaltransferfields :: searchtransferfields( Building* building )
00101 {
00102    actmap->cleartemps( 7 );
00103    bld = building;
00104    numberoffields = 0;
00105    if ( bld->typ->hasFunction( ContainerBaseType::ExternalEnergyTransfer  ) ||
00106         bld->typ->hasFunction( ContainerBaseType::ExternalMaterialTransfer  ) ||
00107         bld->typ->hasFunction( ContainerBaseType::ExternalFuelTransfer  ) ||
00108         bld->typ->hasFunction( ContainerBaseType::ExternalAmmoTransfer  ) ) {
00109       initsearch( bld->getEntry(), 1, 1 );
00110       startsearch();
00111    }
00112    if ( numberoffields )
00113       moveparams.movestatus = 130;
00114 }
00115 
00116 int searchexternaltransferfields ( Building* bld )
00117 {
00118    tsearchexternaltransferfields setf ( actmap );
00119    setf.searchtransferfields ( bld );
00120    return setf.numberoffields;
00121 }
00122 */
00123 
00124 
00125 
00126   class   tsearchdestructbuildingfields : public SearchFields {
00127                       public:
00128                                 Vehicle*                vehicle;
00129                                 char                    numberoffields;
00130                                 tfield*                  startfield;
00131                                 void                    initdestructbuilding( int x, int y );
00132                                 virtual void            testfield ( const MapCoordinate& mc );
00133                                 tsearchdestructbuildingfields ( GameMap* _gamemap ) : SearchFields ( _gamemap ) {};
00134                              };
00135 
00136 
00137 void         tsearchdestructbuildingfields::initdestructbuilding( int x, int y )
00138 {
00139    Vehicle*     eht = getfield(x,y)->vehicle;
00140    vehicle = eht;
00141    if (eht->attacked || (eht->typ->wait && eht->hasMoved() )) {
00142       dispmessage2(305,NULL);
00143       return;
00144    }
00145    actmap->cleartemps(7);
00146    initsearch( MapCoordinate(x,y), 1, 1 );
00147    numberoffields = 0;
00148    startfield = getfield(x,y);
00149    startsearch();
00150    if (numberoffields > 0) {
00151       moveparams.movestatus = 115;
00152       moveparams.vehicletomove = eht;
00153    }
00154    else {
00155       dispmessage2(306,"");
00156    }
00157 }
00158 
00159 
00160 void         tsearchdestructbuildingfields::testfield(const MapCoordinate& mc)
00161 {
00162    startfield = gamemap->getField(mc);
00163    if (startfield->building && getheightdelta(log2(vehicle->height), log2(startfield->building->typ->buildingheight)) == 0 && !startfield->building->typ->buildingNotRemovable ) {
00164       numberoffields++;
00165       startfield->a.temp = 20;
00166    }
00167 }
00168 
00169 
00170 
00171 
00172 
00173 void         destructbuildinglevel1(int xp, int yp)
00174 {
00175    tsearchdestructbuildingfields   sdbf ( actmap );
00176    sdbf.initdestructbuilding( xp, yp  );
00177 }
00178 
00179 Resources getDestructionCost( Building* bld, Vehicle* veh )
00180 {
00181    Resources r;
00182    r.material = - bld->typ->productionCost.material * (100 - bld->damage) / destruct_building_material_get / 100;
00183    r.fuel = destruct_building_fuel_usage * veh->typ->fuelConsumption;
00184    return r;
00185 }
00186 
00187 void         destructbuildinglevel2( int xp, int yp)
00188 {
00189    tfield* fld = getfield(xp,yp);
00190    if (fld->a.temp == 20)
00191       if (moveparams.movestatus == 115) {
00192          actmap->cleartemps(7);
00193          Vehicle* eht = moveparams.vehicletomove;
00194 
00195          Building* bb = fld->building;
00196          Resources res = eht->getResource( getDestructionCost( bb, eht ), false);
00197 
00198          eht->setMovement ( 0 );
00199          eht->attacked = 1;
00200 
00201          if ( bb->getCompletion() ) {
00202             bb->setCompletion ( bb->getCompletion()-1 );
00203          } else {
00204             bb->netcontrol = cnet_stopenergyinput + (cnet_stopenergyinput << 1) + (cnet_stopenergyinput << 2);
00205             Resources put = bb->putResource( bb->actstorage, false );
00206             delete bb;
00207          }
00208          logtoreplayinfo ( rpl_removebuilding3, xp, yp, eht->networkid, res.energy, res.material, res.fuel );
00209          computeview( actmap );
00210          displaymap();
00211          moveparams.movestatus = 0;
00212       }
00213 }
00214 
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00223    class tputmine : public SearchFields {
00224                        int player;
00225                 public:
00226                        char             mienentyp;
00227                        char             mienenlegen, mienenraeumen;
00228                        char             numberoffields;
00229                        virtual void     testfield ( const MapCoordinate& mc );
00230                        int              initpm( char mt, const Vehicle* eht );
00231                        void             run ( void );
00232                        tputmine ( GameMap* _gamemap ) : SearchFields ( _gamemap ) {};
00233               };
00234 
00235 
00236 void         tputmine::testfield(const MapCoordinate& mc)
00237 {
00238    tfield* fld = gamemap->getField(mc);
00239    if ( !fld->vehicle  &&  !fld->building && fieldvisiblenow( fld, player )) {
00240       fld->a.temp = 0;
00241       if ( !fld->mines.empty() ) {
00242          fld->a.temp += 2;
00243          numberoffields++;
00244       }
00245       if (mienenlegen && (fld->mines.empty() || fld->mineowner() == player) && fld->mines.size() < gamemap->getgameparameter ( cgp_maxminesonfield )) {
00246          fld->a.temp += 1;
00247          numberoffields++;
00248       }
00249    }
00250 }
00251 
00252 
00253 
00254 
00255 int          tputmine::initpm(  char mt, const Vehicle* eht )
00256 {
00257    numberoffields = 0;
00258    mienenlegen = false;
00259    mienenraeumen = false;
00260 
00261    const SingleWeapon* weapon = NULL;
00262 
00263    if (eht->typ->weapons.count > 0)
00264       for ( int i = 0; i <= eht->typ->weapons.count - 1; i++)
00265          if ((eht->typ->weapons.weapon[i].getScalarWeaponType() == cwminen) && eht->typ->weapons.weapon[i].shootable() && (eht->typ->weapons.weapon[i].sourceheight & eht->height) ) {
00266             mienenraeumen = true;
00267             if (eht->ammo[i] > 0)
00268                mienenlegen = true;
00269             weapon = &eht->typ->weapons.weapon[i];
00270          }
00271    player = eht->color / 8;
00272    mienentyp = mt;
00273    if (eht->getMovement() < mineputmovedecrease) {
00274       mienenlegen = false;
00275       mienenraeumen = false;
00276       return -119;
00277    }
00278    if (mienenlegen || mienenraeumen)
00279       initsearch( eht->getPosition(), (weapon->mindistance + maxmalq-1) / maxmalq, weapon->maxdistance / maxmalq );
00280    return 0;
00281 }
00282 
00283 
00284 void         tputmine::run(void)
00285 {
00286    if ((mienenlegen || mienenraeumen)) {
00287       startsearch();
00288       if (numberoffields > 0) {
00289          moveparams.movestatus = 90;
00290       }
00291    }
00292 }
00293 
00294 
00295 
00296 
00297 
00298 
00299 void  putMine( const MapCoordinate& pos, int typ, int delta )
00300 {
00301    if (moveparams.movestatus == 0) {
00302       Vehicle* veh = actmap->getField(pos)->vehicle; 
00303       if ( !veh || veh->color != (actmap->actplayer << 3))
00304          return;
00305          
00306       moveparams.vehicletomove = veh;
00307          
00308       tputmine ptm ( actmap );
00309       int res = ptm.initpm(typ,veh);
00310       ptm.run();
00311       if ( res < 0 )
00312          dispmessage2 ( -res );
00313    }
00314    else
00315       if (moveparams.movestatus == 90) {
00316          Vehicle* eht = moveparams.vehicletomove;
00317          tfield* fld = actmap->getField(pos);
00318          if ( fld->a.temp ) {
00319 
00320             if ( (fld->a.temp & 1) && ( delta > 0 )) {
00321                const Vehicletype* fzt = eht->typ;
00322                int  strength = 64;
00323                for ( int i = 0; i < fzt->weapons.count ; i++)
00324                   if ((fzt->weapons.weapon[i].getScalarWeaponType() == cwminen) && fzt->weapons.weapon[i].shootable() )
00325                      if ( fld-> putmine( actmap->actplayer, typ, MineBasePunch[typ-1] * strength / 64 )) {
00326                         eht->ammo[i]--;
00327                         eht->setMovement ( eht->getMovement() - mineputmovedecrease );
00328                         strength = eht->weapstrength[i];
00329                         logtoreplayinfo ( rpl_putmine2, pos.x, pos.y, (int) actmap->actplayer, (int) typ, (int) MineBasePunch[typ-1] * strength / 64, eht->networkid );
00330                         break;
00331                      }
00332 
00333 
00334             }
00335 
00336             if ( (fld->a.temp & 2) && ( delta < 0 )) {
00337                tfield* fld = actmap->getField(pos);
00338                fld->removemine( -1 );
00339                eht->decreaseMovement ( mineremovemovedecrease );
00340                logtoreplayinfo ( rpl_removemine, pos.x, pos.y );
00341             }
00342             actmap->cleartemps(7);
00343             computeview( actmap );
00344             moveparams.movestatus = 0;
00345             displaymap();
00346          }
00347       }
00348 }
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 /*
00357 void         refuelvehicle(int         b)
00358 {
00359    Vehicle*     actvehicle;
00360 
00361    if (moveparams.movestatus == 0) {
00362 
00363       trefuelvehicle rfe;
00364       rfe.initrefuelling(getxpos(),getypos(),b);
00365       rfe.startsearch();
00366 
00367    }
00368    else {
00369       if (moveparams.movestatus == 65) {
00370          if (getactfield()->a.temp > 0) {
00371             actvehicle = getfield(moveparams.movesx,moveparams.movesy)->vehicle;
00372             verlademunition(getactfield()->vehicle,actvehicle,NULL,3 - b);
00373             actmap->cleartemps(7);
00374             moveparams.movestatus = 0;
00375          }
00376       }
00377       else
00378          if (moveparams.movestatus == 66)
00379             if (getactfield()->a.temp > 0) {
00380                actvehicle = getfield(moveparams.movesx,moveparams.movesy)->vehicle;
00381                // actvehicle->repairunit( getactfield()->vehicle );
00382                actmap->cleartemps(7);
00383                moveparams.movestatus = 0;
00384             }
00385       updateFieldInfo();
00386    }
00387 
00388 }
00389 */
00390 
00391 
00392 
00393 
00394 int windbeeline ( const MapCoordinate& start, const MapCoordinate& dest, WindMovement* wm ) {
00395    int x1 = start.x;
00396    int y1 = start.y;
00397    int dist = 0;
00398    while ( x1 != dest.x  || y1 != dest.y ) {
00399       dist+= minmalq;
00400       int direc = getdirection ( x1, y1, dest.x, dest.y );
00401       dist -= wm->getDist(direc);
00402       getnextfield ( x1, y1, direc );
00403    }
00404    return dist;
00405 }
00406 
00407 
00408 
00409 
00410 
00411 
00412 
00413 
00414 
00415 
00416 
00417 
00418 
00419 
00420 pair<int,int> calcMoveMalus( const MapCoordinate3D& start,
00421                             const MapCoordinate3D& dest,
00422                             const Vehicle*     vehicle,
00423                             WindMovement* wm,
00424                             bool*  inhibitAttack,
00425                             bool container2container )
00426 {
00427    int direc = getdirection ( start.x, start.y, dest.x, dest.y );
00428 
00429 
00430    int fuelcost = 10;
00431    int movecost;
00432    bool checkHemming = true;
00433    bool checkWind = wm != NULL;
00434    int dist = 1;
00435 
00436    if ( start.getNumericalHeight() >= 0 && dest.getNumericalHeight() >= 0 ) {
00437 
00438       // changing height
00439       if ( (start.getNumericalHeight() != dest.getNumericalHeight()) && !container2container ) {
00440           const Vehicletype::HeightChangeMethod* hcm = vehicle->getHeightChange( start.getNumericalHeight() < dest.getNumericalHeight() ? 1 : -1, start.getBitmappedHeight());
00441           if ( !hcm || hcm->dist != beeline ( start, dest )/maxmalq )
00442              fatalError("Calcmovemalus called with invalid height change distance");
00443           dist = hcm->dist;
00444           movecost = hcm->moveCost;
00445           fuelcost = max(hcm->dist*10,10);
00446           if ( inhibitAttack && !hcm->canAttack )
00447             *inhibitAttack = !hcm->canAttack;
00448           checkHemming = false;
00449           if ( start.getNumericalHeight() < 4 || dest.getNumericalHeight() < 4 )
00450              checkWind = false;
00451       } else
00452          // flying
00453          if (start.getNumericalHeight() >= 4 )
00454             movecost = maxmalq;
00455          else
00456             if ( start.getNumericalHeight() <= 1 ) {
00457                movecost = submarineMovement;
00458                checkWind = false;
00459             } else {
00460                // not flying
00461                tfield* fld = vehicle->getMap()->getField( dest.x, dest.y );
00462                if ( fld->building )
00463                   movecost = maxmalq;
00464                else
00465                   movecost = fld->getmovemalus( vehicle );
00466                checkWind = false;
00467             }
00468 
00469    } else
00470       if ( dest.getNumericalHeight() >= 0 ) {
00471         // moving out of container
00472         int mm = vehicle->getMap()->getField( start.x, start.y )->getContainer()->vehicleUnloadSystem( vehicle->typ, dest.getBitmappedHeight() )->movecost;
00473         if ( mm > 0 )
00474             movecost = mm;
00475         else {
00476             if ( dest.getNumericalHeight() >= 4 )
00477                // flying
00478                movecost = maxmalq;
00479             else {
00480                if ( dest.getNumericalHeight() <= 1 ) {
00481                   movecost = submarineMovement;
00482                   checkWind = false;
00483                } else {
00484                   movecost = vehicle->getMap()->getField( dest.x, dest.y )->getmovemalus( vehicle );
00485                }
00486             }
00487         }
00488       } else {
00489         // moving from one container to another
00490         movecost = maxmalq;
00491         checkHemming = false;
00492         checkWind = false;
00493       }
00494 
00495    static const  int         movemalus[6]  = { 0, 3, 5, 0, 5, 3 };
00496    
00497    if ( checkHemming )
00498       for (int c = 0; c < sidenum; c++) {
00499          int x = dest.x;
00500          int y = dest.y;
00501          getnextfield( x,  y, c );
00502          tfield* fld = vehicle->getMap()->getField ( x, y );
00503          if ( fld ) {
00504            int d = (c - direc);
00505 
00506            if (d >= sidenum)
00507               d -= sidenum;
00508 
00509            if (d < 0)
00510               d += sidenum;
00511 
00512            tfield* fld = vehicle->getMap()->getField(x,y);
00513            if ( fld->vehicle && dest.getNumericalHeight() >= 0 ) {
00514               if ( vehicle->getMap()->getPlayer(vehicle).diplomacy.isHostile( fld->vehicle->getOwner() ) )
00515                  if ( attackpossible28(fld->vehicle,vehicle, NULL, dest.getBitmappedHeight() ))
00516                     movecost += movemalus[d];
00517               
00518            }
00519          }
00520       }
00521 
00522     /*******************************/
00523     /*    Wind calculation         */
00524     /*******************************/
00525    if ( wm && checkWind && direc >= 0 && direc < 5 )
00526       if (dest.getNumericalHeight() >= 4 && dest.getNumericalHeight() <= 6 &&
00527           start.getNumericalHeight() >= 4 && start.getNumericalHeight() <= 6 &&
00528           actmap->weather.windSpeed  ) {
00529          movecost -=  wm->getDist( direc ) * dist;
00530          fuelcost -=  wm->getDist ( direc ) * dist;
00531 
00532          if ( movecost < 1 )
00533            movecost = 1;
00534 
00535          if ( fuelcost <= 0 )
00536            fuelcost = 0;
00537       }
00538    return make_pair(movecost,fuelcost);
00539 }
00540 
00541 
00542 
00543 
00544 
00545 
00546 void Building :: execnetcontrol ( void )
00547 {
00548    for ( int i = 0; i < 3; i++ )
00549       if ( !actmap->isResourceGlobal(i) ) {
00550          if (  netcontrol & (cnet_moveenergyout << i )) {
00551             npush (  netcontrol );
00552             netcontrol |= (cnet_stopenergyinput << i );
00553             actstorage.resource(i) -= putResource ( actstorage.resource(i), i, 0 );
00554             npop (  netcontrol );
00555          } else
00556             if (  netcontrol & (cnet_storeenergy << i )) {
00557                npush (  netcontrol );
00558                netcontrol |= (cnet_stopenergyoutput << i );
00559                actstorage.resource(i) += getResource ( getStorageCapacity().resource(i) -  actstorage.resource(i), i, false );
00560                npop (  netcontrol );
00561             }
00562       }
00563 
00564 }
00565 
00566                     /*   modes: 0 = energy   ohne abbuchen
00567                                 1 = material ohne abbuchen
00568                                 2 = fuel     ohne abbuchen
00569 
00570                                   +4         mit abbuchen                         /
00571                                   +8         nur Tributzahlungen kassieren       /
00572                                  +16         plus zurueckliefern                 <  diese Bits schliessen sich gegenseitig aus
00573                                  +32         usage zurueckliefern                 \
00574                                  +64         tank zurueckliefern                   \
00575                                  */
00576 
00577 
00578 int  Building :: putResource ( int      need,    int resourcetype, bool queryonly, int scope, int player  )
00579 {
00580    if ( need < 0 )
00581       return -getResource( -need, resourcetype, queryonly, scope, player );
00582    else {
00583       int placed;
00584       {
00585          PutResource putresource ( getMap(), scope );
00586          placed = putresource.getresource ( entryPosition.x, entryPosition.y, resourcetype, need, queryonly, player >= 0 ? player : getMap()->actplayer, scope );
00587       }
00588       // if ( !queryonly && placed > 0 )
00589       //   resourceChanged();
00590       return placed;
00591    }
00592 }
00593 
00594 
00595 int  Building :: getResource ( int      need,    int resourcetype, bool queryonly, int scope, int player )
00596 {
00597    if ( need < 0 )
00598       return -putResource( -need, resourcetype, queryonly, scope, player );
00599    else {
00600       int got;
00601       {
00602          GetResource gr ( getMap(), scope );
00603          got = gr.getresource ( entryPosition.x, entryPosition.y, resourcetype, need, queryonly, player >= 0 ? player : getMap()->actplayer, scope );
00604       }
00605       // if ( !queryonly && got > 0 )
00606       //   resourceChanged();
00607       return got;
00608       
00609    }
00610 }
00611 
00612 int  Building :: getAvailableResource ( int      need,    int resourcetype, int scope ) const
00613 {
00614    int got;
00615    {
00616       GetResource gr ( getMap(), scope );
00617       got = gr.getresource ( entryPosition.x, entryPosition.y, resourcetype, need, true, getMap()->actplayer, scope );
00618    }
00619    return got;
00620 }
00621 
00622 void setupNextTech( Player& player )
00623 {
00624    if ( player.research.goal ) {
00625       if ( player.research.techResearched( player.research.goal->id )) {
00626          chooseTechnology( player );
00627       } else {
00628          list<const Technology*> techs;
00629          if ( player.research.goal->eventually_available( player.research, &techs ))
00630             player.research.activetechnology = *techs.begin();
00631          else
00632             chooseTechnology( player );
00633       }
00634    } else
00635       chooseTechnology( player );
00636 
00637    
00638 }
00639 
00640 bool anyTechAvailable( const Player& player )
00641 {
00642    for (int i = 0; i < technologyRepository.getNum(); i++) {
00643       const Technology* tech = technologyRepository.getObject_byPos( i );
00644       if ( tech ) {
00645          ResearchAvailabilityStatus a = player.research.techAvailable ( tech );
00646          if ( a == Available )
00647             return true;
00648       }
00649    }
00650    return false;
00651 }
00652 
00653 
00654 
00655 void researchCheck( Player& player )
00656 {
00657    // we have no research at all set up in the map
00658    if ( !anyTechAvailable( player ) ) // && player.research.developedTechnologies.empty() )
00659       return;
00660 
00661    Research& research = player.research;
00662    if (research.activetechnology == NULL && research.progress ) 
00663       setupNextTech( player );
00664       
00665    if ( research.activetechnology )
00666       if( find ( research.developedTechnologies.begin(), research.developedTechnologies.end(), research.activetechnology->id ) != research.developedTechnologies.end()) {
00667          research.progress = 0;
00668          setupNextTech( player );
00669       }
00670       
00671    while ( research.activetechnology  &&  (research.progress >= research.activetechnology->researchpoints)) {
00672       int mx = research.progress - research.activetechnology->researchpoints;
00673 
00674       showtechnology( research.activetechnology );
00675       
00676       if ( research.activetechnology )
00677          logtoreplayinfo ( rpl_techResearched, research.activetechnology->id, player.getPosition() );
00678 
00679       NewVehicleTypeDetection pfzt;
00680 
00681       research.addtechnology();
00682 
00683       pfzt.evalbuffer ();
00684 
00685       research.progress = mx;
00686 
00687       setupNextTech( player );
00688 
00689    }
00690 }
00691 

Generated on Tue Jun 24 01:27:38 2008 for Advanced Strategic Command by  doxygen 1.4.2