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