Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

HUD.cpp

Go to the documentation of this file.
00001 /*
00002 CS Senior Project 2003
00003 Team : Leftfield
00004 Project : ModernWarfare
00005 Members :
00006 - Russ Christensen              <rchriste@cs.utah.edu>
00007 - Todd Smith                    <tcsmith@cs.utah.edu>
00008 - Usit Duongsaa                 <duongsaa@cs.utah.edu>
00009 Copyright 2003 Russ Christensen, Usit Duongsaa, and Todd Smith. All rights reserved.
00010 
00011 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00012 
00013 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
00014 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
00015 THIS SOFTWARE IS PROVIDED BY RUSS CHRISTENSEN, USIT DUONGSAA, AND TODD SMITH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RUSS, USIT, TODD OR OTHER CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00016 */
00017 
00022 #include "HUD.h"
00023 #include "GameState.h"
00024 #include "Globals.h"
00025 #include "EconData.h"
00026 #include "Map.h"
00027 #include "HelperFunctions.h"
00028 #include "Sound.h"
00029 
00030 using namespace NetworkMessages;
00031 using namespace Globals;
00032 
00033 const Vec3D HUD::COLOR_INACTIVE_BATTLE(0.792f, 0.741f, 0.768f);
00034 const Vec3D HUD::COLOR_CITY_OUTLINE(0.83f, 0.88f, 0.69f);
00035 
00036 void HUD::init(istream& in)
00037 {
00038         HUD& h = HUD::getObj();
00039 
00040         in >> h.m_startX;
00041         in >> h.m_startY;
00042         in >> h.m_endX;
00043         in >> h.m_endY;
00044 
00045         float delta;
00046 
00047         in >> h.m_mapBorderX1;
00048         h.m_mapBorderX1 += h.m_startX;
00049         in >> h.m_mapBorderY1;
00050         h.m_mapBorderY1 += h.m_startY;
00051         in >> delta;
00052         h.m_mapBorderX2 = h.m_mapBorderX1+delta;
00053         in >> delta;
00054         h.m_mapBorderY2 = h.m_mapBorderY1+delta;
00055         // read inset and calculate map dims
00056         in >> delta;
00057         h.m_mapDims[0].x = h.m_mapBorderX1+delta;
00058         h.m_mapDims[0].y = h.m_mapBorderY1+delta;
00059         h.m_mapDims[1].x = h.m_mapBorderX2-delta;
00060         h.m_mapDims[1].y = h.m_mapBorderY2-delta;
00061         h.m_miniMapBounds.setBounds(h.m_mapDims[0], h.m_mapDims[1]);
00062         in >> h.m_mapCityOutlineSize >> h.m_mapCitySize;
00063         in >> h.m_mapUnitSize;
00064 
00065         // info box, contains build Q in overhead mode, ?? in battle mode
00066         in >> h.m_infoBorderX1;
00067         h.m_infoBorderX1 += h.m_startX;
00068         in >> h.m_infoBorderY1;
00069         h.m_infoBorderY1 += h.m_startY;
00070         in >> delta;
00071         h.m_infoBorderX2 = h.m_infoBorderX1+delta;
00072         in >> delta;
00073         h.m_infoBorderY2 = h.m_infoBorderY1+delta;
00074 
00075         // read in the portrait center and size
00076         in >> delta;
00077         h.m_infoPortraitCenter.x = h.m_infoBorderX1 + delta;
00078         in >> delta;
00079         h.m_infoPortraitCenter.y = h.m_infoBorderY1 + delta;
00080         in >> h.m_infoPortraitSize.x >> h.m_infoPortraitSize.y;
00081 
00082         // build Q
00083         in >> h.m_buildQIconSize.x >> h.m_buildQIconSize.y;
00084         float cX, cY, offset;
00085         // icon center X, icon center Y, offset (how much to shift each icon center
00086         in >> cX >> cY >> offset;
00087         cX += h.m_infoBorderX1;
00088         cY += h.m_infoBorderY1;
00089         for(int i=0; i < 3; ++i)
00090         {
00091                 for(int j=0; j < 3; ++j)
00092                 {
00093                         int index = i*3+j;
00094                         h.m_buildQIconCoords[index].x = cX + j*offset;
00095                         h.m_buildQIconCoords[index].y = cY + i*offset;
00096                 }
00097         }
00098 
00099         in >> delta;
00100         h.m_buildQTimerCoords.x = h.m_infoBorderX1 + delta;
00101         in >> delta;
00102         h.m_buildQTimerCoords.y = h.m_infoBorderY1 + delta;
00103         //in >> h.m_buildQTimerCoords.x >> h.m_buildQTimerCoords.y;
00104         in >> h.m_buildQTimerTextSize;
00105 
00106         string color;
00107         in >> color;
00108         h.m_buildQTimerTextColor = Map::getColorVec3D(color);
00109 
00110 
00111 
00112         in >> h.m_moneyBorderX1;
00113         h.m_moneyBorderX1 += h.m_startX;
00114         in >> h.m_moneyBorderY1;
00115         h.m_moneyBorderY1 += h.m_startY;
00116         in >> delta;
00117         h.m_moneyBorderX2 = h.m_moneyBorderX1+delta;
00118         in >> delta;
00119         h.m_moneyBorderY2 = h.m_moneyBorderY1+delta;
00120         in >> h.m_moneyTextX;
00121         h.m_moneyTextX += h.m_startX;
00122         in >> h.m_moneyTextY;
00123         h.m_moneyTextY += h.m_startY;
00124         in >> h.m_moneyTextSize;
00125         in >> color;
00126         h.m_moneyTextColor = Map::getColorVec3D(color);
00127 
00128         // actions box
00129         in >> h.m_actionsBorderStart.x >> h.m_actionsBorderStart.y;
00130         h.m_actionsBorderStart.x += h.m_startX;
00131         h.m_actionsBorderStart.y += h.m_startY;
00132         in >> h.m_actionsBorderEnd.x >> h.m_actionsBorderEnd.y;
00133         h.m_actionsBorderEnd.x += h.m_startX;
00134         h.m_actionsBorderEnd.y += h.m_startY;
00135 
00136   // map box
00137   in >> h.m_mapBorderStart.x >> h.m_mapBorderStart.y;
00138   h.m_mapBorderStart.x += h.m_startX;
00139   h.m_mapBorderStart.y += h.m_startY;
00140   in >> h.m_mapBorderEnd.x >> h.m_mapBorderEnd.y;
00141   h.m_mapBorderEnd.x += h.m_startX;
00142   h.m_mapBorderEnd.y += h.m_startY;
00143 
00144   // info box
00145   in >> h.m_infoBorderStart.x >> h.m_infoBorderStart.y;
00146   h.m_infoBorderStart.x += h.m_startX;
00147   h.m_infoBorderStart.y += h.m_startY;
00148   in >> h.m_infoBorderEnd.x >> h.m_infoBorderEnd.y;
00149   h.m_infoBorderEnd.x += (h.m_infoBorderStart.x);
00150   h.m_infoBorderEnd.y += (h.m_infoBorderStart.y);
00151 
00152         // build menu icons
00153         h.m_buildIcons.reserve(ICON_COUNT);
00154         h.m_buildIcons[0] = &h.m_iconBuildLT;
00155         h.m_buildIcons[1] = &h.m_iconBuildHT;
00156         h.m_buildIcons[2] = &h.m_iconBuildRL;
00157         h.m_buildIcons[3] = &h.m_iconBuildAR;
00158         h.m_buildIcons[4] = &h.m_iconBuildJT;
00159 
00160         // all build menu icons have same size
00161         float width, height;
00162         in >> width >> height;
00163 
00164         in >> h.m_iconTextXOffset >> h.m_iconTextYOffset >> h.m_iconTextSize;
00165 
00166         in >> color;
00167         h.m_iconTextColor = Map::getColorVec3D(color);
00168 
00169         float x,y;
00170         in >> x >> y;
00171         h.m_iconBuildLT.setBounds( Vec2D(x - width/2,
00172                 y - height/2),
00173                 Vec2D(x + width/2,
00174                 y + height/2));
00175         h.m_iconBuildLT.setImage(Globals::artWork->portraitLT);
00176 
00177         in >> x >> y;
00178         h.m_iconBuildHT.setBounds( Vec2D(x - width/2,
00179                 y - height/2),
00180                 Vec2D(x + width/2,
00181                 y + height/2));
00182         h.m_iconBuildHT.setImage(Globals::artWork->portraitHT);
00183 
00184         in >> x >> y;
00185         h.m_iconBuildRL.setBounds( Vec2D(x - width/2,
00186                 y - height/2),
00187                 Vec2D(x + width/2,
00188                 y + height/2));
00189         h.m_iconBuildRL.setImage(Globals::artWork->portraitLA);
00190 
00191         in >> x >> y;
00192         h.m_iconBuildAR.setBounds( Vec2D(x - width/2,
00193                 y - height/2),
00194                 Vec2D(x + width/2,
00195                 y + height/2));
00196         h.m_iconBuildAR.setImage(Globals::artWork->portraitAR);
00197 
00198         in >> x >> y;
00199         h.m_iconBuildJT.setBounds( Vec2D(x - width/2, y - height/2), Vec2D(x + width/2, y + height/2));
00200         h.m_iconBuildJT.setImage(Globals::artWork->portraitJE);
00201 
00202         in >> x >> y;
00203         h.m_iconOverhead.setBounds(Vec2D(x - width/2, y - height/2), Vec2D(x + width/2, y + height/2));
00204 
00205         in >> x >> y;
00206         h.m_iconCallRFM.setBounds(Vec2D(x - width/2, y - height/2), Vec2D(x + width/2, y + height/2));  // call RFM icon
00207 
00208         in >> h.m_panelCallRFMCoord.x >> h.m_panelCallRFMCoord.y;                               // call RFM panel coord
00209         in >> h.m_panelCallRFMSize.x >> h.m_panelCallRFMSize.y;
00210 
00211         // 5-button callRFM panel
00212         FLOAT callW,callH;              // width,height of 5-but panel
00213         in >> x >> y >> callW >> callH;
00214         callW /= 5;
00215         for( int i=0; i<5; i++ )
00216         {
00217                 Vec2D UL( x+callW*i, y);
00218                 Vec2D LR( x+callW*i+callW, y+callH );           
00219                 h.m_iconCallUnitType.push_back( Icon(UL,LR,NULL) );
00220         }       
00221 
00222         in >> h.cammRFMTextPos.x >> h.cammRFMTextPos.y;
00223 
00224         in >> x >> y;
00225         h.m_iconJetGuard.setBounds(Vec2D(x - width/2, y - height/2), Vec2D(x + width/2, y + height/2)); // jet guard
00226         in >> x >> y;
00227         h.m_iconJetBomb.setBounds(Vec2D(x - width/2, y - height/2), Vec2D(x + width/2, y + height/2));  // jet bomb
00228         in >> x >> y;
00229         h.m_iconStop.setBounds(Vec2D(x - width/2, y - height/2), Vec2D(x + width/2, y + height/2));             // stop
00230 
00231 
00232         in >> h.m_econInfoTextX;
00233         in >> h.m_econInfoTextY;
00234 
00235         in >> x >> y;
00236         const FLOAT econHeight = 0.07f;
00237         h.m_iconUpgradeEcon.setBounds(Vec2D(x - width/2, y - econHeight/2), Vec2D(x + width/2, y + econHeight/2));
00238 
00239         h.m_iconOverhead.setImage(Globals::artWork->switchToOverhead);
00240         h.m_iconCallRFM.setImage(Globals::artWork->callRFMIconTex);
00241         h.m_iconJetGuard.setImage(Globals::artWork->butJetGuard);
00242         h.m_iconJetBomb.setImage(Globals::artWork->butJetBomb);
00243         h.m_iconStop.setImage(Globals::artWork->butStop);
00244 
00245         h.m_pSelectedCity = 0;
00246         h.m_pSelectedUnit = 0;
00247         h.m_selectedGroupType = -1;
00248 
00249         h.m_iconUpgradeEcon.setImage( Globals::artWork->upgradeEconTex );
00250         h.m_portraits[UnitTypes::LIGHT_TANK] = Globals::artWork->portraitLT;
00251         h.m_portraits[UnitTypes::HEAVY_TANK] = Globals::artWork->portraitHT;
00252         h.m_portraits[UnitTypes::LAUNCHER] = Globals::artWork->portraitLA;
00253         h.m_portraits[UnitTypes::ARTILLERY] = Globals::artWork->portraitAR;
00254         h.m_portraits[UnitTypes::JET] = Globals::artWork->portraitJE;
00255 
00256         h.m_blinkOn = false;
00257         h.m_blinkCount = 0;
00258 
00259         h.m_showCallRFMPanel = false;
00260 
00261         // help text
00262         h.m_iconBuildLT.setHelpString("Build Light Tank Battalion\nFast and can shoot in any direction\nHot Key[L]");
00263         h.m_iconBuildHT.setHelpString("Build Heavy Tank Battalion\nSlow but very heavily armored\nHot Key[H]");
00264         h.m_iconBuildRL.setHelpString("Build Rocket Launcher Battalion\nLaunch medium-range rockets\nInflict massive damage to an area\nHot Key[R]");
00265         h.m_iconBuildAR.setHelpString("Build Artillery Battalion\nCan bombard from long range\nHot Key[A]");
00266         h.m_iconBuildJT.setHelpString("Build Jet Squadrom\nCan bomb ground targets or\nshoot down enemy jets\nHot Key[J]");
00267         h.m_iconUpgradeEcon.setHelpString("Upgrade City's Economic Level\nIncreased the city's income\n-rate in the long term");
00268         h.m_iconOverhead.setHelpString("Go back to the overhead map\nHot Key [Ctrl+Up]");
00269         h.m_iconCallRFM.setHelpString("Call in reinforcement (if any)");
00270         h.m_iconJetGuard.setHelpString("Right-Click on Empty Ground\nJets will guard the area\nand shoot down incoming enemy jets");
00271         h.m_iconJetBomb.setHelpString("Right-Click on Enemy Target\nJets will drop non-guided bombs");
00272         h.m_iconStop.setHelpString("Stop this battalion at current\nposition and direction\nHot Key [S]");
00273         h.m_iconCallUnitType[0].setHelpString("Call in more Light Tanks");
00274         h.m_iconCallUnitType[1].setHelpString("Call in more Heavy Tanks");
00275         h.m_iconCallUnitType[2].setHelpString("Call in more Rocket Launchers");
00276         h.m_iconCallUnitType[3].setHelpString("Call in more Artilleries");
00277         h.m_iconCallUnitType[4].setHelpString("Call in more Jets");
00278 }
00279 
00280 Vec2D HUD::translateMiniMapToWorld(const Vec2D& mmPos)
00281 {
00282         Vec2D pos;
00283         pos.x = mmPos.x - m_miniMapBounds.bounds()[0].x;
00284         pos.y = mmPos.y - m_miniMapBounds.bounds()[0].y;
00285         // scale to world coords
00286         pos.x *= 1/m_miniMapScale.x;
00287         pos.y *= 1/m_miniMapScale.y;
00288         // translate to absolute coords
00289         pos.x += m_map.bounds.bounds()[0].x;
00290         pos.y += m_map.bounds.bounds()[0].y;
00291         return pos;
00292 
00293 }
00294 
00295 Vec3D HUD::translateMiniMapToWorld3D(const Vec2D& mmPos)
00296 {
00297         Vec3D pos;
00298         Vec2D pos2D = translateMiniMapToWorld(mmPos);
00299         pos.x = pos2D.x;
00300         pos.y = pos2D.y;
00301         pos.z = 0.0f;
00302         return pos;
00303 }
00304 
00305 Vec2D HUD::translateWorldToMiniMap(const Vec2D& wPos)
00306 {
00307         Vec2D pos;
00308         pos.x = wPos.x - m_map.bounds.bounds()[0].x;
00309         pos.y = wPos.y - m_map.bounds.bounds()[0].y;
00310         // scale
00311         pos.x *= m_miniMapScale.x;
00312         pos.y *= m_miniMapScale.y;
00313         // translate to minimap position in the HUD
00314         pos.x += m_mapDims[0].x;
00315         pos.y += m_mapDims[0].y;
00316         return pos;
00317 }
00318 
00319 
00320 Vec2D HUD::translateWorldToMiniMap(const Vec3D& wPos)
00321 {
00322         return translateWorldToMiniMap(Vec2D(wPos.x, wPos.y));
00323 }
00324 
00325 bool HUD::processMiniMapInput(const Vec2D& mouse)
00326 {
00327         if(m_miniMapBounds.contains(mouse) )
00328         {
00329                 if( input_isMouseLBClicked() )
00330                 {
00331                         // switch from battle mode to overhead mode
00332                         if( input_isKeyDown(KeyCodes::key_LCONTROL) || input_isKeyDown(KeyCodes::key_RCONTROL) )
00333                         {
00334                                 switchToOverhead();
00335                                 // translate mouse position to world position
00336                                 Vec2D pos = translateMiniMapToWorld(mouse);
00337                                 GameState::camTarget().x = pos.x;
00338                                 GameState::camTarget().y = pos.y;
00339                                 return true;
00340                         }
00341                         // if the user clicks on a battle entry icon, switch to it
00342                         for(BattleIter iter=GameState::battles().begin(); iter != GameState::battles().end(); ++iter)
00343                         {
00344                                 // only allow player to switch between battles they are involved in.
00345                                 if( (*iter)->isFoughtBy(m_pPlayer->color()) )
00346                                 {
00347                                         Vec2D pos = translateWorldToMiniMap( (*iter)->getBattleLocation() );
00348                                         Rect r(Vec2D(pos.x-0.01f, pos.y-0.01f), Vec2D(pos.x+0.01f, pos.y+0.01f));
00349 
00350                                         if( r.contains(mouse) )
00351                                         {
00352                                                 GameState::setActiveBattle( *iter );
00353                                                 setSelectedCity(0);
00354                                                 setSelectedUnit(0);
00355                                                 setSelectedGroupType(-1);
00356                                                 return true;
00357                                         }
00358                                 }
00359 
00360                         }
00361                         // translate mouse position to world position
00362                         Vec2D pos = translateMiniMapToWorld(mouse);
00363                         GameState::camTarget().x = pos.x;
00364                         GameState::camTarget().y = pos.y;
00365 
00366                         return true;
00367                 }
00368                 else if( input_isMouseRBClicked() )
00369                 {
00370                         // move units to point on minimap
00371                         Vec3D goalPos = translateMiniMapToWorld3D(mouse);
00372       // only move units within the map bounds
00373       if( GameState::worldMap().bounds.contains(Vec2D(goalPos.x, goalPos.y)) )
00374       {
00375         for(vector<MilitaryUnit*>::iterator iter = GameState::selectedUnits().begin(); iter != GameState::selectedUnits().end(); ++iter)
00376         {
00377           stringstream sstr;
00378           sstr << COMMAND_OVERHEAD << " " << COMMIT_TIME << " " << Globals::currGameTick + NETWORK_GAME_TICK_LAG << " " << COMMAND_GOAL << " "
00379             << (*iter)->uniqueID() << " " << Helper::serialize(goalPos);
00380           net_send(sstr.str());
00381           
00382         }
00383         if(GameState::selectedUnits().size() > 0) Sound::playRandomSound(Sound::CLASS_ACK);
00384         return true;
00385       }
00386                 }
00387         }
00388         return false;
00389 }
00390 
00391 bool HUD::isButtonStopClicked()
00392 {
00393         HUD& h = HUD::getObj();
00394         Vec2D mouse2D( input_getMouseX(), input_getMouseY() );
00395         return input_isMouseLBClicked() &&  h.m_iconStop.contains(mouse2D);
00396 }
00397 
00398 bool HUD::isButtonCallRFMUnitTypeClicked( int unitType )
00399 {
00400         HUD& h = HUD::getObj();
00401         Vec2D mouse2D( input_getMouseX(), input_getMouseY() );
00402         if( !h.m_showCallRFMPanel ) return false;
00403         return input_isMouseLBClicked() &&  h.m_iconCallUnitType[unitType].contains(mouse2D);
00404 }
00405 //------------------------------------------------------------------------------------
00406 namespace Overhead {
00408         void deleteMilitaryUnit(MilitaryUnit* unit);
00409 }
00410 
00411 void sendReinforcement( int unitType )
00412 {
00413         HUD& h = HUD::getObj(); 
00414         if( !GameState::activeBattle() ) return;
00415         Vec2D battlePos( GameState::activeBattle()->getBattleLocation() );
00416         Vec3D playerCol( GameState::consolePlayer()->color() );
00417         for( UnitIter iter(GameState::units().begin()); iter!=GameState::units().end(); iter++ )
00418                 if( (*iter)->color()==playerCol )
00419                         if( (*iter)->unitType()==unitType )
00420                         {
00421                                 Vec2D unitPos( (*iter)->position().x, (*iter)->position().y );
00422                                 if( math_dist2D(battlePos,unitPos) <= 100.0f )
00423                                 {
00424                                         stringstream sstr;
00425                                         if( unitType==UnitTypes::JET )
00426                                         {
00427                                                 sstr << COMMAND_SEND_JET_REINFORCEMENT << " " << COMMIT_TIME << " " << currGameTick + NETWORK_GAME_TICK_LAG
00428                                                         << " " << GameState::activeBattle()->uniqueID() << " " << (*iter)->uniqueID();
00429                                         } else
00430                                         {
00431                                                 sstr << COMMAND_SEND_UNIT_REINFORCEMENT << " " << COMMIT_TIME << " " << currGameTick + NETWORK_GAME_TICK_LAG
00432                                                         << " " << GameState::activeBattle()->uniqueID() << " " << (*iter)->uniqueID();
00433                                         }
00434                                         net_send(sstr.str());
00435                                         return;
00436                                 }
00437                         }
00438 }
00439 //------------------------------------------------------------------------------------
00440 bool HUD::processOverheadInput()
00441 {
00442         HUD& h = HUD::getObj();
00443 
00444   // adjust sound volume
00445   bool ctrl_down(input_isKeyDown(KeyCodes::key_LCONTROL) || input_isKeyDown(KeyCodes::key_RCONTROL));
00446   if(input_isKeyDown(KeyCodes::key_ADD) && !ctrl_down)
00447     Sound::increaseSongVol();
00448   if(input_isKeyDown(KeyCodes::key_SUBTRACT) && !ctrl_down) 
00449     Sound::decreaseSongVol();
00450   if(input_isKeyPressed(KeyCodes::key_ADD) && ctrl_down)
00451     Sound::increaseSFXVol();
00452   if(input_isKeyPressed(KeyCodes::key_SUBTRACT) && ctrl_down)
00453     Sound::decreaseSFXVol();
00454 
00455 
00456         Vec2D mouse2D( input_getMouseX(), input_getMouseY() );
00457 
00458         if( h.processMiniMapInput(mouse2D) ) return true;
00459 
00460         // process build menu
00461         if(h.m_pSelectedCity)
00462         {
00463                 if(input_isMouseLBClicked() &&  h.m_iconBuildLT.contains(mouse2D)) 
00464                 {
00465                         sendBuildMessage( COMMAND_BUILD_LIGHTTANK, h.m_pSelectedCity->uniqueID() );
00466                         return true;
00467                 } 
00468                 else if( input_isMouseLBClicked() && h.m_iconBuildHT.contains(mouse2D) ) 
00469                 {
00470                         sendBuildMessage( COMMAND_BUILD_HEAVYTANK, h.m_pSelectedCity->uniqueID());
00471                         return true;
00472                 } 
00473                 else if( input_isMouseLBClicked() &&  h.m_iconBuildRL.contains(mouse2D) ) 
00474                 {
00475                         sendBuildMessage( COMMAND_BUILD_ROCKET_LAUNCHER, h.m_pSelectedCity->uniqueID() );
00476                         return true;
00477                 } 
00478                 else if( input_isMouseLBClicked() && h.m_iconBuildAR.contains(mouse2D) ) 
00479                 {
00480                         sendBuildMessage( COMMAND_BUILD_ARTILLERY, h.m_pSelectedCity->uniqueID() ); 
00481                         return true;
00482                 } 
00483                 else if(input_isMouseLBClicked() && h.m_iconBuildJT.contains(mouse2D)  ) 
00484                 {
00485                         sendBuildMessage( COMMAND_BUILD_JET, h.m_pSelectedCity->uniqueID() );
00486                         return true;
00487                 }
00488                 else if(input_isMouseLBClicked() && h.m_iconUpgradeEcon.contains(mouse2D)  )            // upgrade econ
00489                 {
00490                         sendBuildMessage( COMMAND_BUILD_ECON, h.m_pSelectedCity->uniqueID() );                  
00491                         return true;
00492                 }               
00493         }
00494         else if( GameState::activeBattle() )
00495         {
00496                 // switch to overhead mode
00497                 if(input_isMouseLBClicked())
00498                 {
00499                         if( h.m_iconOverhead.contains(mouse2D) )
00500                         {
00501                                 h.switchToOverhead();
00502                                 return true;
00503                         }
00504 
00505                         if( h.m_iconCallRFM.contains(mouse2D) )                                 // call Reinforcement
00506                         {
00507                                 h.m_showCallRFMPanel = true;
00508                                 h.setSelectedCity(NULL);
00509                                 h.setSelectedGroupType(-1);
00510                                 h.setSelectedUnit(NULL);
00511                                 GameState::activeBattle()->clearUnitSelection();
00512                                 return true;
00513                         }
00514 
00515                         // call Reinforcement
00516                         Vec3D &playerCol = (Vec3D) GameState::consolePlayer()->color();
00517                         bool mayGround = GameState::activeBattle()->maySendGroundReinforcement( playerCol );
00518                         bool mayAir    = GameState::activeBattle()->maySendAirReinforcement( playerCol );
00519                         bool allowed[5] = { mayGround, mayGround, mayGround, mayGround, mayAir };
00520                         for( int i=0; i<UnitTypes::COUNT; i++ )
00521                         if( isButtonCallRFMUnitTypeClicked(i) )
00522                         {
00523                                 if( allowed[i] )  sendReinforcement(i);
00524                                 return true;
00525                         }
00526 
00527                         if( h.m_selectedGroupType==UnitTypes::JET )                             // jet guard & bomb buttons
00528                         {
00529                                 if( h.m_iconJetGuard.contains(mouse2D) ) return true;
00530                                 if( h.m_iconJetBomb.contains(mouse2D) ) return true;
00531                         }
00532                 }
00533         }
00534 
00535         // cycle through battles using CTRL+LEFT/RIGHT ARROW KEYS
00536         if( GameState::battles().size() > 0 )
00537         {
00538                 if( (input_isKeyDown(KeyCodes::key_LCONTROL) || input_isKeyDown(KeyCodes::key_RCONTROL)) && input_isKeyPressed(KeyCodes::key_RIGHT) )
00539                 {
00540                         h.switchToNextBattle();
00541                         return true;
00542                 }
00543                 else if ( (input_isKeyDown(KeyCodes::key_LCONTROL) || input_isKeyDown(KeyCodes::key_RCONTROL)) && input_isKeyPressed(KeyCodes::key_LEFT) )
00544                 {
00545                         h.switchToPrevBattle();
00546                         return true;
00547                 }
00548                 else if( (input_isKeyDown(KeyCodes::key_LCONTROL) || input_isKeyDown(KeyCodes::key_RCONTROL)) &&  input_isKeyPressed(KeyCodes::key_UP) )
00549                 {
00550                         h.switchToOverhead();
00551                         return true;
00552                 }
00553         }
00554         return false;
00555 }
00556 
00557 void HUD::renderMiniMap()
00558 {
00559         // draw minimap background
00560         overlay_rect(m_mapDims[0], m_mapDims[1], true, Colors::gray, BlendModes::NONE, 1.0f, ICON_RENDER_PRIORITY);
00561 
00562         // draw each city
00563         for(CityIter iter=GameState::cities().begin(); iter != GameState::cities().end(); ++iter)
00564         {
00565                 Vec2D pos = translateWorldToMiniMap( (*iter)->position() );
00566                 overlay_point(pos, m_mapCityOutlineSize, COLOR_CITY_OUTLINE, BlendModes::NONE, 1.0f, ICON_RENDER_PRIORITY);
00567                 overlay_point(pos, m_mapCitySize, (*iter)->color(), BlendModes::NONE, 1.0f, 1+ICON_RENDER_PRIORITY);
00568         }
00569         // draw each unit
00570         for(UnitIter iter=GameState::units().begin(); iter != GameState::units().end(); ++iter)
00571         {
00572                 // translate from absolute(world) to map coords
00573                 Vec2D pos = translateWorldToMiniMap( (*iter)->position() );
00574                 overlay_point(pos, m_mapUnitSize, (*iter)->color(), BlendModes::NONE, 1.0f, ICON_RENDER_PRIORITY);
00575         }
00576         // draw a symbol to show each battle
00577         for(BattleIter iter=GameState::battles().begin(); iter != GameState::battles().end(); ++iter)
00578         {
00579                 //Vec2D pos = translateWorldToMiniMap(Vec2D((*iter)->getBattleLocation().x, (*iter)->getBattleLocation().y));
00580                 Vec2D pos = translateWorldToMiniMap( (*iter)->getBattleLocation() );
00581 
00582                 // only show battles that the player is fighting in
00583                 if( (*iter)->isFoughtBy(m_pPlayer->color()) && m_blinkOn )
00584                 {      
00585                         overlay_image(Globals::artWork->minimapBattleIcon, pos, Vec2D(0.03f,0.03f),
00586                                 BlendModes::KEY, 1.0f, MOUSE_RENDER_PRIORITY);
00587                 }
00588         }
00589 
00590 }
00591 
00592 void HUD::update()
00593 {
00594         HUD& h = HUD::getObj();
00595 
00596         if(h.m_blinkCount++ > BLINK_RATE)
00597         {
00598                 h.m_blinkOn = !h.m_blinkOn;
00599                 h.m_blinkCount = 0;
00600         }
00601 }
00602 
00603 
00604 void HUD::render() 
00605 {
00606         HUD& h = HUD::getObj();
00607         Vec2D mouse2D( input_getMouseX(), input_getMouseY() );
00608 
00609         // draw the background
00610         overlay_image(Globals::artWork->hud, Vec2D(0.5f,0.9f), Vec2D(1.0f, 0.2f), BlendModes::NONE, 1.0f, BG_RENDER_PRIORITY);
00611 
00612         // draw box to indicate player color
00613   overlay_rect(h.m_mapBorderStart, h.m_mapBorderEnd, false, h.m_pPlayer->color(), BlendModes::NONE, 1.0f, ICON_RENDER_PRIORITY);
00614         overlay_rect(h.m_actionsBorderStart, h.m_actionsBorderEnd, false, h.m_pPlayer->color(), BlendModes::NONE, 1.0f, ICON_RENDER_PRIORITY);
00615   overlay_rect(h.m_infoBorderStart, h.m_infoBorderEnd, false, h.m_pPlayer->color(), BlendModes::NONE, 1.0f, ICON_RENDER_PRIORITY);
00616 
00617         // draw the minimap
00618         h.renderMiniMap();
00619 
00620         // display amount of money in bank
00621         overlay_text() << "$" << h.m_pPlayer->bank().balance();
00622         overlay_textOut(Vec2D(h.m_moneyTextX, h.m_moneyTextY), h.m_moneyTextSize, h.m_moneyTextColor);
00623 
00624         if(h.m_pSelectedCity)
00625         {
00626                 // econ data
00627                 int econLevel = h.m_pSelectedCity->econLevel();
00628                 int incomeRate = EconData::getObj().depositPerCity(econLevel) * 62 * 60 / EconData::getObj().depositInterval();
00629                 overlay_text() << "Economics Level = " << econLevel << "\n";
00630                 overlay_text() << "Generates $" << incomeRate << "/min";
00631                 if( h.m_pSelectedCity->timeUntilFinishEconUpgrade()!=-1 )
00632                         overlay_text() << "\nUpgrading : " << h.m_pSelectedCity->timeUntilFinishEconUpgrade();
00633                 
00634                 overlay_textOut( Vec2D(h.m_econInfoTextX,h.m_econInfoTextY), 0.8f );
00635 
00636                 // upgrading econ
00637                 h.m_iconUpgradeEcon.render();
00638                 h.m_iconUpgradeEcon.drawHelpString();
00639                 if( h.m_iconUpgradeEcon.contains(mouse2D) )  h.m_iconUpgradeEcon.drawOutline(Colors::yellow);
00640                 int cost = EconData::getObj().econUpgradeCost( h.m_pSelectedCity->econLevel() );
00641                 if( cost <= 10000 )  overlay_text() << "$" << cost;
00642                 else                             overlay_text() << "MAX";
00643                 overlay_textOut( h.m_iconUpgradeEcon.bounds()[0]+Vec2D(0.002f,0.004f), h.m_iconTextSize, h.m_iconTextColor );
00644 
00645                 // diplay build menu
00646                 for(int i=0; i < ICON_COUNT; ++i)
00647                 {
00648                         h.m_buildIcons[i]->render();
00649                         h.m_buildIcons[i]->drawHelpString();
00650                         // draw unit price
00651                         overlay_text() << "$" << EconData::getObj().unitAmount(i);
00652                         overlay_textOut(Vec2D(h.m_buildIcons[i]->bounds()[0].x + h.m_iconTextXOffset,
00653                                 h.m_buildIcons[i]->bounds()[0].y + h.m_iconTextYOffset), 
00654                                 h.m_iconTextSize, 
00655                                 h.m_iconTextColor);
00656                         if( h.m_buildIcons[i]->contains(mouse2D) )  h.m_buildIcons[i]->drawOutline(Colors::yellow);                     
00657                 }
00658 
00659                 // display build queue 
00660                 deque<int> q = h.m_pSelectedCity->trainees();
00661                 int n=0;
00662                 for(deque<int>::iterator it = q.begin(); it != q.end() && n < 9; ++it, ++n)
00663                         overlay_image(h.m_buildIcons[*it]->image(), 
00664                         h.m_buildQIconCoords[n], 
00665                         h.m_buildQIconSize, 
00666                         BlendModes::NONE, 
00667                         1.0f, 
00668                         ICON_RENDER_PRIORITY);
00669 
00670                 // 62 == ticks per second
00671                 if( !q.empty() )
00672                 {
00673                         overlay_text() << static_cast<int>(h.m_pSelectedCity->trainingTimeLeft()/62);
00674                         overlay_textOut(h.m_buildQTimerCoords, h.m_buildQTimerTextSize, h.m_buildQTimerTextColor);
00675                 }
00676 
00677 
00678         }
00679         else if(h.m_pSelectedUnit) 
00680         {
00681                 overlay_image(h.m_portraits[h.m_pSelectedUnit->unitType()], 
00682                         h.m_infoPortraitCenter,
00683                         h.m_infoPortraitSize,
00684                         BlendModes::NONE,
00685                         1.0f,
00686                         ICON_RENDER_PRIORITY);
00687         }
00688         else if (h.m_selectedGroupType != -1) 
00689         {
00690                 overlay_image(h.m_portraits[h.m_selectedGroupType], 
00691                         h.m_infoPortraitCenter,
00692                         h.m_infoPortraitSize,
00693                         BlendModes::NONE,
00694                         1.0f,
00695                         ICON_RENDER_PRIORITY);
00696         }
00697 
00698         // if we are in a battle show button to switch to overhead
00699         if( GameState::activeBattle() )
00700         {
00701                 h.m_iconOverhead.render();
00702                 h.m_iconCallRFM.render();
00703                 h.m_iconOverhead.drawHelpString();
00704                 h.m_iconCallRFM.drawHelpString();
00705                 if( h.m_iconOverhead.contains(mouse2D) )  h.m_iconOverhead.drawOutline(Colors::yellow);
00706                 if( h.m_iconCallRFM.contains(mouse2D) )   h.m_iconCallRFM.drawOutline(Colors::yellow );
00707 
00708                 if( h.m_showCallRFMPanel )                                                              // Call Reinforcement Panel
00709                 {
00710                         overlay_image( Globals::artWork->callRFMPanelTex, h.m_panelCallRFMCoord, h.m_panelCallRFMSize,
00711                                 BlendModes::NONE, 1.0f, 6 );
00712 
00713                         int totalCallable = 0;
00714                         for( int i=0; i<5; i++ )                        // the 5 call unit type buttons
00715                         {
00716                                 if( h.m_iconCallUnitType[i].contains(mouse2D) )  h.m_iconCallUnitType[i].drawOutline(Colors::yellow);
00717                                 h.m_iconCallUnitType[i].drawHelpString();
00718                                 totalCallable += GameState::availableRFM()[i];
00719 
00720                                 // number of available RFM
00721                                 Vec2D pos( h.m_iconCallUnitType[i].bounds()[0] + h.m_iconCallUnitType[i].bounds()[1] );
00722                                 pos = pos * 0.5f + Vec2D( -0.002f, -0.001f );
00723                                 overlay_text() << GameState::availableRFM()[i];
00724                                 overlay_textOut( pos, 1.2f, Colors::yellow, NULL, 6 );
00725                         }
00726 
00727                         // callRFM description text                     
00728                         Vec3D &playerCol = (Vec3D)GameState::consolePlayer()->color();
00729                         bool mayGround = GameState::activeBattle()->maySendGroundReinforcement( playerCol );
00730                         bool mayAir    = GameState::activeBattle()->maySendAirReinforcement( playerCol );
00731                         if( totalCallable==0 )                  
00732                                 overlay_text() << "No nearby friendly forces";                  
00733                         else if( !mayGround && !mayAir )
00734                                 overlay_text() << "Too many units in battle already";
00735                         else if( !mayGround )
00736                                 overlay_text() << "Too many tanks\n in battle already";
00737                         else if( !mayAir )
00738                                 overlay_text() << "Too many jets\nin battle already";
00739                         else
00740                                 overlay_text() << totalCallable << " Battalions Standing by";
00741                         overlay_textOut( h.cammRFMTextPos, 0.7f, Colors::red, NULL, 6 );
00742 
00743 
00744                         
00745                 }
00746 
00747                 // battle unit command
00748                 if( h.m_selectedGroupType != -1 )                                       // stop button
00749                 {
00750                         h.m_iconStop.render();
00751                         h.m_iconStop.drawHelpString();
00752                         if( h.m_iconStop.contains(mouse2D) )  h.m_iconStop.drawOutline(Colors::yellow);
00753                 }
00754                 if( h.m_selectedGroupType == UnitTypes::JET )                                   // jet guard, bomb buttons
00755                 {
00756                         h.m_iconJetGuard.render();
00757                         h.m_iconJetGuard.drawHelpString();
00758                         if( h.m_iconJetGuard.contains(mouse2D) )  h.m_iconJetGuard.drawOutline(Colors::yellow);
00759                         h.m_iconJetBomb.render();
00760                         h.m_iconJetBomb.drawHelpString();
00761                         if( h.m_iconJetBomb.contains(mouse2D) )  h.m_iconJetBomb.drawOutline(Colors::yellow);
00762                 }
00763         }
00764 }
00765 
00766 
00767 void HUD::setWorldMap(Map::WorldMap& map) 
00768 { 
00769         HUD& h = HUD::getObj();
00770         h.m_map = map; 
00771         h.m_miniMapScale.x = (h.m_mapDims[1].x - h.m_mapDims[0].x) / h.m_map.width;
00772         h.m_miniMapScale.y = (h.m_mapDims[1].y - h.m_mapDims[0].y) / h.m_map.height;
00773 }
00774 
00775 void HUD::clearSelections() 
00776 {
00777         HUD::getObj().m_selectedGroupType = -1;
00778         HUD::getObj().m_pSelectedCity = 0;
00779         HUD::getObj().m_pSelectedUnit = 0;
00780 }
00781 
00782 void HUD::shutdown()
00783 {
00784         HUD::getObj().releaseObj();
00785 }
00786 
00787 
00788 void HUD::switchToNextBattle()
00789 {
00790         BattleIter currBattle;
00791         // find the active battle
00792         if( GameState::activeBattle() )
00793         {
00794                 for(BattleIter iter = GameState::battles().begin(); iter != GameState::battles().end(); ++iter)
00795                 {
00796                         if( (*iter) == GameState::activeBattle() )
00797                         {
00798                                 currBattle = iter;
00799                                 break;
00800                         }
00801                 }
00802         }
00803         else
00804         {
00805                 currBattle = GameState::battles().begin();
00806         }
00807 
00808         // treat the vector of battles as a circular queue
00809         // now get the next battle the player belongs to
00810         for(BattleIter iter=currBattle+1; iter != GameState::battles().end(); ++iter)
00811         {
00812                 if( (*iter)->isFoughtBy(m_pPlayer->color()) )
00813                 {
00814                         GameState::setActiveBattle(*iter);
00815                         return;
00816                 }
00817         }
00818         // start from the beginning of the list and go up to current battle
00819         for(BattleIter iter=GameState::battles().begin(); iter != currBattle; ++iter)
00820         {
00821                 if( (*iter)->isFoughtBy(m_pPlayer->color()) )
00822                 {
00823                         GameState::setActiveBattle(*iter);
00824                         return;
00825                 }
00826         }
00827         // current battle is the only battle this player is involved in
00828         if( (*currBattle)->isFoughtBy(m_pPlayer->color()) )
00829                 GameState::setActiveBattle(*currBattle);
00830 }
00831 
00832 void HUD::switchToPrevBattle()
00833 {
00834         BattleIter currBattle;
00835         // find the active battle
00836         if( GameState::activeBattle() )
00837         {
00838                 for(BattleIter iter = GameState::battles().begin(); iter != GameState::battles().end(); ++iter)
00839                 {
00840                         if( (*iter) == GameState::activeBattle() )
00841                         {
00842                                 currBattle = iter;
00843                                 break;
00844                         }
00845                 }
00846         }
00847         else
00848         {
00849                 currBattle = GameState::battles().end()-1;
00850         }
00851 
00852         // treat the vector of battles as a circular queue
00853         // now get the previous battle the player belongs to
00854         for(BattleIter iter=currBattle-1; iter >= GameState::battles().begin(); --iter)
00855         {
00856                 if( (*iter)->isFoughtBy(m_pPlayer->color()) )
00857                 {
00858                         GameState::setActiveBattle(*iter);
00859                         return;
00860                 }
00861         }
00862         // start from the beginning of the list and go up to current battle
00863         for(BattleIter iter=GameState::battles().end()-1; iter != currBattle; --iter)
00864         {
00865                 if( (*iter)->isFoughtBy(m_pPlayer->color()) )
00866                 {
00867                         GameState::setActiveBattle(*iter);
00868                         return;
00869                 }
00870         }
00871         // current battle is the only battle this player is involved in
00872         if( (*currBattle)->isFoughtBy(m_pPlayer->color()) )
00873                 GameState::setActiveBattle(*currBattle);
00874 }
00875 
00876 void HUD::switchToOverhead()
00877 {
00878         GameState::setActiveBattle(0);
00879         setSelectedCity(0);
00880         setSelectedUnit(0);
00881         setSelectedGroupType(-1);
00882 }

Generated on Wed Apr 23 05:50:15 2003 for Modern Warfare by doxygen1.3-rc2