vehicletype.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           vehicletype.cpp  -  description
00003                              -------------------
00004     begin                : Fri Sep 29 2000
00005     copyright            : (C) 2000 by Martin Bickel
00006     email                : bickel@asc-hq.org
00007  ***************************************************************************/
00008 
00014 /***************************************************************************
00015  *                                                                         *
00016  *   This program is free software; you can redistribute it and/or modify  *
00017  *   it under the terms of the GNU General Public License as published by  *
00018  *   the Free Software Foundation; either version 2 of the License, or     *
00019  *   (at your option) any later version.                                   *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 #include <algorithm>
00024 #include "global.h"
00025 #include "vehicletype.h"
00026 #include "sgstream.h"
00027 #include "graphicset.h"
00028 #include "terraintype.h"
00029 #include "objecttype.h"
00030 #include "textfileparser.h"
00031 #include "textfiletags.h"
00032 #include "textfile_evaluation.h"
00033 #include "graphics/blitter.h"
00034 #include "graphics/ColorTransform_PlayerColor.h"
00035 #include "unitcostcalculator-standard.h"
00036 
00037 /*
00038 const char*  cvehiclefunctions[cvehiclefunctionsnum+1]  = {
00039                    "sonar",
00040                    "paratrooper",
00041                    "mine-layer",
00042                    "cruiser landing",
00043                    "repair vehicle",
00044                    "conquer buildings",
00045                    "move after attack",
00046                    "view satellites",
00047                    "construct ALL buildings",
00048                    "view mines",
00049                    "construct vehicles",
00050                    "construct specific buildings",
00051                    "refuel units",
00052                    "icebreaker",
00053                    "cannot be refuelled in air",
00054                    "refuels material",
00055                    "! (unused) !",
00056                    "makes tracks",
00057                    "drill for mineral resources manually",
00058                    "no reactionfire",
00059                    "auto repair",
00060                    "generator",
00061                    "search for mineral resources automatically",
00062                    "Kamikaze only",
00063                    "immune to mines",
00064                    "refuels energy",
00065                    "jams only own field",
00066                    "move with reaction fire on",
00067                    "only move to and from transports",
00068                    NULL };
00069 */
00070 const char*  cwaffentypen[weaponTypeNum]  = {"cruise missile", "mine",    "bomb",       "large missile", "small missile", "torpedo", "machine gun",
00071       "cannon",         "service", "ammunition refuel", "laser", "shootable", "object placement"
00072                                             };
00073 
00074 const int  ammoProductionCost[weaponTypeNum][3]    = { { 1500,1500,1500 }, // cruise missile
00075    {10, 10, 10},       // mine
00076    {40, 40, 40},       // bomb
00077    {200, 200, 200},    // big missile
00078    {50, 50, 50},       // small missile
00079    {20, 30, 40},       // torpedo
00080    {1, 1, 1},          // machine gun
00081    {5, 5, 1},          // cannon
00082    {0, 0, 0},     // service
00083    {0, 0, 0},     // ammo refuel
00084    {0, 0, 0},     // laser
00085    {0, 0, 0},     // shootable
00086    {0, 0, 0}
00087 }
00088 ;    // objectPlacement
00089 
00090 
00091 const bool  weaponAmmo[weaponTypeNum] = {
00092    true, true, true, true, true, true, true, true, false, false, false, false, false
00093 };
00094 
00095 VehicleType :: VehicleType ( void )
00096 {
00097    recommendedAIJob = AiParameter::job_undefined;
00098 
00099    int i;
00100 
00101    armor = 0;
00102 
00103    height     = 0;
00104    cargoMovementDivisor = 2;
00105    wait = 0;
00106    fuelConsumption = 0;
00107 
00108    movement.resize(8);
00109    for ( i = 0; i < 8; i++ )
00110       movement[i] = 0;
00111    movemalustyp = 0;
00112 
00113    maxwindspeedonwater = 0;
00114    digrange = 0;
00115    initiative = 0;
00116 
00117    weight = 0;
00118    bipicture = -1;
00119 
00120    autorepairrate = 0;
00121 
00122    heightChangeMethodNum = 0;
00123 
00124    for ( i = 0; i < 8; i++ )
00125       aiparam[i] = NULL;
00126 
00127    unitConstructionMoveCostPercentage = 50;
00128 
00129    unitConstructionMinDistance = 1;
00130    unitConstructionMaxDistance = 1;
00131 }
00132 
00133 
00134 int VehicleType::maxsize ( void ) const
00135 {
00136    return weight;
00137 }
00138 
00139 
00140 const int vehicle_version = 33;
00141 
00142 
00143 
00144 void VehicleType::setupRemovableObjectsFromOldFileLayout ( )
00145 {
00146    for ( vector<IntRange>::iterator i = objectsBuildable.begin(); i != objectsBuildable.end();  )
00147       if ( i->to < 0 && i->from < 0 ) {
00148          int mi = min ( -i->from, -i->to );
00149          int ma = max ( -i->from, -i->to );
00150          objectsRemovable.push_back ( IntRange ( mi, ma ));
00151          i = objectsBuildable.erase ( i );
00152       } else {
00153          objectsRemovable.push_back ( *i );
00154          i++;
00155       }
00156 }
00157 
00158 void VehicleType :: read ( tnstream& stream )
00159 {
00160    int version = stream.readInt();
00161    if ( version > vehicle_version || version < 1)
00162       throw tinvalidversion ( stream.getLocation(), vehicle_version, version );
00163 
00164    int   j;
00165 
00166    bool ___load_name = stream.readInt();
00167    bool ___load_description = stream.readInt();
00168    bool ___load_infotext = stream.readInt();
00169 
00170    if ( version <= 2 ) {
00171       weapons.count = stream.readChar();
00172       for ( j = 0; j< 8; j++ ) {
00173          weapons.weapon[j].set ( stream.readWord() );
00174          weapons.weapon[j].targ = stream.readChar();
00175          weapons.weapon[j].sourceheight = stream.readChar();
00176          weapons.weapon[j].maxdistance = stream.readWord();
00177          weapons.weapon[j].mindistance = stream.readWord();
00178          weapons.weapon[j].count = stream.readChar();
00179          weapons.weapon[j].maxstrength = stream.readChar();
00180          weapons.weapon[j].minstrength = stream.readChar();
00181          for ( int k = 0; k < 13; k++ )
00182             weapons.weapon[j].efficiency[k] = 100;
00183       }
00184    }
00185 
00186    if ( version <= 27 ) {
00187       productionCost.energy   = stream.readWord();
00188       productionCost.material = stream.readWord();
00189    } else
00190       productionCost.read( stream );
00191 
00192    armor = stream.readWord();
00193 
00194    bool picture[8];
00195    for ( j = 0; j < 8; j++ )
00196       if ( version <= 18 )
00197          picture[j] = stream.readInt();
00198       else
00199          picture[j] = false;
00200 
00201    height = stream.readChar();
00202    stream.readWord(); // was: researchID
00203    int _terrain = 0;
00204    int _terrainreq = 0;
00205    int _terrainkill = 0;
00206    if ( version <= 2 ) {
00207       _terrain = stream.readInt();
00208       _terrainreq = stream.readInt();
00209       _terrainkill = stream.readInt();
00210    }
00211    stream.readChar(); // steigung
00212    jamming = stream.readChar();
00213    view = stream.readWord();
00214    wait = stream.readChar();
00215 
00216    if ( version <= 2 )
00217       stream.readChar (); // dummy
00218 
00219    stream.readWord(); // dummy
00220    stream.readWord(); // dummy
00221    stream.readChar(); // dummy
00222    stream.readChar(); // dummy
00223    stream.readChar(); // dummy
00224    if ( version <= 18 )
00225       id = stream.readWord();
00226    else
00227       id = stream.readInt();
00228 
00229    if ( version < 24 ) {
00230       bi_mode_tank.resource(2) = bi_mode_tank.resource(2) = stream.readInt();
00231       fuelConsumption = stream.readWord();
00232       bi_mode_tank.resource(0) = bi_mode_tank.resource(0) = stream.readInt();
00233       bi_mode_tank.resource(1) = bi_mode_tank.resource(1) = stream.readInt();
00234    } else
00235       fuelConsumption = stream.readInt();
00236 
00237    if ( version <= 22 ) {
00238       int functions = stream.readInt();
00239       features = convertOldFunctions ( functions, stream.getLocation() );
00240    }
00241 
00242    for ( j = 0; j < 8; j++ )
00243       if ( version <= 4 )
00244          movement[j] = stream.readChar();
00245       else
00246          movement[j] = stream.readInt();
00247 
00248 
00249    movemalustyp = stream.readChar();
00250    if ( movemalustyp >= cmovemalitypenum )
00251       movemalustyp = cmovemalitypenum -1;
00252 
00253    if ( version <= 2 )
00254       for ( j = 0; j < 9; j++ )
00255          stream.readWord( ); // dummy1
00256 
00257    bool ___load_classnames[8];
00258    if ( version <= 15 ) {
00259       stream.readChar(); // classnum
00260 
00261       for ( j = 0; j < 8; j++ )
00262          ___load_classnames[j] = stream.readInt();
00263 
00264       for ( j = 0; j < 8; j++ ) {
00265          int k;
00266          for ( k = 0; k < 8; k++ )
00267             stream.readWord();
00268 
00269          if ( version <= 2 )
00270             stream.readWord (  ); // dummy2
00271 
00272          stream.readWord();
00273          stream.readWord();
00274          for ( k = 0; k < 4; k++ )
00275             stream.readWord();
00276 
00277          stream.readChar();
00278          stream.readInt();
00279          if ( version <= 2 )
00280             stream.readChar( ); // dummy
00281       }
00282    }
00283 
00284    maxwindspeedonwater = stream.readChar();
00285    digrange = stream.readChar();
00286    initiative = stream.readInt();
00287    int _terrainnot = 0;
00288    if ( version <= 4 ) {
00289       _terrainnot = stream.readInt();
00290       stream.readInt(); // _terrainreq1
00291    }
00292    int objectsbuildablenum = stream.readInt();
00293    if ( version <= 4 )
00294       stream.readInt(); // objectsbuildableid = (int*)
00295 
00296    weight = stream.readInt();
00297 
00298    bool ___loadterrainaccess = false;
00299    if ( version <= 4 )
00300       ___loadterrainaccess = stream.readInt();
00301 
00302    bipicture = stream.readInt();
00303    int vehiclesbuildablenum = stream.readInt();
00304    if ( version <= 4 )
00305       stream.readInt(); // vehiclesbuildableid = (int*)
00306 
00307    if ( version <= 4 )
00308       stream.readInt(); // buildicon
00309 
00310    int buildingsbuildablenum = stream.readInt();
00311    if ( version <= 4 )
00312       stream.readInt(); // buildingsbuildable = (Vehicletype::tbuildrange*)
00313 
00314    bool load_weapons = stream.readInt();
00315    autorepairrate = stream.readInt();
00316    if ( version >= 15 )
00317       readClassContainer ( wreckageObject, stream );
00318    else
00319       if ( version >= 8 ) {
00320          wreckageObject.clear();
00321          wreckageObject.push_back ( stream.readInt() );
00322       }
00323 
00324 
00325    if ( version <= 2 )
00326       stream.readInt( ); // dummy
00327 
00328    if ( version >= 4 )
00329       stream.readInt(); // dummy
00330 
00331    if (___load_name)
00332       name = stream.readString( true );
00333 
00334    if (___load_description)
00335       description = stream.readString( true );
00336 
00337    if (___load_infotext)
00338       infotext = stream.readString ( true );
00339 
00340    int i;
00341    if ( version <= 15 )
00342       for ( i=0;i<8  ;i++ )
00343          if ( ___load_classnames[i] )
00344             stream.readString ( true );
00345 
00346    if ( hasFunction( AutoRepair ) )
00347       if ( !autorepairrate )
00348          autorepairrate =  10;
00349 
00350    if ( version <= 18 ) {
00351       if ( picture[0] )
00352          image.read ( stream );
00353 
00354       for ( int i=1;i<8  ;i++ ) {
00355          if ( picture[i] ) {
00356             Surface s;
00357             s.read ( stream );
00358             bipicture = 0;
00359          }
00360       }
00361    } else {
00362       image.read ( stream );
00363    }
00364 
00365 
00366    if ( objectsbuildablenum )
00367       for ( i = 0; i < objectsbuildablenum; i++ ) {
00368          int from = stream.readInt ( );
00369          int to;
00370          if ( version <= 4 )
00371             to = from;
00372          else
00373             to = stream.readInt();
00374 
00375          objectsBuildable.push_back ( IntRange ( from, to ));
00376       }
00377 
00378    if ( version >= 6 ) {
00379       int num = stream.readInt();
00380       for ( int i = 0; i < num; i++ ) {
00381          int from = stream.readInt();
00382          int to   = stream.readInt();
00383 
00384          objectsRemovable.push_back ( IntRange ( from, to ));
00385       }
00386    } else
00387       setupRemovableObjectsFromOldFileLayout();
00388 
00389    if ( version >= 8 ) {
00390       int num = stream.readInt();
00391       for ( int i = 0; i < num; i++ ) {
00392          int from = stream.readInt();
00393          int to   = stream.readInt();
00394 
00395          objectGroupsBuildable.push_back ( IntRange ( from, to ));
00396       }
00397 
00398       num = stream.readInt();
00399       for ( int i = 0; i < num; i++ ) {
00400          int from = stream.readInt();
00401          int to   = stream.readInt();
00402 
00403          objectGroupsRemovable.push_back ( IntRange ( from, to ));
00404       }
00405    }
00406 
00407    if ( vehiclesbuildablenum )
00408       for ( i = 0; i < vehiclesbuildablenum; i++ ) {
00409          int from = stream.readInt ( );
00410          int to;
00411          if ( version <= 4 )
00412             to = from;
00413          else
00414             to = stream.readInt();
00415 
00416          vehiclesBuildable.push_back ( IntRange ( from, to ));
00417       }
00418 
00419    if ( load_weapons && version > 1) {
00420       weapons.count = stream.readInt();
00421       for ( j = 0; j< 16; j++ ) {
00422          weapons.weapon[j].set ( stream.readInt() );
00423          weapons.weapon[j].targ = stream.readInt();
00424          weapons.weapon[j].sourceheight = stream.readInt();
00425          weapons.weapon[j].maxdistance = stream.readInt();
00426          weapons.weapon[j].mindistance = stream.readInt();
00427          weapons.weapon[j].count = stream.readInt();
00428          weapons.weapon[j].maxstrength = stream.readInt();
00429          weapons.weapon[j].minstrength = stream.readInt();
00430 
00431          if ( version >= 17 )
00432             weapons.weapon[j].reactionFireShots = stream.readInt();
00433 
00434          if ( version >= 22 )
00435             weapons.weapon[j].name = stream.readString();
00436 
00437          /*
00438          if ( weapons.weapon[j].getScalarWeaponType() == cwminen )
00439             if ( weapons.weapon[j].mindistance < 8 )
00440                warningMessage ( ASCString("unit with id ") + strrr ( id ) + " has invalid mine weapon range ");
00441          */
00442 
00443          for ( int k = 0; k < 13; k++ )
00444             weapons.weapon[j].efficiency[k] = stream.readInt();
00445 
00446          if ( version <= 6 ) {
00447             int targets_not_hittable = stream.readInt();
00448             for ( int i = 0; i < cmovemalitypenum; i++ )
00449                if ( targets_not_hittable & ( 1 << i))
00450                   weapons.weapon[j].targetingAccuracy[i] = 0;
00451          } else {
00452             int num = stream.readInt();
00453             for ( int i = 0; i < num; i++ )
00454                weapons.weapon[j].targetingAccuracy[i] = stream.readInt();
00455          }
00456 
00457 
00458          if ( version <= 2 )
00459             for ( int l = 0; l < 9; l++ )
00460                stream.readInt(); // dummy
00461 
00462          if ( version >= 11 ) {
00463             weapons.weapon[j].laserRechargeRate = stream.readInt();
00464             weapons.weapon[j].laserRechargeCost.read( stream );
00465          }
00466          if ( version >= 20 )
00467             weapons.weapon[j].soundLabel = stream.readString();
00468 
00469       }
00470 
00471       if ( version <= 2 )
00472          for ( int m = 0; m< 10; m++ )
00473             stream.readInt(); // dummy
00474 
00475    }
00476 
00477    if ( ___loadterrainaccess || version >= 5 )
00478       terrainaccess.read ( stream );
00479    else {
00480       terrainaccess.terrain.setInt ( _terrain, 0 );
00481       terrainaccess.terrainreq.setInt ( _terrainreq, 0 );
00482       terrainaccess.terrainnot.setInt ( _terrainnot, 0 );
00483       terrainaccess.terrainkill.setInt ( _terrainkill, 0 );
00484    }
00485 
00486    if ( buildingsbuildablenum )
00487       for ( i = 0; i < buildingsbuildablenum; i++ ) {
00488          int from = stream.readInt();
00489          int to = stream.readInt();
00490          buildingsBuildable.push_back ( IntRange ( from, to ));
00491       }
00492 
00493 
00494    filename = stream.getDeviceName();
00495    location = stream.getLocation();
00496 
00497    if ( version >= 9 )
00498       ContainerBaseType::read ( stream );
00499 
00500    if ( version >= 10 ) {
00501       heightChangeMethodNum = stream.readInt();
00502       heightChangeMethod.resize(heightChangeMethodNum );
00503       for ( int i = 0; i < heightChangeMethodNum; i++ )
00504          heightChangeMethod[i].read( stream );
00505    } else
00506       heightChangeMethodNum = 0;
00507 
00508    if ( version >= 12 )
00509       techDependency.read( stream );
00510 
00511    if ( version >= 13 && version <= 24 ) {
00512       Surface s;
00513       s.read( stream );
00514    }
00515 
00516    if ( version >= 14 && version < 18)
00517       cargoMovementDivisor = stream.readInt();
00518    else
00519       if ( version >= 18 )
00520          cargoMovementDivisor = stream.readFloat();
00521 
00522    if ( version >= 20 ) {
00523       movementSoundLabel = stream.readString();
00524       killSoundLabel = stream.readString();
00525    }
00526 
00527    if ( version >= 22 )
00528       readClassContainer( guideSortHelp, stream );
00529 
00530    if ( version >= 24 ) {
00531       efficiencyfuel = stream.readInt( );
00532       efficiencymaterial = stream.readInt( );
00533       asc_mode_tank.read( stream );
00534       bi_mode_tank.read( stream );
00535 
00536 
00537       maxresearchpoints = stream.readInt();
00538       defaultMaxResearchpoints = stream.readInt();
00539       nominalresearchpoints = stream.readInt();
00540       maxplus.read( stream );
00541       defaultProduction.read( stream );
00542    }
00543 
00544    for ( int w = 0; w < weapons.count; ++w )
00545       if ( weapons.weapon[w].canRefuel() )
00546          setFunction( ExternalAmmoTransfer );
00547 
00548    if ( version >= 26 ) {
00549       jumpDrive.height = stream.readInt();
00550       jumpDrive.targetterrain.read( stream );
00551       jumpDrive.consumption.read( stream );
00552       jumpDrive.maxDistance = stream.readInt();
00553    }
00554 
00555    if ( version >= 27 ) {
00556       int num = stream.readInt();
00557       for ( int i = 0; i < num; i++ ) {
00558          int from = stream.readInt();
00559          int to   = stream.readInt();
00560          objectLayedByMovement.push_back ( IntRange ( from, to ));
00561       }
00562    }
00563 
00564    if ( version >= 29 )
00565       unitConstructionMoveCostPercentage = stream.readInt();
00566 
00567    if ( version >= 30 ) {
00568       unitConstructionMinDistance = stream.readInt();
00569       unitConstructionMaxDistance = stream.readInt();
00570    }
00571    
00572    if ( version >= 31 )
00573       imageFilename = stream.readString();
00574    
00575    if ( version >= 32 )
00576       recommendedAIJob = AiParameter::Job(stream.readInt());
00577 
00578    if ( version >= 33 )
00579       costCalculator = stream.readString();
00580 }
00581 
00582 
00583 
00584 
00585 void VehicleType:: write ( tnstream& stream ) const
00586 {
00587    int i,j;
00588 
00589    stream.writeInt ( vehicle_version );
00590 
00591    if ( !name.empty() )
00592       stream.writeInt( 1 );
00593    else
00594       stream.writeInt( 0 );
00595 
00596    if ( !description.empty() )
00597       stream.writeInt( 1 );
00598    else
00599       stream.writeInt( 0 );
00600 
00601    if ( !infotext.empty() )
00602       stream.writeInt( 1 );
00603    else
00604       stream.writeInt( 0 );
00605 
00606    productionCost.write( stream );
00607    stream.writeWord( armor );
00608    stream.writeChar( height );
00609    stream.writeWord(0); // researchid
00610    stream.writeChar(0); // steigung
00611    stream.writeChar(jamming);
00612    stream.writeWord(view);
00613    stream.writeChar(wait);
00614    stream.writeWord(0);
00615    stream.writeWord(0);
00616    stream.writeChar(0);
00617    stream.writeChar(0);
00618    stream.writeChar(0);
00619    stream.writeInt(id );
00620    stream.writeInt(fuelConsumption );
00621    for ( j = 0; j < 8; j++ )
00622       stream.writeInt( movement[j] );
00623 
00624 
00625    stream.writeChar(movemalustyp );
00626 
00627    stream.writeChar(maxwindspeedonwater );
00628    stream.writeChar(digrange );
00629    stream.writeInt(initiative );
00630    stream.writeInt( objectsBuildable.size() );
00631 
00632    stream.writeInt(weight );
00633 
00634    stream.writeInt(bipicture );
00635    stream.writeInt(vehiclesBuildable.size() );
00636    stream.writeInt( buildingsBuildable.size() );
00637    stream.writeInt( 1 ); // weapons
00638 
00639    stream.writeInt( autorepairrate );
00640    writeClassContainer( wreckageObject, stream );
00641 
00642    stream.writeInt( 0 );
00643 
00644    if ( !name.empty() )
00645       stream.writeString( name );
00646 
00647    if ( !description.empty() )
00648       stream.writeString( description );
00649 
00650    if ( !infotext.empty() )
00651       stream.writeString( infotext );
00652 
00653    image.write( stream );
00654 
00655    for ( i = 0; i < objectsBuildable.size(); i++ ) {
00656       stream.writeInt ( objectsBuildable[i].from );
00657       stream.writeInt ( objectsBuildable[i].to );
00658    }
00659 
00660    stream.writeInt ( objectsRemovable.size() );
00661    for ( i = 0; i < objectsRemovable.size(); i++ ) {
00662       stream.writeInt ( objectsRemovable[i].from );
00663       stream.writeInt ( objectsRemovable[i].to );
00664    }
00665 
00666    stream.writeInt ( objectGroupsBuildable.size() );
00667    for ( i = 0; i < objectGroupsBuildable.size(); i++ ) {
00668       stream.writeInt ( objectGroupsBuildable[i].from );
00669       stream.writeInt ( objectGroupsBuildable[i].to );
00670    }
00671 
00672    stream.writeInt ( objectGroupsRemovable.size() );
00673    for ( i = 0; i < objectGroupsRemovable.size(); i++ ) {
00674       stream.writeInt ( objectGroupsRemovable[i].from );
00675       stream.writeInt ( objectGroupsRemovable[i].to );
00676    }
00677 
00678 
00679    for ( i = 0; i < vehiclesBuildable.size(); i++ ) {
00680       stream.writeInt ( vehiclesBuildable[i].from );
00681       stream.writeInt ( vehiclesBuildable[i].to );
00682    }
00683 
00684    stream.writeInt(weapons.count );
00685    for ( j = 0; j< 16; j++ ) {
00686       stream.writeInt(weapons.weapon[j].gettype( ));
00687       stream.writeInt(weapons.weapon[j].targ);
00688       stream.writeInt(weapons.weapon[j].sourceheight );
00689       stream.writeInt(weapons.weapon[j].maxdistance );
00690       stream.writeInt(weapons.weapon[j].mindistance );
00691       stream.writeInt(weapons.weapon[j].count );
00692       stream.writeInt(weapons.weapon[j].maxstrength );
00693       stream.writeInt(weapons.weapon[j].minstrength );
00694       stream.writeInt(weapons.weapon[j].reactionFireShots );
00695       stream.writeString( weapons.weapon[j].name );
00696 
00697       for ( int k = 0; k < 13; k++ )
00698          stream.writeInt(weapons.weapon[j].efficiency[k] );
00699 
00700       stream.writeInt ( cmovemalitypenum );
00701       for ( int i = 0; i < cmovemalitypenum; i++ )
00702          stream.writeInt(weapons.weapon[j].targetingAccuracy[i] );
00703 
00704       stream.writeInt( weapons.weapon[j].laserRechargeRate );
00705       weapons.weapon[j].laserRechargeCost.write( stream );
00706       stream.writeString( weapons.weapon[j].soundLabel );
00707    }
00708 
00709    terrainaccess.write ( stream );
00710 
00711    for ( i = 0; i < buildingsBuildable.size(); i++ ) {
00712       stream.writeInt( buildingsBuildable[i].from );
00713       stream.writeInt( buildingsBuildable[i].to );
00714    }
00715 
00716    ContainerBaseType::write ( stream );
00717 
00718 
00719    stream.writeInt( heightChangeMethodNum );
00720    for ( i = 0; i < heightChangeMethodNum; i++ )
00721       heightChangeMethod[i].write( stream );
00722 
00723    techDependency.write( stream );
00724 
00725    stream.writeFloat ( cargoMovementDivisor );
00726 
00727    stream.writeString( movementSoundLabel );
00728    stream.writeString( killSoundLabel );
00729    writeClassContainer( guideSortHelp, stream );
00730 
00731    stream.writeInt( efficiencyfuel );
00732    stream.writeInt( efficiencymaterial );
00733 
00734    asc_mode_tank.write( stream );
00735    bi_mode_tank.write( stream );
00736 
00737    stream.writeInt( maxresearchpoints );
00738    stream.writeInt( defaultMaxResearchpoints );
00739    stream.writeInt( nominalresearchpoints );
00740    maxplus.write ( stream );
00741    defaultProduction.write( stream );
00742 
00743    stream.writeInt( jumpDrive.height );
00744    jumpDrive.targetterrain.write( stream );
00745    jumpDrive.consumption.write( stream );
00746    stream.writeInt( jumpDrive.maxDistance );
00747 
00748    stream.writeInt ( objectLayedByMovement.size() );
00749    for ( i = 0; i < objectLayedByMovement.size(); i++ ) {
00750       stream.writeInt ( objectLayedByMovement[i].from );
00751       stream.writeInt ( objectLayedByMovement[i].to );
00752    }
00753 
00754    stream.writeInt( unitConstructionMoveCostPercentage );
00755    stream.writeInt( unitConstructionMinDistance );
00756    stream.writeInt( unitConstructionMaxDistance );
00757    stream.writeString( imageFilename );
00758    stream.writeInt( recommendedAIJob );
00759    
00760    stream.writeString( costCalculator );
00761 }
00762 
00763 
00764 ASCString VehicleType::getName( ) const
00765 {
00766    if ( !name.empty() )
00767       return name;
00768    else
00769       return description;
00770 }
00771 
00772 int VehicleType :: maxSpeed ( ) const
00773 {
00774    int maxUnitMovement = 0;
00775    for ( int i = 0; i < 8; i++ )
00776       maxUnitMovement = max ( maxUnitMovement, movement[i] );
00777    return maxUnitMovement;
00778 }
00779 
00780 int VehicleType::getMemoryFootprint() const
00781 {
00782    return sizeof(*this) + image.getMemoryFootprint();
00783 }
00784 
00785 
00786 VehicleType :: ~VehicleType ( )
00787 {
00788    for ( int i = 0; i < 8; i++ )
00789       if ( aiparam[i] ) {
00790          delete aiparam[i];
00791          aiparam[i] = NULL;
00792       }
00793 }
00794 
00795 
00796 
00797 SingleWeapon::SingleWeapon()
00798 {
00799    typ = 0;
00800    targ = 0;
00801    sourceheight = 0;
00802    maxdistance = 0;
00803    mindistance = 0;
00804    count = 0;
00805    maxstrength= 0;
00806    minstrength = 0;
00807    laserRechargeRate = 0;
00808    for ( int i = 0; i < 13; i++ )
00809       efficiency[i] = 0;
00810    for ( int i = 0; i < cmovemalitypenum; i++ )
00811       targetingAccuracy[i] = 100;
00812 
00813    reactionFireShots = 1;
00814 }
00815 
00816 
00817 /* Translate the weapon/mine/service bit pattern into scalar
00818  * weapon number for use in fetching UI resources.
00819  */
00820 int SingleWeapon::getScalarWeaponType(void) const
00821 {
00822    if ( typ & (cwweapon | cwmineb) )
00823       return getFirstBit ( typ & (cwweapon | cwmineb) );
00824    else
00825       return -1;
00826 }
00827 
00828 
00829 bool SingleWeapon::requiresAmmo(void) const
00830 {
00831    if ( typ & cwlaserb )
00832       return false;
00833    else
00834       return typ & ( cwweapon | cwmineb );
00835 }
00836 
00837 bool SingleWeapon::shootable( void ) const
00838 {
00839    return typ & cwshootableb;
00840 }
00841 
00842 bool SingleWeapon::offensive( void ) const
00843 {
00844    return typ & cwweapon;
00845 }
00846 
00847 bool SingleWeapon::service( void ) const
00848 {
00849    return typ & cwserviceb;
00850 }
00851 
00852 bool SingleWeapon::placeObjects(  ) const
00853 {
00854    return typ & cwobjectplacementb;
00855 }
00856 
00857 
00858 bool SingleWeapon::canRefuel( void ) const
00859 {
00860    return typ & cwammunitionb;
00861 }
00862 
00863 void SingleWeapon::set
00864 ( int type )
00865 {
00866    typ = type;
00867 }
00868 
00869 ASCString SingleWeapon::getName ( void ) const
00870 {
00871    if ( !name.empty() )
00872       return name;
00873 
00874    ASCString s;
00875 
00876    int k = getScalarWeaponType();
00877    if ( k < weaponTypeNum && k >= 0 )
00878       s = cwaffentypen[k];
00879    else
00880       if ( service() || placeObjects() )
00881          s = cwaffentypen[cwservicen];
00882       else
00883          s = "undefined";
00884 
00885    return s;
00886 }
00887 
00888 ASCString    SingleWeapon::getIconFileName( int numerical )
00889 {
00890    switch ( numerical ) {
00891       case cwcruisemissile:
00892          return "weap-cruisemissile";
00893       case cwbombn:
00894          return "weap-bomb";
00895       case cwlargemissilen:
00896          return "weap-bigmissile";
00897       case cwsmallmissilen:
00898          return "weap-smallmissile";
00899       case cwtorpedon:
00900          return "weap-torpedo";
00901       case cwmachinegunn:
00902          return "weap-machinegun";
00903       case cwcannonn:
00904          return "weap-cannon";
00905       case cwminen:
00906          return "weap-mine";
00907       case cwservicen:
00908          return "weap-service";
00909       case cwlasern:
00910          return "weap-laser";
00911       default:
00912          return "weap-undefined";
00913    };
00914 }
00915 
00916 
00917 bool SingleWeapon::equals( const SingleWeapon* otherWeapon ) const
00918 {
00919    if (
00920       otherWeapon->targ == this->targ &&
00921       otherWeapon->sourceheight == this->sourceheight &&
00922       otherWeapon->maxdistance == this->maxdistance &&
00923       otherWeapon->mindistance == this->mindistance &&
00924       otherWeapon->count == this->count &&
00925       otherWeapon->maxstrength == this->maxstrength &&
00926       otherWeapon->minstrength == this->minstrength &&
00927       otherWeapon->gettype() == this->gettype()
00928    ) {
00929       bool equal = true;
00930       for ( int i=0; i<13; i++ ) {
00931          if ( otherWeapon->efficiency[ i ] != this->efficiency[ i ] ) {
00932             equal = false;
00933          }
00934       }
00935       if ( equal ) return true;
00936    }
00937 
00938    return false;
00939 }
00940 
00941 
00942 UnitWeapon :: UnitWeapon ( void )
00943 {
00944    count = 0;
00945 }
00946 
00947 
00948 
00949 
00950 void VehicleType::runTextIO ( PropertyContainer& pc )
00951 {
00952    ContainerBaseType::runTextIO ( pc );
00953 
00954    pc.addInteger( "Armor", armor );
00955 
00956    ASCString fn;
00957    if ( filename.empty() ) {
00958       fn += "vehicle";
00959       fn += strrr(id);
00960    } else
00961       fn = extractFileName_withoutSuffix( filename );
00962 
00963    pc.addImage( "Picture", image, fn, true );
00964    if ( pc.isReading() ) 
00965       imageFilename = fn;
00966    else
00967       pc.addString("OriginalImageFilename", imageFilename );
00968    
00969    if ( image.w() < fieldsizex || image.h() < fieldsizey )
00970       image.strech( fieldsizex, fieldsizey );
00971 
00972    image.assignDefaultPalette();
00973 
00974    pc.addTagInteger( "Height", height, choehenstufennum, heightTags );
00975    pc.addBool ( "WaitForAttack", wait );
00976 
00977    if ( bi_mode_tank == Resources(0,0,0) && asc_mode_tank == Resources(0,0,0)) {
00978       pc.openBracket( "Tank" );
00979       Resources tank;
00980       tank.runTextIO ( pc );
00981       pc.closeBracket();
00982       bi_mode_tank = tank;
00983       asc_mode_tank = tank;
00984    }
00985 
00986    pc.addInteger( "FuelConsumption", fuelConsumption );
00987    if ( !pc.find("Features") && pc.isReading() ) {
00988       int abilities;
00989       pc.addTagInteger ( "Abilities", abilities, legacyVehicleFunctionNum, vehicleAbilities );
00990 
00991       features = convertOldFunctions ( abilities, pc.getFileName() );
00992 
00993    } else
00994       pc.addTagArray ( "Features", features, functionNum, containerFunctionTags );
00995 
00996 
00997    pc.addIntegerArray ( "Movement", movement );
00998    while ( movement.size() < 8 )
00999       movement.push_back(0);
01000    for ( vector<int>::iterator i = movement.begin(); i != movement.end(); i++ )
01001       if ( *i > 350 )
01002          *i = 350;
01003 
01004    pc.addNamedInteger ( "Category", movemalustyp, cmovemalitypenum, unitCategoryTags );
01005    pc.addInteger("MaxSurvivableStorm", maxwindspeedonwater, 255 );
01006    pc.addInteger("ResourceDrillingRange", digrange, 0 );
01007    pc.addInteger("SelfRepairRate", autorepairrate, 0 );
01008    if ( pc.find ( "WreckageObject" ) || !pc.isReading() )
01009       pc.addIntegerArray("WreckageObject", wreckageObject );
01010 
01011 
01012    if ( pc.find( "CargoMovementDivisor" ))
01013       pc.addDFloat("CargoMovementDivisor", cargoMovementDivisor);
01014    else {
01015       pc.openBracket( "Transportation" );
01016       pc.addDFloat("CargoMovementDivisor", cargoMovementDivisor, 2 );
01017       pc.closeBracket();
01018    }
01019 
01020 
01021    pc.addInteger("Weight",  weight);
01022    pc.openBracket("TerrainAccess" );
01023    terrainaccess.runTextIO ( pc );
01024    pc.closeBracket();
01025 
01026    pc.openBracket ( "Construction" );
01027    pc.addIntRangeArray ( "Buildings", buildingsBuildable );
01028    pc.addIntRangeArray ( "Vehicles", vehiclesBuildable );
01029    pc.addIntRangeArray ( "Objects", objectsBuildable );
01030    if ( pc.isReading() ) {
01031       if ( pc.find ( "ObjectsRemovable" ))
01032          pc.addIntRangeArray ( "ObjectsRemovable", objectsRemovable );
01033       else
01034          setupRemovableObjectsFromOldFileLayout();
01035    } else
01036       pc.addIntRangeArray ( "ObjectsRemovable", objectsRemovable );
01037 
01038    pc.addIntRangeArray ( "ObjectGroupsBuildable", objectGroupsBuildable, false );
01039    pc.addIntRangeArray ( "ObjectGroupsRemovable", objectGroupsRemovable, false );
01040    pc.addInteger("UnitConstructionMoveCostPercentage", unitConstructionMoveCostPercentage, 50);
01041    pc.addInteger("UnitConstructionMinDistance", unitConstructionMinDistance, 1 );
01042    pc.addInteger("UnitConstructionMaxDistance", unitConstructionMaxDistance, 1 );
01043    pc.closeBracket();
01044 
01045    pc.openBracket ( "Weapons");
01046    // pc.addInteger("Initiative", initiative );
01047    pc.addInteger("Number", weapons.count );
01048    for ( int i = 0; i < weapons.count; i++ ) {
01049       pc.openBracket ( ASCString("Weapon")+strrr(i) );
01050       weapons.weapon[i].runTextIO( pc );
01051       pc.closeBracket();
01052       if ( hasFunction( NoReactionfire ) )
01053          weapons.weapon[i].reactionFireShots = 0;
01054 
01055    }
01056 
01057    pc.closeBracket();
01058 
01059    int job = recommendedAIJob;
01060    pc.addNamedInteger ( "AIJobOverride", job, AiParameter::jobNum, AIjobs, AiParameter::job_undefined );
01061    recommendedAIJob = AiParameter::Job(job);
01062 
01063    pc.addString("MovementSound", movementSoundLabel, "" );
01064    pc.addString("KillSound", killSoundLabel, "" );
01065 
01066    pc.addInteger("HeightChangeMethodNum", heightChangeMethodNum, 0 );
01067    heightChangeMethod.resize( heightChangeMethodNum );
01068    for ( int i = 0; i < heightChangeMethodNum; i++ ) {
01069       pc.openBracket( ASCString("HeightChangeMethod")+strrr(i) );
01070       heightChangeMethod[i].runTextIO ( pc );
01071       pc.closeBracket();
01072    }
01073 
01074    techDependency.runTextIO( pc, strrr(id) );
01075 
01076 
01077 
01078    pc.openBracket ( "ConstructionCost" );
01079    productionCost.runTextIO ( pc );
01080    int costCalcMethod = 0;
01081    pc.addNamedInteger( "CalculationMethod", costCalcMethod, productionCostCalculationMethodNum, productionCostCalculationMethod,  0 );
01082    if ( pc.isReading() ) {
01083       if ( !pc.find ( "material" ) && costCalcMethod == 0)
01084          costCalcMethod = 1;
01085    }
01086 
01087    pc.addString( "Calculator", costCalculator, "standard" );
01088    
01089    if ( costCalcMethod == 1 )
01090       productionCost = calcProductionCost();
01091    
01092    if ( costCalcMethod == 2 )
01093       productionCost += calcProductionCost();
01094 
01095    if ( costCalcMethod != 0 ) {
01096       displayLogMessage ( 4, "unit %s id %d has a production cost of %d E; %d M;  %d F \n", name.c_str(), id, productionCost.energy, productionCost.material, productionCost.fuel );
01097    }
01098 
01099    pc.closeBracket ();
01100 
01101    if ( pc.find( "guideSortHelp") || !pc.isReading() )
01102       pc.addIntegerArray("guideSortHelp", guideSortHelp );
01103 
01104    bool hasService = false;
01105    for ( int w = 0; w < weapons.count; ++w ) {
01106       if ( weapons.weapon[w].canRefuel() )
01107          setFunction( ExternalAmmoTransfer );
01108       if ( weapons.weapon[w].service() )
01109          hasService = true;
01110    }
01111 
01112    if ( !hasService ) {
01113       features.reset( ExternalRepair );
01114       features.reset( ExternalEnergyTransfer );
01115       features.reset( ExternalMaterialTransfer );
01116       features.reset( ExternalFuelTransfer );
01117       features.reset( ExternalAmmoTransfer );
01118    }
01119 
01120 
01121 
01122    pc.openBracket ( "JumpDrive" );
01123    pc.addTagInteger( "Height", jumpDrive.height, choehenstufennum, heightTags, 0 );
01124    pc.openBracket ( "consumption" );
01125    jumpDrive.consumption.runTextIO ( pc, Resources(0,0,0) );
01126    pc.closeBracket();
01127    if ( jumpDrive.height || !pc.isReading() )
01128       jumpDrive.targetterrain.runTextIO ( pc );
01129    pc.addInteger( "MaxDistance", jumpDrive.maxDistance, maxint );
01130    pc.closeBracket();
01131 
01132    if ( jumpDrive.height && view )
01133       pc.error( "only units without radar may have a jump drive." );
01134 
01135    if ( !pc.isReading() || pc.find ( "ObjectsLayedByMovement" ))
01136       pc.addIntRangeArray ( "ObjectsLayedByMovement", objectLayedByMovement );
01137    else
01138       objectLayedByMovement.clear();
01139 
01140    if ( hasFunction( ContainerBaseType::IceBreaker ))
01141       objectLayedByMovement.push_back ( 6 );
01142 
01143    if ( hasFunction( ContainerBaseType::MakesTracks ))
01144       objectLayedByMovement.push_back ( 7 );
01145 
01146 
01147 }
01148 
01149 BitSet VehicleType::convertOldFunctions( int abilities, const ASCString& location )
01150 {
01151    BitSet features;
01152    if ( abilities & 1 )
01153       features.set( Sonar );
01154    if ( abilities & 2 )
01155       features.set( Paratrooper );
01156    if ( abilities & 4 )
01157       features.set( PlaceMines );
01158    if ( abilities & 8 )
01159       features.set( CruiserLanding );
01160    if ( abilities & 16 ) {
01161       features.set( ExternalRepair );
01162       features.set( InternalUnitRepair );
01163    }
01164    if ( abilities & 32 )
01165       features.set( ConquerBuildings );
01166    if ( abilities & 64 )
01167       features.set( MoveAfterAttack );
01168    if ( abilities & 128 )
01169       features.set( SatelliteView );
01170    if ( abilities & 256 )
01171       errorMessage( location + ": The features construct_ALL_buildings is not supported any more");
01172    if ( abilities & 512 )
01173       features.set( MineView );
01174    if ( abilities & 1024 )
01175       features.set( ExternalVehicleProduction );
01176    if ( abilities & 2048 )
01177       features.set( ConstructBuildings );
01178    if ( abilities & 4096 )
01179       features.set( ExternalFuelTransfer );
01180    if ( abilities & 8192 )
01181       features.set( IceBreaker );
01182    if ( abilities & 16384 )
01183       features.set( NoInairRefuelling );
01184    if ( abilities & 32768 )
01185       features.set( ExternalMaterialTransfer );
01186    if ( abilities & (1 << 17) )
01187       features.set( MakesTracks );
01188    if ( abilities & (1 << 18) )
01189       features.set( DetectsMineralResources );
01190    if ( abilities & (1 << 19) )
01191       features.set( NoReactionfire );
01192    if ( abilities & (1 << 20) )
01193       features.set( AutoRepair );
01194    if ( abilities & (1 << 21) )
01195       features.set( MatterConverter );
01196    // we probably need to setup the conversion matrix at this point
01197 
01198    if ( abilities & (1 << 22) )
01199       features.set( DetectsMineralResources );
01200    if ( abilities & (1 << 23) )
01201       features.set( KamikazeOnly );
01202    if ( abilities & (1 << 24) )
01203       features.set( ImmuneToMines );
01204    if ( abilities & (1 << 25) )
01205       features.set( ExternalEnergyTransfer );
01206    if ( abilities & (1 << 26) )
01207       features.set( JamsOnlyOwnField );
01208    if ( abilities & (1 << 27) )
01209       features.set( MoveWithReactionFire );
01210    if ( abilities & (1 << 28) )
01211       features.set( OnlyMoveToAndFromTransports );
01212    return features;
01213 }
01214 
01215 void  VehicleType::paint ( Surface& s, SPoint pos, const PlayerColor& player, int direction ) const
01216 {
01217    megaBlitter<ColorTransform_PlayerCol,ColorMerger_AlphaOverwrite,SourcePixelSelector_Plain,TargetPixelSelector_All>( getImage(), s, pos, player, nullParam, nullParam, nullParam );
01218 }
01219 
01220 void  VehicleType::paint ( Surface& s, SPoint pos ) const
01221 {
01222    megaBlitter<ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_Plain,TargetPixelSelector_All>( getImage(), s, pos, nullParam, nullParam, nullParam, nullParam );
01223 }
01224 
01225 
01226 void SingleWeapon::runTextIO ( PropertyContainer& pc )
01227 {
01228    pc.addTagInteger( "Type", typ, weaponTypeNum, weaponTags );
01229    pc.addTagInteger( "targets", targ, choehenstufennum, heightTags );
01230    pc.addTagInteger( "shotFrom", sourceheight, choehenstufennum, heightTags );
01231    pc.addInteger("MaxRange", maxdistance );
01232    pc.addInteger("MinRange", mindistance );
01233    pc.addInteger("Ammo", count );
01234    pc.addInteger("Punch@MaxRange", minstrength );
01235    pc.addInteger("Punch@MinRange", maxstrength );
01236    pc.addString("Sound", soundLabel, "");
01237    pc.addInteger("LaserRechargeRate", laserRechargeRate, 0 );
01238    pc.openBracket( "laserRechargeCost" );
01239    laserRechargeCost.runTextIO ( pc, Resources(0,0,0) );
01240    pc.closeBracket();
01241 
01242    pc.addInteger("ReactionFireShots", reactionFireShots, 1 );
01243    if ( getScalarWeaponType() == cwminen && reactionFireShots > 0 )
01244         warningMessage(pc.getFileName() + " has a mine with Reactionfire. This doesn't make sense.");
01245 
01246    pc.openBracket("HitAccuracy" );
01247    {
01248       for ( int j = 0; j < 13; j++ )
01249          if ( j < 6 )
01250             pc.addInteger( ASCString("d")+strrr(abs(j-6)), efficiency[j] );
01251          else
01252             if ( j == 6 )
01253                pc.addInteger( "0", efficiency[j] );
01254             else
01255                pc.addInteger( ASCString("u")+strrr(j-6), efficiency[j] );
01256    }
01257    pc.closeBracket();
01258 
01259    if ( pc.isReading() ) {
01260       if ( pc.find ( "cantHit" )) {
01261          int targets_not_hittable;
01262          pc.addTagInteger( "cantHit", targets_not_hittable, cmovemalitypenum, unitCategoryTags );
01263          for ( int i = 0; i < cmovemalitypenum; i++ )
01264             if ( targets_not_hittable & ( 1 << i ))
01265                targetingAccuracy[i] = 0;
01266       }
01267       pc.openBracket("WeaponEffectiveness" );
01268       for ( int i = 0; i < cmovemalitypenum; i++ ) {
01269          if ( pc.find ( unitCategoryTags[i] ))
01270             pc.addInteger( unitCategoryTags[i], targetingAccuracy[i] );
01271       }
01272       pc.closeBracket();
01273    } else {
01274       pc.openBracket("WeaponEffectiveness" );
01275       for ( int i = 0; i < cmovemalitypenum; i++ )
01276          if ( targetingAccuracy[i] != 100 )
01277             pc.addInteger( unitCategoryTags[i], targetingAccuracy[i] );
01278       pc.closeBracket();
01279    }
01280    pc.addString("name", name, "");
01281 }
01282 
01283 
01284 void VehicleType :: HeightChangeMethod :: runTextIO ( PropertyContainer& pc )
01285 {
01286    pc.addTagInteger( "StartHeight", startHeight, choehenstufennum, heightTags );
01287    pc.addInteger("HeightDelta", heightDelta );
01288    pc.addInteger("MoveCost", moveCost, 0 );
01289    pc.addBool ( "CanAttack", canAttack );
01290    pc.addInteger("Dist", dist );
01291 }
01292 
01293 
01294 
01295 const int vehicleHeightChangeMethodVersion = 1;
01296 
01297 
01298 void VehicleType :: HeightChangeMethod :: read ( tnstream& stream )
01299 {
01300    int version = stream.readInt();
01301    if ( version > vehicleHeightChangeMethodVersion || version < 1 ) {
01302       ASCString s = "invalid version for reading VehicleType :: HeightChangeMethod : ";
01303       s += strrr ( version );
01304       throw ASCmsgException ( s );
01305    }
01306    startHeight = stream.readInt();
01307    heightDelta = stream.readInt();
01308    moveCost = stream.readInt();
01309    canAttack = stream.readInt();
01310    dist = stream.readInt();
01311 }
01312 
01313 void VehicleType :: HeightChangeMethod :: write ( tnstream& stream ) const
01314 {
01315    stream.writeInt ( vehicleHeightChangeMethodVersion );
01316    stream.writeInt ( startHeight );
01317    stream.writeInt ( heightDelta );
01318    stream.writeInt ( moveCost );
01319    stream.writeInt ( canAttack );
01320    stream.writeInt ( dist );
01321 }
01322 
01323 Resources VehicleType :: calcProductionCost()
01324 {
01325    static UnitCostCalculator* standard = new StandardUnitCostCalculator();
01326    // static UnitCostCalculator* pbp2 = new UnitCostCalculator2
01327    return standard->productionCost( this );
01328 }

Generated on Mon May 21 01:26:39 2012 for Advanced Strategic Command by  doxygen 1.5.1