00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "vehicletype.h"
00027 #include "buildingtype.h"
00028
00029 #include "edmisc.h"
00030 #include "edselfnt.h"
00031 #include "mapdisplay.h"
00032 #include "itemrepository.h"
00033 #include "edglobal.h"
00034
00035 #include "graphics/blitter.h"
00036 #include "paradialog.h"
00037
00038 #include "dialogs/vehicletypeselector.h"
00039 #include "unitset.h"
00040 #include "spfst-legacy.h"
00041
00042 SigC::Signal0<void> filtersChangedSignal;
00043
00044
00045
00046
00047
00048 bool buildingComp( const BuildingType* v1, const BuildingType* v2 )
00049 {
00050 int id1 = getUnitSetID(v1);
00051 int id2 = getUnitSetID(v2);
00052 return (id1 < id2) ||
00053 (id1 == id2 && v1->name < v2->name);
00054 }
00055
00056 bool objectComp( const ObjectType* v1, const ObjectType* v2 )
00057 {
00058 return v1->name < v2->name;
00059 }
00060
00061 bool terrainComp( const TerrainType* v1, const TerrainType* v2 )
00062 {
00063 if ( v1->weather[0] && v2->weather[0] )
00064 return v1->weather[0]->art.to_ulong() < v2->weather[0]->art.to_ulong();
00065 else
00066 return v1->name < v2->name;
00067 }
00068
00069 bool mineComp( const MineType* v1, const MineType* v2 )
00070 {
00071 return v1->id < v2->id;
00072 }
00073
00074
00075 void sortItems( vector<VehicleType*>& vec )
00076 {
00077 sort( vec.begin(), vec.end(), vehicleComp );
00078 }
00079
00080 void sortItems( vector<BuildingType*>& vec )
00081 {
00082 sort( vec.begin(), vec.end(), buildingComp );
00083 }
00084
00085 void sortItems( vector<ObjectType*>& vec )
00086 {
00087 sort( vec.begin(), vec.end(), objectComp );
00088 }
00089
00090 void sortItems( vector<TerrainType*>& vec )
00091 {
00092 sort( vec.begin(), vec.end(), terrainComp );
00093 }
00094
00095 void sortItems( vector<MineType*>& vec )
00096 {
00097 sort( vec.begin(), vec.end(), mineComp );
00098 }
00099
00100
00101 void MapComponent::displayClip( PG_Widget* parent, SDL_Surface * surface, const PG_Rect & src, const PG_Rect & dst ) const
00102 {
00103 if ( !getClippingSurface().valid() )
00104 getClippingSurface() = Surface::createSurface( displayWidth() + 10, displayHeight() + fontHeight + 10, 32, 0 );
00105
00106 getClippingSurface().Fill(0);
00107 display( getClippingSurface(), SPoint( 0, 0 ) );
00108
00109 static PG_ThemeWidget* fontProvidingWidget = NULL;
00110 if ( !fontProvidingWidget )
00111 fontProvidingWidget = new PG_ThemeWidget( NULL, PG_Rect::null , false, "MapedItemSelector" );
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 PG_Draw::BlitSurface( getClippingSurface().getBaseSurface(), src, surface, dst);
00124
00125 int x = dst.x;
00126 int y = dst.y + displayHeight() + fontProvidingWidget ->GetFontAscender() - src.y;
00127
00128 PG_FontEngine::RenderText( surface, dst, x, y, getItemType()->getName(), fontProvidingWidget ->GetFont() );
00129 }
00130
00131
00132
00133
00134 int VehicleItem::place( GameMap* gamemap, const MapCoordinate& mc, const VehicleType* v, int owner )
00135 {
00136 MapField* fld = gamemap->getField(mc);
00137 if ( !fld )
00138 return -1;
00139
00140 const VehicleType* veh = v;
00141
00142 if ( !veh )
00143 return -2;
00144
00145 if ( owner >= 8 )
00146 return -3;
00147
00148 bool accessible = veh->terrainaccess.accessible ( fld->bdt );
00149 if ( veh->height >= chtieffliegend )
00150 accessible = true;
00151
00152 if ( fld->building || ( !accessible && !gamemap->getgameparameter( cgp_movefrominvalidfields)) )
00153 return -3;
00154
00155
00156 if ( fld->vehicle ) {
00157 if ( fld->vehicle->typ != veh ) {
00158 delete fld->vehicle;
00159 fld->vehicle = NULL;
00160 } else {
00161 fld->vehicle->convert( owner );
00162 return 1;
00163 }
00164 }
00165 fld->vehicle = new Vehicle ( v, gamemap, owner );
00166 fld->vehicle->setnewposition ( mc );
00167 fld->vehicle->fillMagically();
00168
00169 for ( int i = 0; i < 9; ++i ) {
00170 if ( fld->vehicle->typ->height & (1 << i )) {
00171 fld->vehicle->height = 1 << i;
00172 if ( terrainaccessible( fld, fld->vehicle ) == 2 )
00173 break;
00174 }
00175 if ( i == 8 ) {
00176 delete fld->vehicle;
00177 fld->vehicle = NULL;
00178 return -3;
00179 }
00180 }
00181 fld->vehicle->resetMovement();
00182 return 1;
00183
00184 }
00185
00186 int VehicleItem::place( const MapCoordinate& mc ) const
00187 {
00188 return place( actmap, mc, item, selection.getPlayer() );
00189 }
00190
00191 Surface BuildingItem::clippingSurface;
00192 Surface BuildingItem::fullSizeImage;
00193 int BuildingItem::place( const MapCoordinate& mc ) const
00194 {
00195 if ( selection.getPlayer() > 8 )
00196 return -3;
00197
00198 int f = 0;
00199 for ( int x = 0; x < 4; x++ )
00200 for ( int y = 0; y < 6; y++ )
00201 if ( bld->fieldExists ( BuildingType::LocalCoordinate(x, y) )) {
00202 MapCoordinate mc = bld->getFieldCoordinate ( actmap->getCursor() , BuildingType::LocalCoordinate (x, y) );
00203 if ( !actmap->getField (mc) )
00204 return -1;
00205
00206 if ( bld->terrainaccess.accessible ( actmap->getField (mc)->bdt ) <= 0 )
00207 f++;
00208 }
00209 if ( f ) {
00210 if (choice_dlg("Invalid terrain for building !","~i~gnore","~c~ancel") == 2)
00211 return -1 ;
00212 }
00213
00214 putbuilding( actmap, actmap->getCursor(), selection.getPlayer() * 8, bld, bld->construction_steps );
00215 return 0;
00216 }
00217
00218 void BuildingItem::display( Surface& s, const SPoint& pos ) const
00219 {
00220 if ( !fullSizeImage.valid() )
00221 fullSizeImage = Surface::createSurface( displayWidth()*2 + 10, displayHeight()*2 + 30, 32, 0 );
00222 fullSizeImage.FillTransparent();
00223 if ( actmap )
00224 bld->paint ( fullSizeImage, SPoint(0,0), actmap->getPlayer( selection.getPlayer()).getPlayerColor() );
00225 else
00226 bld->paint ( fullSizeImage, SPoint(0,0) );
00227
00228 MegaBlitter<colorDepth,colorDepth,ColorTransform_None,ColorMerger_AlphaOverwrite,SourcePixelSelector_DirectZoom,TargetPixelSelector_Valid> blitter;
00229 blitter.setZoom( 0.5 );
00230 blitter.blit( fullSizeImage, s, pos );
00231 }
00232
00233
00234
00235
00236 int ObjectItem::place( const MapCoordinate& mc ) const
00237 {
00238 if ( !actmap->getField(mc)->addobject( item ) )
00239 if ( SDL_GetKeyState(NULL)[SDLK_LCTRL] || SDL_GetKeyState(NULL)[SDLK_RCTRL] || choice_dlg("object cannot be built here\n(bypass this dialog by pressing <ctrl>)","~c~ancel","~i~gnore") == 2)
00240 actmap->getField(mc)->addobject( item, -1, true );
00241
00242 return 0;
00243 }
00244
00245
00246 bool ObjectItem::remove ( const MapCoordinate& mc ) const
00247 {
00248 if ( item && actmap->getField(mc)->checkForObject(item) ) {
00249 actmap->getField(mc)->removeObject ( item );
00250 return true;
00251 }
00252 return false;
00253
00254 }
00255
00256
00257 template<typename T> Surface BasicItem<T>::clippingSurface;
00258 int TerrainItem::place( const MapCoordinate& mc ) const
00259 {
00260 MapField* fld = actmap->getField(mc);
00261 fld->typ = item->weather[0];
00262 fld->setWeather( selection.getWeather() );
00263 fld->setparams();
00264 for ( int d = 0; d < 6; ++d ) {
00265 MapCoordinate pos = getNeighbouringFieldCoordinate( mc, d );
00266 MapField* fld = actmap->getField( pos );
00267 if ( fld )
00268 for ( MapField::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); ++i )
00269 calculateobject( pos, false, i->typ, actmap );
00270 }
00271 return 0;
00272 }
00273
00274
00275 int MineItem::place( const MapCoordinate& mc ) const
00276 {
00277 actmap->getField(mc)->putmine( selection.getPlayer(), MineTypes(item->id), MineBasePunch[item->id-1] );
00278 return 0;
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 class CargoItemFactory: public MapItemTypeWidgetFactory<MapItemTypeWidget< VehicleType > > {
00302 typedef MapItemTypeWidgetFactory<MapItemTypeWidget< VehicleType > > Parent;
00303 typedef MapItemTypeWidget< VehicleType > WidgetType;
00304 ContainerBase* container;
00305 protected:
00306 bool isFiltered( const ItemType& item ) {
00307 if ( Parent::isFiltered( item ))
00308 return true;
00309
00310 if ( !container->baseType->vehicleFit( &item ))
00311 return true;
00312
00313 bool result = true;
00314 Vehicle* unit = new Vehicle ( &item, actmap, container->getOwner() );
00315 if ( container->vehicleFit ( unit ))
00316 result = false;
00317 delete unit;
00318 return result;
00319 };
00320
00321 public:
00322 CargoItemFactory( ContainerBase* container_ ) : Parent(vehicleTypeRepository), container( container_ ) {};
00323
00324 void itemSelected( const SelectionWidget* widget, bool mouse )
00325 {
00326 if ( !widget )
00327 return;
00328
00329 const WidgetType* mapItemWidget = dynamic_cast<const WidgetType*>(widget);
00330 assert( mapItemWidget );
00331 if ( mapItemWidget->getItem() ) {
00332 Vehicle* unit = new Vehicle ( mapItemWidget->getItem(), actmap, container->getOwner() );
00333 unit->fillMagically();
00334 unit->setnewposition ( container->getPosition() );
00335 unit->tank.material = 0;
00336 unit->tank.fuel = 0;
00337 if ( container->vehicleFit ( unit )) {
00338 unit->tank.material = unit->getStorageCapacity().material;
00339 unit->tank.fuel = unit->getStorageCapacity().fuel;
00340
00341 if ( !container->vehicleFit ( unit )) {
00342 unit->tank.material = 0;
00343 unit->tank.fuel = 0;
00344 displaymessage("Warning:\nThe unit you just set could not be loaded with full material and fuel\nPlease set these values manually",1);
00345 }
00346 container->addToCargo( unit );
00347
00348 } else {
00349 delete unit;
00350 displaymessage("The unit could not be loaded !",1);
00351 }
00352 }
00353 }
00354
00355 };
00356
00357
00358 void addCargo( ContainerBase* container )
00359 {
00360 ItemSelectorWindow isw( NULL, PG_Rect( 100, 100, 280, 600), "cargo", new CargoItemFactory( container ) );
00361 isw.Show();
00362 isw.RunModal();
00363 }
00364
00365
00366
00367
00368
00369 class ProductionItemFactory: public MapItemTypeWidgetFactory<MapItemTypeWidget< VehicleType > > {
00370 typedef MapItemTypeWidgetFactory<MapItemTypeWidget< VehicleType > > Parent;
00371 typedef MapItemTypeWidget< VehicleType > WidgetType;
00372 ContainerBase* container;
00373 const VehicleType* selectedItem;
00374 protected:
00375 bool isFiltered( const ItemType& item ) {
00376 if ( Parent::isFiltered( item ))
00377 return true;
00378
00379 if ( !container->baseType->vehicleFit( &item ))
00380 return true;
00381
00382 if ( !(container->baseType->vehicleCategoriesProduceable & (1 << item.movemalustyp)))
00383 return true;
00384
00385 return false;
00386 };
00387
00388 public:
00389 ProductionItemFactory( ContainerBase* container_ ) : Parent(vehicleTypeRepository), container( container_ ), selectedItem(NULL) {};
00390
00391
00392 void itemMarked ( const SelectionWidget* widget )
00393 {
00394 if ( !widget )
00395 return;
00396
00397 const WidgetType* mapItemWidget = dynamic_cast<const WidgetType*>(widget);
00398 assert( mapItemWidget );
00399 const VehicleType* type = mapItemWidget->getItem();
00400 if ( type ) {
00401 selectedItem = type;
00402 }
00403 };
00404
00405 void itemSelected( const SelectionWidget* widget, bool mouse )
00406 {
00407 itemMarked( widget );
00408 }
00409
00410 const VehicleType* getSelectedVehicleType()
00411 {
00412 return selectedItem;
00413 }
00414
00415 };
00416
00417
00418 class AvailableProductionItemFactory: public SelectionItemFactory, public SigC::Object {
00419 private:
00420 const ContainerBase* container;
00421 const VehicleType* selectedItem;
00422 protected:
00423 ContainerBase::Production::const_iterator it;
00424 ContainerBase::Production& production;
00425 public:
00426 AvailableProductionItemFactory( ContainerBase* container_, ContainerBase::Production& prod ) : container( container_ ), selectedItem(NULL), production( prod )
00427 {
00428 restart();
00429 };
00430
00431 void restart()
00432 {
00433
00434 it = production.begin();
00435 }
00436
00437 SelectionWidget* spawnNextItem( PG_Widget* parent, const PG_Point& pos )
00438 {
00439 if ( it != production.end() ) {
00440 const VehicleType* v = *(it++);
00441 return new VehicleTypeBaseWidget( parent, pos, parent->Width() - 15, v, actmap->getCurrentPlayer() );
00442 } else
00443 return NULL;
00444 };
00445
00446 void itemMarked ( const SelectionWidget* widget )
00447 {
00448 if ( !widget )
00449 return;
00450
00451 const VehicleTypeBaseWidget* mapItemWidget = dynamic_cast<const VehicleTypeBaseWidget*>(widget);
00452 assert( mapItemWidget );
00453 const VehicleType* type = mapItemWidget->getVehicletype();
00454 if ( type ) {
00455 selectedItem = type;
00456 }
00457 }
00458
00459
00460 void itemSelected( const SelectionWidget* widget, bool mouse )
00461 {
00462 itemMarked( widget );
00463 }
00464
00465 const VehicleType* getSelectedVehicleType()
00466 {
00467 return selectedItem;
00468 }
00469
00470 };
00471
00472
00473
00474 class ProductionEditorWindow : public ASC_PG_Dialog {
00475 private:
00476 ProductionItemFactory* allTypesFactory;
00477 ItemSelectorWidget* allTypes;
00478
00479 AvailableProductionItemFactory* productionFactory;
00480 ItemSelectorWidget* productionWidget;
00481
00482
00483 ContainerBase* container;
00484
00485 ContainerBase::Production production;
00486
00487
00488 bool ok()
00489 {
00490 container->setProductionLines( production );
00491 QuitModal();
00492 return true;
00493 }
00494
00495 bool addOne()
00496 {
00497 const VehicleType* v = allTypesFactory->getSelectedVehicleType();
00498 if ( !v )
00499 return false;
00500
00501 if ( find( production.begin(), production.end(), v ) == production.end() ) {
00502 production.push_back( v );
00503 productionWidget->reLoad( true );
00504 return true;
00505 }
00506 return false;
00507 }
00508
00509 bool removeOne()
00510 {
00511 const VehicleType* v = productionFactory->getSelectedVehicleType();
00512 if ( !v )
00513 return false;
00514
00515 ContainerBase::Production::iterator i = find( production.begin(), production.end(), v );
00516 if ( i != production.end() ) {
00517 production.erase( i );
00518 productionWidget->reLoad( true );
00519 return true;
00520 }
00521 return false;
00522 }
00523
00524
00525 public:
00526 ProductionEditorWindow ( ContainerBase* container ) : ASC_PG_Dialog ( NULL, PG_Rect( 20,20, 700, 550 ), "Unit Production" )
00527 {
00528 this->container = container;
00529 production = container->getProduction();
00530
00531 const int centerSpace = 80;
00532 const int border = 10;
00533
00534 allTypesFactory = new ProductionItemFactory( container );
00535 allTypes = new ItemSelectorWidget( this, PG_Rect( border, 50, (my_width- centerSpace) / 2 - 2 * border, my_height - 100 ), allTypesFactory );
00536
00537 productionFactory = new AvailableProductionItemFactory( container, production );
00538 productionWidget = new ItemSelectorWidget( this, PG_Rect( (my_width + centerSpace) / 2 + border, 50, (my_width- centerSpace) / 2 - 2 * border, my_height - 100 ), productionFactory);
00539
00540
00541
00542 PG_Button* addB = new PG_Button( this, PG_Rect( (my_width - centerSpace) / 2, 100, centerSpace, 30 ), "->" );
00543 addB->sigClick.connect( SigC::slot( *this, &ProductionEditorWindow::addOne ));
00544
00545 PG_Button* removeB = new PG_Button( this, PG_Rect( (my_width - centerSpace) / 2, 140, centerSpace, 30 ), "<-" );
00546 removeB->sigClick.connect( SigC::slot( *this, &ProductionEditorWindow::removeOne ));
00547
00548
00549 PG_Button* ok = new PG_Button( this, PG_Rect( my_width - 100, my_height - 40, 90, 30 ), "OK" );
00550 ok->sigClick.connect( SigC::slot( *this, &ProductionEditorWindow::ok ));
00551 };
00552
00553 };
00554
00555
00556 void editProduction( ContainerBase* container )
00557 {
00558 ProductionEditorWindow pew ( container );
00559 pew.Show();
00560 pew.RunModal();
00561 }
00562