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