00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <pgimage.h>
00012 #include "../paradialog.h"
00013 #include "../typen.h"
00014 #include "../vehicletype.h"
00015 #include "../vehicle.h"
00016 #include "../iconrepository.h"
00017 #include "../spfst.h"
00018 #include "../dialog.h"
00019
00020 #include "../textfiletags.h"
00021 #include "../windowing.h"
00022
00023 void assignWeaponInfo ( Panel* panel, PG_Widget* widget, const SingleWeapon& weapon )
00024 {
00025 int scalarType = weapon.service() ? cwservicen : weapon.getScalarWeaponType();
00026 panel->setImage( "weapon_symbol1", IconRepository::getIcon(SingleWeapon::getIconFileName( scalarType ) + "-small.png"), widget );
00027
00028 panel->setLabelText( "weapon_text1", weapon.getName(), widget );
00029 panel->setLabelText( "weapon_reactionfire", weapon.reactionFireShots, widget );
00030 panel->setLabelText( "weapon_maxammo", weapon.count, widget );
00031 panel->setLabelText( "weapon_canshoot", weapon.shootable()? "yes" : "no", widget );
00032 panel->setLabelText( "weapon_canrefuel", weapon.canRefuel()? "yes" : "no", widget );
00033 panel->setLabelText( "weapon_strenghtmax", weapon.maxstrength, widget );
00034 panel->setLabelText( "weapon_strenghtmin", weapon.minstrength, widget );
00035 panel->setLabelText( "weapon_distancemin", (weapon.mindistance+9)/10, widget );
00036 panel->setLabelText( "weapon_distancemax", weapon.maxdistance/10, widget );
00037
00038 for ( int i = 0; i < 8; ++i ) {
00039 if ( weapon.targ & (1<< i)) {
00040 panel->setWidgetTransparency( ASCString("weapon_notarget_") + heightTags[i] , 255 );
00041 panel->setWidgetTransparency( ASCString("weapon_target_") + heightTags[i] , 0 );
00042 } else {
00043 panel->setWidgetTransparency( ASCString("weapon_notarget_") + heightTags[i] , 0 );
00044 panel->setWidgetTransparency( ASCString("weapon_target_") + heightTags[i] , 255 );
00045 }
00046
00047 if ( weapon.sourceheight & (1<< i)) {
00048 panel->setWidgetTransparency( ASCString("weapon_nosource_") + heightTags[i] , 255 );
00049 panel->setWidgetTransparency( ASCString("weapon_source_") + heightTags[i] , 0 );
00050 } else {
00051 panel->setWidgetTransparency( ASCString("weapon_nosource_") + heightTags[i] , 0 );
00052 panel->setWidgetTransparency( ASCString("weapon_source_") + heightTags[i] , 255 );
00053 }
00054 }
00055 }
00056
00057 const int paneNum = 5;
00058 static const char* paneName[paneNum] = { "information", "movement", "weapons", "transport", "description" };
00059
00060 class UnitInfoDialog : public Panel {
00061 const Vehicle* veh;
00062 const Vehicletype* vt;
00063 PG_Widget* weaponGraph;
00064 int currentWeapon;
00065 typedef vector< pair<int,int> > EntranceHeights;
00066 EntranceHeights entranceHeights;
00067 Surface infoImage;
00068
00069 bool eventKeyDown(const SDL_KeyboardEvent* key)
00070 {
00071 if ( key->keysym.sym == SDLK_ESCAPE ) {
00072 QuitModal();
00073 return true;
00074 }
00075 return false;
00076 };
00077
00078
00079
00080 void registerSpecialDisplay( const ASCString& name )
00081 {
00082 SpecialDisplayWidget* sdw = dynamic_cast<SpecialDisplayWidget*>( FindChild( name, true ) );
00083 if ( sdw )
00084 sdw->display.connect( SigC::slot( *this, &UnitInfoDialog::painter ));
00085 };
00086
00087 void registerSpecialInput( const ASCString& name )
00088 {
00089 SpecialInputWidget* siw = dynamic_cast<SpecialInputWidget*>( FindChild( name, true ) );
00090 if ( siw )
00091 siw->sigMouseButtonDown.connect( SigC::slot( *this, &UnitInfoDialog::onClick ));
00092 };
00093
00094 bool onClick ( PG_MessageObject* obj, const SDL_MouseButtonEvent* event ) {
00095 PG_Widget* w = dynamic_cast<PG_Widget*>(obj);
00096 if ( w ) {
00097 click( w->GetName() );
00098 return true;
00099 }
00100 return false;
00101 };
00102
00103 bool onEntranceClick ( PG_MessageObject* obj, const SDL_MouseButtonEvent* event, int entranceNum ) {
00104 if ( vt ) {
00105 PG_Widget* swi = FindChild( "single_weapon_info", true );
00106 if ( swi ) {
00107 ContainerBaseType::TransportationIO tio = vt->entranceSystems[entranceNum];
00108 setWidgetTransparency( "pad_transport_in", tio.mode & ContainerBaseType::TransportationIO::In ? 0 : 255 );
00109 setWidgetTransparency( "pad_transport_out", tio.mode & ContainerBaseType::TransportationIO::Out ? 0 : 255 );
00110 setWidgetTransparency( "pad_transport_docking", tio.mode & ContainerBaseType::TransportationIO::Docking ? 0 : 255 );
00111
00112 for ( int i = 0; i < cmovemalitypenum; ++i )
00113 if ( (vt->vehicleCategoriesStorable & (1<<i)) && (tio.vehicleCategoriesLoadable & (1<<i)))
00114 setImage( ASCString("unitpad_transport_") + unitCategoryTags[i], IconRepository::getIcon("pad_symbol_ok.png") );
00115 else
00116 setImage( ASCString("unitpad_transport_") + unitCategoryTags[i], IconRepository::getIcon("pad_symbol_no.png") );
00117
00118 ASCString s;
00119 for ( int i = 0; i < ContainerBaseType::functionNum; ++i )
00120 if ( tio.requiresUnitFeature.test( i )) {
00121 if ( s.length() )
00122 s += ", ";
00123 s += ContainerBaseType::getFunctionName( ContainerBaseType::ContainerFunctions(i));
00124 }
00125 setLabelText( "unitpad_transport_specialfunctions", s );
00126
00127 setLabelText( "unitpad_transport_attackafterwards", tio.disableAttack ? "no" : "yes" );
00128
00129 entranceHeights.clear();
00130 for ( int i = 0; i < 8; ++i )
00131 if ( vt->height & (1 << i) & tio.container_height )
00132 for ( int j = 0; j < 8; ++j )
00133 if ( !tio.height_abs || tio.height_abs & (1 <<j ))
00134 if ( tio.height_rel == -100 || getheightdelta( i, j ) == tio.height_rel )
00135 entranceHeights.push_back( make_pair(i,j));
00136
00137 PG_Widget* w = FindChild( "unitpad_transport_leveldisplay", true );
00138 if ( w )
00139 w->Update();
00140 }
00141
00142 for ( int i = 0; i < vt->entranceSystems.size(); ++i ) {
00143 ASCString n = "pad_transport_square" + ASCString::toString(i);
00144 PG_Widget* w = FindChild( n, true );
00145 if ( w ) {
00146 if ( i == entranceNum )
00147 w->SetTransparency( 0 );
00148
00149 else
00150 w->SetTransparency( 255 );
00151
00152
00153 }
00154 }
00155 Update();
00156 }
00157 return true;
00158 };
00159
00160 bool onWeaponClick ( PG_MessageObject* obj, const SDL_MouseButtonEvent* event, int weaponNum ) {
00161 if ( vt ) {
00162 PG_Widget* swi = FindChild( "single_weapon_info", true );
00163 if ( swi )
00164 assignWeaponInfo( this, swi, vt->weapons.weapon[weaponNum] );
00165
00166 for ( int i = 0; i < vt->weapons.count; ++i ) {
00167 ASCString n = "pad_weaponbar" + ASCString::toString(i);
00168 PG_Widget* w = FindChild( n, true );
00169 if ( w ) {
00170 if ( i == weaponNum )
00171 w->SetTransparency( 0 );
00172
00173 else
00174
00175 w->SetTransparency( 255 );
00176
00177 }
00178 }
00179 Update();
00180 currentWeapon = weaponNum;
00181 if ( weaponGraph )
00182 weaponGraph->GetParent()->Update();
00183 }
00184 return true;
00185 };
00186
00187 SPoint getWeaponGraphCoords( int maxdist, int maxstrength, int dist, int strength )
00188 {
00189 const int border = 0;
00190 SPoint p;
00191 if( maxdist < 2 )
00192 maxdist = 2;
00193
00194 p.x = (weaponGraph->Width() - 2 * border ) * dist / maxdist + border;
00195 p.y = weaponGraph->Height() - border - (weaponGraph->Height() - 2 * border ) * strength / maxstrength ;
00196 p.x += weaponGraph->my_xpos;
00197 p.y += weaponGraph->my_ypos;
00198 return p;
00199 }
00200
00201 void painter ( const PG_Rect &src, const ASCString& name, const PG_Rect &dst)
00202 {
00203 Surface screen = Surface::Wrap( PG_Application::GetScreen() );
00204
00205 if ( name == "unitpad_unitsymbol" )
00206 if ( vt )
00207 if ( veh )
00208 vt->paint( screen, SPoint( dst.x, dst.y ), veh->getMap()->getPlayer(veh).getPlayerColor() );
00209 else
00210 vt->paint( screen, SPoint( dst.x, dst.y ));
00211
00212 if ( name == "unitpad_weapon_diagram" ) {
00213 if ( vt && weaponGraph ) {
00214 int maxdist = 0;
00215 int maxstrength = 0;
00216 for ( int i = 0; i < vt->weapons.count; ++i )
00217 if ( vt->weapons.weapon[i].shootable() ) {
00218 maxdist = max ( maxdist, vt->weapons.weapon[i].maxdistance );
00219 maxstrength = max ( maxstrength, vt->weapons.weapon[i].maxstrength );
00220 }
00221
00222 setLabelText( "unitpad_weapon_diagram_maxdist", max(maxdist / maxmalq, 2 ) );
00223 setLabelText( "unitpad_weapon_diagram_maxstrength", maxstrength );
00224
00225 if( maxdist > 0 && maxstrength > 0 )
00226 for ( int i = 0; i < vt->weapons.count; ++i ) {
00227 int mind = (vt->weapons.weapon[i].mindistance+maxmalq-1) / maxmalq;
00228 int maxd = vt->weapons.weapon[i].maxdistance / maxmalq;
00229 int linewidth;
00230 int linecolor;
00231 if ( currentWeapon == i ) {
00232 linewidth = 2;
00233 linecolor = 0xff7777;
00234 } else {
00235 linewidth = 1;
00236 linecolor = 0xffffff;
00237 }
00238
00239 if ( mind == maxd ) {
00240 SPoint p = getWeaponGraphCoords( maxdist/maxmalq, maxstrength, mind, vt->weapons.weapon[i].maxstrength );
00241 PG_Draw::DrawLine( PG_Application::GetScreen(), p.x , p.y - 2, p.x , p.y + 2, linecolor, linewidth );
00242 PG_Draw::DrawLine( PG_Application::GetScreen(), p.x - 2, p.y , p.x + 2, p.y , linecolor, linewidth );
00243 } else {
00244 SPoint p = getWeaponGraphCoords( maxdist/maxmalq, maxstrength, mind, vt->weapons.weapon[i].maxstrength );
00245 SPoint p2 = getWeaponGraphCoords( maxdist/maxmalq, maxstrength, maxd, vt->weapons.weapon[i].minstrength );
00246 PG_Draw::DrawLine( PG_Application::GetScreen(), p.x , p.y , p2.x, p2.y , linecolor, linewidth );
00247 }
00248 }
00249 }
00250 }
00251 if ( name == "unitpad_transport_leveldisplay" ) {
00252 int xoffs = 0;
00253 for ( EntranceHeights::iterator i = entranceHeights.begin(); i != entranceHeights.end(); ++i ) {
00254 for ( int j = 0; j < 2; ++j ) {
00255 Surface& icon = IconRepository::getIcon( ASCString("height-a") + ASCString::toString( j==0 ? i->second : i->first) + ".png");
00256 int y;
00257 if ( j == 0)
00258 y = 27;
00259 else
00260 y = 2;
00261 screen.Blit( icon, SPoint( dst.x + xoffs+2, dst.y+y ));
00262 }
00263 Surface& icon = IconRepository::getIcon("pad_transport_leveldisplay.png");
00264 screen.Blit( icon, SPoint( dst.x + xoffs, dst.y ));
00265 xoffs += icon.w() + 3;
00266 }
00267 }
00268 };
00269
00270 void activate( const ASCString& pane ) {
00271 BulkGraphicUpdates bgu ( this );
00272
00273 for ( int i = 0; i < paneNum; ++i )
00274 if ( ASCString( paneName[i]) != pane )
00275 hide( paneName[i] );
00276
00277 for ( int i = 0; i < paneNum; ++i )
00278 if ( ASCString( paneName[i]) == pane )
00279 show( paneName[i] );
00280 };
00281
00282 void click( const ASCString& name ) {
00283 for ( int i = 0; i < paneNum; ++i)
00284 if ( name == ASCString("padclick_") + paneName[i] )
00285 activate(paneName[i]);
00286 if ( name == "padclick_exit" )
00287 QuitModal();
00288 };
00289
00290 public:
00291
00292
00293 UnitInfoDialog (PG_Widget *parent, const Vehicle* vehicle, const Vehicletype* vehicleType )
00294 : Panel( parent, PG_Rect::null, "UnitInfoDialog", false ), veh(vehicle), vt( vehicleType ), weaponGraph(NULL), currentWeapon(-1) {
00295 sigClose.connect( SigC::slot( *this, &UnitInfoDialog::QuitModal ));
00296
00297 if( veh )
00298 vt = veh->typ;
00299
00300 try {
00301 setup();
00302 }
00303 catch ( ParsingError err ) {
00304 displaymessage( err.getMessage(), 1 );
00305 return;
00306 }
00307 catch ( ... ) {
00308 displaymessage( "unknown exception", 1 );
00309 return;
00310 }
00311
00312 if ( !vt->infoImageFilename.empty() && exist( vt->infoImageFilename )) {
00313 PG_Image* img = dynamic_cast<PG_Image*>(FindChild( "unitpad_3dpic", true ));
00314 if ( img ) {
00315 tnfilestream stream ( vt->infoImageFilename, tnstream::reading );
00316 infoImage.readImageFile( stream );
00317 img->SetDrawMode( PG_Draw::STRETCH );
00318 img->SetImage( infoImage.getBaseSurface(), false );
00319 img->SizeWidget( img->GetParent()->w, img->GetParent()->h );
00320 }
00321 }
00322
00323 if ( veh )
00324 setLabelText( "unitpad_unitname", veh->getName() );
00325 else
00326 if ( vt )
00327 setLabelText( "unitpad_unitname", vt->getName() );
00328
00329 setLabelText( "unitpad_unitcategory", cmovemalitypes[ vt->movemalustyp ] );
00330 registerSpecialDisplay( "unitpad_unitsymbol");
00331 registerSpecialDisplay( "unitpad_weapon_diagram");
00332 registerSpecialDisplay( "unitpad_transport_transporterlevel");
00333 registerSpecialDisplay( "unitpad_transport_unitlevel");
00334 registerSpecialDisplay( "unitpad_transport_leveldisplay");
00335
00336 weaponGraph = FindChild( "unitpad_weapon_diagram", true );
00337
00338 if ( vt ) {
00339 setLabelText( "unitpad_unitarmor", vt->armor );
00340 setLabelText( "unitpad_unitweight", vt->weight );
00341 setLabelText( "unitpad_unitview", vt->view );
00342 setLabelText( "unitpad_unitjamming", vt->jamming );
00343 setLabelText( "unitpad_unitcostenergy", vt->productionCost.energy );
00344 setLabelText( "unitpad_unitcostmaterial", vt->productionCost.material );
00345 setLabelText( "unitpad_unitcostfuel", vt->productionCost.fuel );
00346 setLabelText( "unitpad_unittankfuel", vt->getStorageCapacity(0).fuel );
00347 setLabelText( "unitpad_unittankenergy", vt->getStorageCapacity(0).energy );
00348 setLabelText( "unitpad_unittankmaterial", vt->getStorageCapacity(0).material );
00349
00350
00351 ASCString abilities = "#indent=0,15#";
00352 for ( int i = 0; i < ContainerBaseType::functionNum; ++i )
00353 if ( vt->hasFunction(ContainerBaseType::ContainerFunctions(i)))
00354 abilities += ContainerBaseType::getFunctionName(ContainerBaseType::ContainerFunctions(i)) + ASCString("\n");
00355 if ( vt->wait )
00356 abilities += "Wait for attack\n";
00357 setLabelText( "unitpad_unitabilities", abilities );
00358
00359
00360 setLabelText( "unitpad_unitmove_unitfuelconsumption", vt->fuelConsumption );
00361 for ( int i = 0; i< 8; ++i )
00362 setLabelText( ASCString("unitpad_unitmove_") + heightTags[i], vt->movement[i] );
00363
00364 if ( vt->maxwindspeedonwater < 255 && vt->maxwindspeedonwater > 0 )
00365 setLabelText( "unitpad_unitmove_windresistance", vt->maxwindspeedonwater );
00366 else
00367 setLabelText( "unitpad_unitmove_windresistance", "-" );
00368
00369 if ( vt->maxLoadableUnits ) {
00370 setLabelText( "unitpad_transport_maxtotalweight", vt->maxLoadableWeight );
00371 setLabelText( "unitpad_transport_maxsingleweight", vt->maxLoadableUnitSize );
00372 setLabelText( "unitpad_transport_loadableunits", vt->maxLoadableUnits );
00373 }
00374 if ( vt->weapons.count >= 1 )
00375 onWeaponClick( NULL, NULL, 0 );
00376 }
00377
00378
00379 for ( int i = 0; i < paneNum; ++i )
00380 registerSpecialInput( ASCString("padclick_") + paneName[i] );
00381 registerSpecialInput( "padclick_exit" );
00382
00383 setLabelText( "unitpad_description_text", vt->infotext );
00384
00385 activate(paneName[0]);
00386 Show();
00387
00388 };
00389
00390 void userHandler( const ASCString& label, PropertyReadingContainer& pc, PG_Widget* parent, WidgetParameters widgetParams )
00391 {
00392 if ( label == "unitpad_heightchange" && vt ) {
00393 int yoffset = 0;
00394 for ( int i = 0; i < vt->heightChangeMethodNum; ++i ) {
00395 int srcLevelCount = 0;
00396 for ( int j = 0; j < 8; ++j )
00397 if ( vt->height & vt->heightChangeMethod[i].startHeight & (1 << j))
00398 ++srcLevelCount;
00399
00400 pc.openBracket( "LineWidget" );
00401 PG_Rect r = parseRect( pc, parent);
00402 r.y += yoffset;
00403 r.my_height *= (srcLevelCount-1) / 3 + 1;
00404 widgetParams.runTextIO( pc );
00405
00406 SpecialInputWidget* sw = new SpecialInputWidget ( parent, r );
00407 parsePanelASCTXT( pc, sw, widgetParams );
00408 pc.closeBracket();
00409 yoffset += sw->Height();
00410
00411
00412
00413 int counter = 0;
00414 for ( int j = 0; j < 8; ++j )
00415 if ( vt->height & vt->heightChangeMethod[i].startHeight & (1 << j)) {
00416 ASCString filename = "height-a" + ASCString::toString(j) + ".png";
00417 int xoffs = 3 + IconRepository::getIcon(filename).w() * (counter % 3 );
00418 int yoffs = 2 + IconRepository::getIcon(filename).h() * (counter / 3 );
00419 new PG_Image( sw, PG_Point( xoffs, yoffs ), IconRepository::getIcon(filename).getBaseSurface(), false );
00420 ++counter;
00421 }
00422
00423 ASCString delta = ASCString::toString( vt->heightChangeMethod[i].heightDelta );
00424 if ( vt->heightChangeMethod[i].heightDelta > 0 )
00425 delta = "+" + delta;
00426 setLabelText( "unitpad_move_changeheight_change", delta, sw );
00427
00428 setLabelText( "unitpad_move_changeheight_movepoints", vt->heightChangeMethod[i].moveCost, sw );
00429 setLabelText( "unitpad_move_changeheight_distance", vt->heightChangeMethod[i].dist, sw );
00430 }
00431 }
00432 if ( label == "unitpad_terrainaccess" && vt ) {
00433 int yoffset = 0;
00434 for ( int i = 0; i < terrainPropertyNum ; ++i ) {
00435 if ( vt->terrainaccess.terrain.test(i) || vt->terrainaccess.terrainkill.test(i) || vt->terrainaccess.terrainnot.test(i) || vt->terrainaccess.terrainreq.test(i) ) {
00436 pc.openBracket( "LineWidget" );
00437 widgetParams.runTextIO( pc );
00438 PG_Rect r = parseRect( pc, parent);
00439 r.y += yoffset;
00440
00441
00442 SpecialInputWidget* sw = new SpecialInputWidget ( parent, r );
00443 parsePanelASCTXT( pc, sw, widgetParams );
00444 pc.closeBracket();
00445 yoffset += sw->Height();
00446
00447 setLabelText( "unitpad_unitmove_terraintype", terrainProperty[i], sw);
00448
00449 PG_Widget* w = sw->FindChild("unitpad_unitmove_terrainaccess", true);
00450 if ( w ) {
00451 int xoffs = 0;
00452 static const char* iconName[] = {"pad_symbol_ok.png", "pad_symbol_warn.png", "pad_symbol_no.png", "pad_symbol_kill.png" };
00453 const TerrainBits* bits[] = { &vt->terrainaccess.terrain, &vt->terrainaccess.terrainreq, &vt->terrainaccess.terrainnot, &vt->terrainaccess.terrainkill };
00454 for ( int icon = 0; icon < 4; ++icon ) {
00455 bool set = bits[icon]->test(i);
00456
00457 if ( set ) {
00458 PG_Image* img = new PG_Image( w, PG_Point( xoffs, 0 ), IconRepository::getIcon( iconName[icon] ).getBaseSurface(), false );
00459 xoffs += img->Width();
00460 }
00461 }
00462 }
00463 }
00464 }
00465 }
00466 if ( label == "unitpad_weaponlist" && vt ) {
00467 int yoffset = 0;
00468 for ( int i = 0; i < vt->weapons.count ; ++i ) {
00469 pc.openBracket( "LineWidget" );
00470 widgetParams.runTextIO( pc );
00471 PG_Rect r = parseRect( pc, parent);
00472 r.y += yoffset;
00473
00474
00475 SpecialInputWidget* sw = new SpecialInputWidget ( parent, r );
00476 parsePanelASCTXT( pc, sw, widgetParams );
00477 rename( "pad_weaponbar", "pad_weaponbar" + ASCString::toString( i ));
00478 pc.closeBracket();
00479 yoffset += sw->Height();
00480
00481 assignWeaponInfo( this, sw, vt->weapons.weapon[i] );
00482 sw->sigMouseButtonDown.connect( SigC::bind( SigC::slot( *this, &UnitInfoDialog::onWeaponClick ), i));
00483 }
00484 }
00485 if ( label == "entrancesystems" && vt ) {
00486 int xoffset = 0;
00487 for ( int i = 0; i < vt->entranceSystems.size() ; ++i ) {
00488 pc.openBracket( "LineWidget" );
00489 widgetParams.runTextIO( pc );
00490 PG_Rect r = parseRect( pc, parent);
00491 r.x += xoffset;
00492
00493 SpecialInputWidget* sw = new SpecialInputWidget ( parent, r );
00494 parsePanelASCTXT( pc, sw, widgetParams );
00495 rename( "pad_transport_square", "pad_transport_square" + ASCString::toString( i ));
00496 pc.closeBracket();
00497
00498 setLabelText( "unitpad_transport_entrancenumber", i+1, sw );
00499
00500 xoffset += sw->Width();
00501
00502
00503 sw->sigMouseButtonDown.connect( SigC::bind( SigC::slot( *this, &UnitInfoDialog::onEntranceClick ), i));
00504 }
00505 }
00506 };
00507
00508 };
00509
00510 void unitInfoDialog( const Vehicletype* vt )
00511 {
00512 if ( vt ) {
00513 UnitInfoDialog uid ( NULL, NULL, vt );
00514 uid.Show();
00515 uid.RunModal();
00516 } else {
00517 tfield* fld = actmap->getField( actmap->getCursor() );
00518 if ( fld && fld->vehicle ) {
00519 UnitInfoDialog uid ( NULL, fld->vehicle, NULL );
00520 uid.Show();
00521 uid.RunModal();
00522 } else
00523 displaymessage2("please select a unit" );
00524 }
00525 }
00526