00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
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
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
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
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
00453 if (start.getNumericalHeight() >= 4 )
00454 movecost = maxmalq;
00455 else
00456 if ( start.getNumericalHeight() <= 1 ) {
00457 movecost = submarineMovement;
00458 checkWind = false;
00459 } else {
00460
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
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
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
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
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
00567
00568
00569
00570
00571
00572
00573
00574
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
00589
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
00606
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
00658 if ( !anyTechAvailable( player ) )
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