/** * @file * @author Flugente (bears-pit.com) */ #include "SkillMenu.h" #include "Soldier Profile Type.h" #include "Overhead.h" #include "Text.h" #include "Isometric Utils.h" #include "DisplayCover.h" #include "worldman.h" #include "Queen Command.h" #include "strategicmap.h" #include "Map Screen Interface.h" #include "Rotting Corpses.h" #include "Dialogue Control.h" #include "Handle Items.h" extern void GetEquipmentTemplates( ); std::vector gTemplateVector; extern void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name ); extern INT8 bSelectedInfoChar; // sevenfm: need this for correct calculation of traits menu position extern INT16 gsInterfaceLevel; extern void BeginAutoBandage(); UINT16 usTraitMenuPosX = 0; UINT16 usTraitMenuPosY = 0; INT32 sTraitsMenuTargetGridNo = NOWHERE; void Hide( void ) { // set off display of trait range/target gridno ToggleTraitRangeView(FALSE); // Dirty! fMapPanelDirty = TRUE; } // Turns an option off by always returning FALSE BOOLEAN Popup_OptionOff( void ) { return FALSE; } void SkillMenuItem::SetupPopup(CHAR* name) { // create a popup gPopup = new POPUP(name); // add a callback that lets the keyboard handler know we're done (and ready to pop up again) gPopup->setCallback(POPUP_CALLBACK_HIDE, new popupCallbackFunction( &Hide ) ); } // Different SkillItem classes. We need wrappers for each one, as we cannot pass a pointer to a member function (we need a concrete object) /////////////////////////////// Trait Selection //////////////////////////////////////////// TraitSelection gTraitSelection; void Wrapper_Setup_TraitSelection( UINT32 aVal) { gTraitSelection.Setup(aVal); } void Wrapper_Cancel_TraitSelection( UINT32 aVal ) { gTraitSelection.Cancel(); } /////////////////////////////// Trait Selection //////////////////////////////////////////// /////////////////////////////// Skill Selection //////////////////////////////////////////// SkillSelection gSkillSelection; void Wrapper_Function_SkillSelection( UINT32 aVal) { gSkillSelection.Functions(aVal); } void Wrapper_Setup_SkillSelection( UINT32 aVal) { gSkillSelection.Setup(aVal); } void Wrapper_Cancel_SkillSelection( UINT32 aVal ) { gSkillSelection.Cancel(); } void Wrapper_Setup_AutobandageSelection(UINT32 aVal) { gSkillSelection.Cancel(); gTraitSelection.Cancel(); BeginAutoBandage(); } /////////////////////////////// Skill Selection //////////////////////////////////////////// /////////////////////////////// Artillery Sector Selection //////////////////////////////////////////// ArtillerySector gArtillerySector; //void Wrapper_Function_ArtillerySector( UINT32 aVal) { gArtillerySector.Functions(aVal); } void Wrapper_Setup_ArtillerySector( UINT32 aVal) { gArtillerySector.Setup(aVal); } void Wrapper_Cancel_ArtillerySector( UINT32 aVal ) { gArtillerySector.Cancel(); } /////////////////////////////// Artillery Sector Selection //////////////////////////////////////////// /////////////////////////////// Artillery Team Selection //////////////////////////////////////////// ArtilleryTeam gArtilleryTeam; void Wrapper_Function_ArtilleryTeam( UINT32 aVal) { gArtilleryTeam.Functions(aVal); } void Wrapper_Setup_ArtilleryTeam( UINT32 aVal) { gArtilleryTeam.Setup(aVal); } void Wrapper_Cancel_ArtilleryTeam( UINT32 aVal ) { gArtilleryTeam.Cancel(); } /////////////////////////////// Artillery Team Selection //////////////////////////////////////////// /////////////////////////////// Reinforcement Sector Selection //////////////////////////////////////////// ReinforcementSector gReinforcementSector; //void Wrapper_Function_ReinforcementSector( UINT32 aVal) { gReinforcementSector.Functions(aVal); } void Wrapper_Setup_ReinforcementSector( UINT32 aVal) { gReinforcementSector.Setup(aVal); } void Wrapper_Cancel_ReinforcementSector( UINT32 aVal ) { gReinforcementSector.Cancel(); } /////////////////////////////// Reinforcement Sector Selection //////////////////////////////////////////// /////////////////////////////// Reinforcement Number Selection //////////////////////////////////////////// ReinforcementNumber gReinforcementNumber; void Wrapper_Function_ReinforcementNumber( UINT32 aVal) { gReinforcementNumber.Functions(aVal); } void Wrapper_Setup_ReinforcementNumber( UINT32 aVal) { gReinforcementNumber.Setup(aVal); } void Wrapper_Cancel_ReinforcementNumber( UINT32 aVal ) { gReinforcementNumber.Cancel(); } /////////////////////////////// Reinforcement Number Selection //////////////////////////////////////////// /////////////////////////////// Soldier Target Selection //////////////////////////////////////////// SoldierSelection gSoldierSelection; void Wrapper_Function_SoldierSelection( UINT32 aVal) { gSoldierSelection.Functions(aVal); } void Wrapper_Setup_SoldierSelection( UINT32 aVal) { gSoldierSelection.Setup(aVal); } void Wrapper_Cancel_SoldierSelection( UINT32 aVal ) { gSoldierSelection.Cancel(); } /////////////////////////////// Soldier Target Selection //////////////////////////////////////////// /////////////////////////////// Drag Selection //////////////////////////////////////////// DragSelection gDragSelection; void Wrapper_Function_DragSelection( UINT32 aVal) { gDragSelection.Functions(aVal); } void Wrapper_Function_DragSelection_GridNo( INT32 aVal ){ gDragSelection.FunctionsGridNo( aVal ); } void Wrapper_Setup_DragSelection( UINT32 aVal ) { gDragSelection.Setup( aVal ); } void Wrapper_Cancel_DragSelection( UINT32 aVal ) { gDragSelection.Cancel( ); } /////////////////////////////// Drag Selection //////////////////////////////////////////// /////////////////////////////// Trait Selection //////////////////////////////////////////// void TraitSelection::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; SetupPopup("TraitSelection"); POPUP_OPTION *pOption; CHAR16 pStr[300]; // create entries for the sub-menus for each trait const UINT8 num = 5; UINT8 traitarray[num]; traitarray[0] = RADIO_OPERATOR_NT; traitarray[1] = INTEL; traitarray[2] = DISGUISE; traitarray[3] = VARIOUSSKILLS; traitarray[4] = AUTOBANDAGESKILLS; for ( int i = 0; i < num; ++i) { swprintf( pStr, gzMercSkillTextNew[traitarray[i]] ); if (traitarray[i] == AUTOBANDAGESKILLS) { pOption = new POPUP_OPTION(&std::wstring(pStr), new popupCallbackFunction(&Wrapper_Setup_AutobandageSelection, traitarray[i])); } else { pOption = new POPUP_OPTION(&std::wstring(pStr), new popupCallbackFunction(&Wrapper_Setup_SkillSelection, traitarray[i])); } // if we cannot perform this skill, grey it out if ( !HAS_SKILL_TRAIT(pSoldier, traitarray[i]) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_TraitSelection, 0 ) ); GetPopup()->addOption( *pOption ); // grab soldier's x,y screen position INT16 sX, sY; // sevenfm: changed TraitsMenu position from soldier to mouse //GetSoldierScreenPos( pSoldier, &sX, &sY ); GetGridNoScreenPos( sTraitsMenuTargetGridNo, (UINT8)gsInterfaceLevel, &sX, &sY ); if( sX < 0 ) sX = 0; if( sY < 0 ) sY = 0; usTraitMenuPosX = sX + 30; usTraitMenuPosY = sY; if ( ( usTraitMenuPosX + 400 ) > SCREEN_WIDTH ) usTraitMenuPosX = SCREEN_WIDTH - 400; if ( ( usTraitMenuPosY + 130 ) > SCREEN_HEIGHT ) usTraitMenuPosY = SCREEN_HEIGHT - 190; SetPos(usTraitMenuPosX, usTraitMenuPosY); } /////////////////////////////// Trait Selection //////////////////////////////////////////// /////////////////////////////// Skill Selection //////////////////////////////////////////// void SkillSelection::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( HAS_SKILL_TRAIT(pSoldier, aVal) ) { SetupPopup("SkillSelection"); POPUP_OPTION *pOption; CHAR16 pStr[300]; SetTraitToDisplay(aVal); SetGridNoForTraitDisplay(sTraitsMenuTargetGridNo); // this switch isn't really necessary. But dividing the skills into menus for each trait gives a better overview, and looks way better than a huge list switch ( aVal ) { case RADIO_OPERATOR_NT: { for(UINT32 uiCounter = SKILLS_RADIO_FIRST; uiCounter <= SKILLS_RADIO_LAST; ++uiCounter) { swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] ); if ( uiCounter == SKILLS_RADIO_ARTILLERY) pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Setup_ArtillerySector, uiCounter ) ); else if ( uiCounter == SKILLS_RADIO_CALLREINFORCEMENTS) pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Setup_ReinforcementSector, uiCounter ) ); else pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_SkillSelection, uiCounter ) ); // if we cannot perform this skill, grey it out if ( !(pSoldier->CanUseSkill(uiCounter, TRUE)) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } } break; case INTEL: { for ( UINT32 uiCounter = SKILLS_INTEL_FIRST; uiCounter <= SKILLS_INTEL_LAST; ++uiCounter ) { swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_SkillSelection, uiCounter ) ); // if we cannot perform this skill, grey it out if ( !( pSoldier->CanUseSkill( uiCounter, TRUE, sTraitsMenuTargetGridNo ) ) ) { // Set this option off. pOption->setAvail( new popupCallbackFunction( &Popup_OptionOff, NULL ) ); } GetPopup()->addOption( *pOption ); } } break; case DISGUISE: { for ( UINT32 uiCounter = SKILLS_DISGUISE_FIRST; uiCounter <= SKILLS_DISGUISE_LAST; ++uiCounter ) { swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_SkillSelection, uiCounter ) ); // if we cannot perform this skill, grey it out if ( !( pSoldier->CanUseSkill( uiCounter, TRUE, sTraitsMenuTargetGridNo ) ) ) { // Set this option off. pOption->setAvail( new popupCallbackFunction( &Popup_OptionOff, NULL ) ); } GetPopup()->addOption( *pOption ); } } break; case VARIOUSSKILLS: { for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter) { swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] ); if ( uiCounter == SKILLS_DRAG ) pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Setup_DragSelection, uiCounter ) ); else pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_SkillSelection, uiCounter ) ); // if we cannot perform this skill, grey it out if ( !(pSoldier->CanUseSkill( uiCounter, TRUE, sTraitsMenuTargetGridNo )) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } SetTraitToDisplay(VARIOUSSKILLS); SetGridNoForTraitDisplay(sTraitsMenuTargetGridNo); ToggleTraitRangeView(TRUE); } break; default: break; } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_SkillSelection, 0 ) ); GetPopup()->addOption( *pOption ); } // same y, different x SetPos(gTraitSelection.GetMaxPosX(), usTraitMenuPosY); if ( HAS_SKILL_TRAIT(pSoldier, aVal) ) { UINT8 cnt = 0; switch ( aVal ) { case RADIO_OPERATOR_NT: { for(UINT32 uiCounter = SKILLS_RADIO_FIRST; uiCounter <= SKILLS_RADIO_LAST; ++uiCounter) { SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc( uiCounter, sTraitsMenuTargetGridNo ) ); } } break; case INTEL: { for ( UINT32 uiCounter = SKILLS_INTEL_FIRST; uiCounter <= SKILLS_INTEL_LAST; ++uiCounter ) { SetRegionFastHelpText( &( GetPopup()->MenuRegion[cnt++] ), pSoldier->PrintSkillDesc( uiCounter, sTraitsMenuTargetGridNo ) ); } } break; case DISGUISE: for ( UINT32 uiCounter = SKILLS_DISGUISE_FIRST; uiCounter <= SKILLS_DISGUISE_LAST; ++uiCounter ) { SetRegionFastHelpText( &( GetPopup()->MenuRegion[cnt++] ), pSoldier->PrintSkillDesc( uiCounter, sTraitsMenuTargetGridNo ) ); } break; case VARIOUSSKILLS: { for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter) { SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc(uiCounter, sTraitsMenuTargetGridNo ) ); } } break; } } } void SkillSelection::Functions( UINT32 aVal ) { Cancel(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; UINT8 ubID = WhoIsThere2(sTraitsMenuTargetGridNo, 0 ); BOOLEAN result = pSoldier->UseSkill(aVal, sTraitsMenuTargetGridNo, ubID); // additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pSoldier, ADE_SKILL_RESULT, aVal, result ); Cancel(); gTraitSelection.Cancel(); } /////////////////////////////// Skill Selection //////////////////////////////////////////// /////////////////////////////// Artillery Sector Selection //////////////////////////////////////////// void ArtillerySector::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( pSoldier->CanUseSkill(SKILLS_RADIO_ARTILLERY) ) { SetupPopup("ArtillerySector"); POPUP_OPTION *pOption; CHAR16 pStr[300]; // check wether we can call artillery from the 4 adjacent sectors for (UINT8 i = 0; i < 4; ++i) { INT16 loopX = pSoldier->sSectorX; INT16 loopY = pSoldier->sSectorY; if ( i == 0 ) ++loopY; else if ( i == 1 ) ++loopX; else if ( i == 2 ) --loopY; else if ( i == 3 ) --loopX; if ( loopX < 1 || loopX >= MAP_WORLD_X - 1 || loopY < 1 || loopY >= MAP_WORLD_Y - 1 ) continue; UINT32 sectornr = (UINT32)SECTOR( loopX, loopY ); swprintf( pStr, L"%c%d", loopY + 'A' - 1, loopX ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Setup_ArtilleryTeam, sectornr ) ); // grey out if no artillery can be called from this sector if ( !IsValidArtilleryOrderSector( loopX, loopY, pSoldier->bSectorZ, pSoldier->bTeam ) && !IsValidArtilleryOrderSector( loopX, loopY, pSoldier->bSectorZ, MILITIA_TEAM ) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_ArtillerySector, 0 ) ); GetPopup()->addOption( *pOption ); // certain traits have skills whose effects depend on wether someone is near to us (squadleader, commissar). We therefore display our radius of effect while this display is open SetTraitToDisplay(RADIO_OPERATOR_NT); SetGridNoForTraitDisplay(sTraitsMenuTargetGridNo); ToggleTraitRangeView(TRUE); } // same y, different x SetPos(gSkillSelection.GetMaxPosX(), usTraitMenuPosY); } /////////////////////////////// Artillery Sector Selection //////////////////////////////////////////// /////////////////////////////// Artillery Team Selection //////////////////////////////////////////// void ArtilleryTeam::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( pSoldier->CanUseSkill(SKILLS_RADIO_ARTILLERY) && pSoldier->bSectorZ == 0) { usSector = aVal; SetupPopup("ArtilleryTeam"); POPUP_OPTION *pOption; CHAR16 pStr[300]; // determine sector coordinates INT16 sSectorX = SECTORX(usSector); INT16 sSectorY = SECTORY(usSector); // order artillery from militia swprintf( pStr, pSkillMenuStrings[SKILLMENU_MILITIA] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ArtilleryTeam, MILITIA_TEAM ) ); // grey out if no ArtilleryTeam can be called from this sector if ( !IsValidArtilleryOrderSector( sSectorX, sSectorY, pSoldier->bSectorZ, MILITIA_TEAM ) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); // order artillery from our mercs swprintf( pStr, pSkillMenuStrings[SKILLMENU_OTHERSQUADS] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ArtilleryTeam, pSoldier->bTeam ) ); // grey out if no ArtilleryTeam can be called from this sector if ( !IsValidArtilleryOrderSector( sSectorX, sSectorY, pSoldier->bSectorZ, pSoldier->bTeam ) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_ArtilleryTeam, 0 ) ); GetPopup()->addOption( *pOption ); // certain traits have skills whose effects depend on wether someone is near to us (squadleader, commissar). We therefore display our radius of effect while this display is open SetTraitToDisplay(RADIO_OPERATOR_NT); SetGridNoForTraitDisplay(sTraitsMenuTargetGridNo); ToggleTraitRangeView(TRUE); } // same y, different x SetPos(gArtillerySector.GetMaxPosX(), usTraitMenuPosY); } void ArtilleryTeam::Functions( UINT32 aVal ) { Cancel(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL || !pSoldier->CanUseSkill(SKILLS_RADIO_ARTILLERY) ) return; BOOLEAN result = pSoldier->OrderArtilleryStrike(usSector, sTraitsMenuTargetGridNo, (UINT8)(aVal)); // additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pSoldier, ADE_SKILL_RESULT, SKILLS_RADIO_ARTILLERY, result ); Cancel(); gArtillerySector.Cancel(); gSkillSelection.Cancel(); gTraitSelection.Cancel(); } /////////////////////////////// Artillery Team Selection //////////////////////////////////////////// /////////////////////////////// Reinforcement Sector Selection //////////////////////////////////////////// void ReinforcementSector::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( pSoldier->CanUseSkill(aVal) ) { SetupPopup("Reinforcements sector"); POPUP_OPTION *pOption; CHAR16 pStr[300]; // check wether we can call artillery from the 4 adjacent sectors for (UINT8 i = 0; i < 4; ++i) { INT16 loopX = pSoldier->sSectorX; INT16 loopY = pSoldier->sSectorY; if ( i == 0 ) ++loopY; else if ( i == 1 ) ++loopX; else if ( i == 2 ) --loopY; else if ( i == 3 ) --loopX; if ( loopX < 1 || loopX >= MAP_WORLD_X - 1 || loopY < 1 || loopY >= MAP_WORLD_Y - 1 ) continue; UINT32 sectornr = (UINT32)SECTOR( loopX, loopY ); swprintf( pStr, L"%c%d", loopY + 'A' - 1, loopX ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Setup_ReinforcementNumber, sectornr ) ); // grey out if no reinforcements can be called from this sector if ( !CanRequestMilitiaReinforcements( pSoldier->sSectorX, pSoldier->sSectorY, loopX, loopY ) ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_ReinforcementSector, 0 ) ); GetPopup()->addOption( *pOption ); } // same y, different x SetPos(gSkillSelection.GetMaxPosX(), usTraitMenuPosY); } /////////////////////////////// Reinforcement Sector Selection //////////////////////////////////////////// /////////////////////////////// Reinforcement Number Selection //////////////////////////////////////////// void ReinforcementNumber::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( pSoldier->CanUseSkill(SKILLS_RADIO_CALLREINFORCEMENTS) ) { usSector = aVal; SetupPopup("Reinforcements number submenu"); POPUP_OPTION *pOption; CHAR16 pStr[300]; UINT8 numberofmilitia = NumNonPlayerTeamMembersInSector( SECTORX( usSector ), SECTORY( usSector ), MILITIA_TEAM ); // 5 militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_X_MILITIA], 5 ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, 5 ) ); if ( numberofmilitia < 5 ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); // 10 militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_X_MILITIA], 10 ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, 10 ) ); if ( numberofmilitia < 10 ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); // 15 militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_X_MILITIA], 15 ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, 15 ) ); if ( numberofmilitia < 15 ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); // 20 militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_X_MILITIA], 20 ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, 20 ) ); if ( numberofmilitia < 20 ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } // 30 militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_X_MILITIA], 30 ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, 30 ) ); if ( numberofmilitia < 30 ) { // Set this option off. pOption->setAvail( new popupCallbackFunction( &Popup_OptionOff, NULL ) ); } // 40 militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_X_MILITIA], 40 ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, 40 ) ); if ( numberofmilitia < 40 ) { // Set this option off. pOption->setAvail( new popupCallbackFunction( &Popup_OptionOff, NULL ) ); } GetPopup()->addOption( *pOption ); // all militia option swprintf( pStr, pSkillMenuStrings[SKILLMENU_ALL_MILITIA] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_ReinforcementNumber, numberofmilitia ) ); GetPopup()->addOption( *pOption ); // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_ReinforcementNumber, 0 ) ); GetPopup()->addOption( *pOption ); } // same y, different x SetPos(gReinforcementSector.GetMaxPosX(), usTraitMenuPosY); } void ReinforcementNumber::Functions( UINT32 aVal ) { Cancel(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL || !pSoldier->CanUseSkill(SKILLS_RADIO_CALLREINFORCEMENTS) ) return; BOOLEAN result = pSoldier->RadioCallReinforcements(usSector, aVal); // additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pSoldier, ADE_SKILL_RESULT, SKILLS_RADIO_CALLREINFORCEMENTS, result ); Cancel(); gReinforcementSector.Cancel(); gSkillSelection.Cancel(); gTraitSelection.Cancel(); } /////////////////////////////// Reinforcement Number Selection //////////////////////////////////////////// /////////////////////////////// Soldier Target Selection //////////////////////////////////////////// void SoldierSelection::Setup( UINT32 aVal ) { Destroy(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( pSoldier->CanUseSkill(aVal) ) { usSkill = aVal; SetupPopup("SoldierSelection"); POPUP_OPTION *pOption; CHAR16 pStr[300]; // pretty simple: we find every soldier in a radius around the target position and add him to the list // loop through all soldiers around for ( UINT32 cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID ; cnt <= gTacticalStatus.Team[ CIV_TEAM ].bLastID ; ++cnt ) { INT32 iRange = GetRangeInCellCoordsFromGridNoDiff( sTraitsMenuTargetGridNo, MercPtrs[ cnt ]->sGridNo ); if ( iRange < 100 ) { if ( cnt != pSoldier->ubID ) { swprintf( pStr, L"%s", MercPtrs[ cnt ]->GetName() ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_SoldierSelection, cnt ) ); // grey out if no artillery can be called from this sector if ( 0 ) { // Set this option off. pOption->setAvail(new popupCallbackFunction( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } } } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_SoldierSelection, 0 ) ); GetPopup()->addOption( *pOption ); } // same y, different x SetPos(gSkillSelection.GetMaxPosX(), usTraitMenuPosY); } void SoldierSelection::Functions( UINT32 aVal ) { Cancel(); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; BOOLEAN result = pSoldier->UseSkill(usSkill, sTraitsMenuTargetGridNo, aVal); // additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pSoldier, ADE_SKILL_RESULT, usSkill, result ); Cancel(); gSkillSelection.Cancel(); gTraitSelection.Cancel(); } /////////////////////////////// Soldier Target Selection //////////////////////////////////////////// /////////////////////////////// Drag Selection //////////////////////////////////////////// void DragSelection::Setup( UINT32 aVal ) { Destroy( ); SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier == NULL ) return; if ( pSoldier->CanUseSkill( aVal ) ) { usSkill = aVal; SetupPopup( "DragSelection" ); POPUP_OPTION *pOption; CHAR16 pStr[300]; // pretty simple: we find every soldier in a radius around the target position and add him to the list // loop through all soldiers around for ( UINT32 cnt = gTacticalStatus.Team[OUR_TEAM].bFirstID; cnt <= gTacticalStatus.Team[CIV_TEAM].bLastID; ++cnt ) { if ( cnt != pSoldier->ubID && pSoldier->CanDragPerson(cnt) ) { swprintf( pStr, L"%s", MercPtrs[cnt]->GetName( ) ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_DragSelection, cnt ) ); GetPopup( )->addOption( *pOption ); } } // corpses std::vector corpseids = GetCorpseIDsNearGridNo( pSoldier->sGridNo, pSoldier->pathing.bLevel, 1 ); for ( std::vector::iterator it = corpseids.begin(); it != corpseids.end(); ++it ) { ROTTING_CORPSE* pCorpse = GetRottingCorpse( (*it) ); swprintf( pStr, pSkillMenuStrings[SKILLMENU_CORPSES], pCorpse->name ); // we have to use an offset of NOBODY in order to differentiate between person and corpse pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_DragSelection, (*it) + NOBODY ) ); GetPopup( )->addOption( *pOption ); } // gridno for ( int ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ++ubDirection ) { INT32 sTempGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( ubDirection ) ); UINT32 tiletype; UINT16 structurenumber; UINT8 hitpoints; UINT8 decalflag; if ( pSoldier->CanDragStructure( sTempGridNo ) && IsDragStructurePresent( sTempGridNo, pSoldier->pathing.bLevel, tiletype, structurenumber, hitpoints, decalflag ) ) { int xmlentry; GetDragStructureXmlEntry( tiletype, structurenumber, xmlentry ); if ( xmlentry >= 0 ) { WCHAR buf[256]; MultiByteToWideChar(CP_UTF8, 0, gStructureMovePossible[xmlentry].szTileSetDisplayName, -1, buf, 256); swprintf(pStr, L"%s (%s)", buf, FaceDirs[gOneCDirection[ubDirection]]); // we have to use an offset of NOBODY in order to differentiate between person and corpse pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_DragSelection_GridNo, sTempGridNo ) ); GetPopup()->addOption( *pOption ); } } } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_DragSelection, 0 ) ); GetPopup( )->addOption( *pOption ); } // same y, different x SetPos( gSkillSelection.GetMaxPosX( ), usTraitMenuPosY ); } void DragSelection::Functions( UINT32 aVal ) { SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier ) { BOOLEAN result = pSoldier->UseSkill( usSkill, NOWHERE, aVal ); // additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pSoldier, ADE_SKILL_RESULT, usSkill, result ); } Cancel( ); gSkillSelection.Cancel(); gTraitSelection.Cancel( ); } void DragSelection::FunctionsGridNo( INT32 aVal ) { SOLDIERTYPE * pSoldier = NULL; GetSoldier( &pSoldier, gusSelectedSoldier ); if ( pSoldier ) { BOOLEAN result = pSoldier->UseSkill( usSkill, aVal, 0 ); // additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pSoldier, ADE_SKILL_RESULT, usSkill, result ); } Cancel(); gSkillSelection.Cancel(); gTraitSelection.Cancel(); } /////////////////////////////// Drag Selection //////////////////////////////////////////// /** * Flugente: traits menu popup box * This will create other boxes when needed */ void TraitsMenu( INT32 usMapPos ) { sTraitsMenuTargetGridNo = usMapPos; gTraitSelection.Setup(0); } /////////////////////////////// Trait Selection //////////////////////////////////////////// EquipmentSelection gEquipmentSelection; void Wrapper_Function_EquipmentSelection(UINT32 aVal) { gEquipmentSelection.Functions(aVal); } void Wrapper_Setup_EquipmentSelection(UINT32 aVal) { gEquipmentSelection.Setup(aVal); } void Wrapper_Cancel_EquipmentSelection(UINT32 aVal) { gEquipmentSelection.Cancel(); } /////////////////////////////// Trait Selection //////////////////////////////////////////// /////////////////////////////// Trait Selection //////////////////////////////////////////// UINT32 gEquipmentSelectionFirstEntryShown = 0; UINT32 gEquipmentSelectionLastEntryShown = 0; UINT32 gEquipmentSelectionMaxEntriesShown = 0; void EquipmentSelection::Setup(UINT32 aVal) { Destroy(); SetupPopup("EquipmentSelection"); INT16 sX = 261 + 406 + xResOffset + 30; INT16 sY = 0 + 10 + yResOffset + 30; if ( sX < 0 ) sX = 0; if ( sY < 0 ) sY = 0; usTraitMenuPosX = sX + 30; usTraitMenuPosY = sY; if ( (usTraitMenuPosX + 400) > SCREEN_WIDTH ) usTraitMenuPosX = SCREEN_WIDTH - 400; if ( (usTraitMenuPosY + 130) > SCREEN_HEIGHT ) usTraitMenuPosY = SCREEN_HEIGHT - 190; POPUP_OPTION *pOption; CHAR16 pStr[300]; // create entries for the sub-menus for each trait GetEquipmentTemplates(); // we limit the maximum number of entries shown at once - too many entries could theoretically cause the button system to freak out gEquipmentSelectionMaxEntriesShown = min(40, max( 0, (SCREEN_HEIGHT - 150 - usTraitMenuPosY) / 12 ) ); gEquipmentSelectionLastEntryShown = min( gEquipmentSelectionFirstEntryShown + gEquipmentSelectionMaxEntriesShown, gTemplateVector.size( ) ); if ( gEquipmentSelectionLastEntryShown < gEquipmentSelectionMaxEntriesShown ) gEquipmentSelectionFirstEntryShown = 0; else gEquipmentSelectionFirstEntryShown = gEquipmentSelectionLastEntryShown - gEquipmentSelectionMaxEntriesShown; UINT32 cnt = gEquipmentSelectionFirstEntryShown; for ( UINT32 i = gEquipmentSelectionFirstEntryShown; i < gEquipmentSelectionLastEntryShown; ++i ) { //std::string str8 = (*it); std::string str8 = gTemplateVector[i]; std::size_t found = str8.find_last_of( "." ); std::string str82 = str8.substr( 0, found ); const char* coca = str82.c_str( ); CHAR16 tmpchar[256]; int nChars = MultiByteToWideChar( CP_ACP, 0, coca, -1, NULL, 0 ); MultiByteToWideChar( CP_UTF8, 0, coca, -1, tmpchar, nChars ); pOption = new POPUP_OPTION( &std::wstring( tmpchar ), new popupCallbackFunction( &Wrapper_Function_EquipmentSelection, i ) ); pOption->color_foreground = FONT_GREEN; GetPopup()->addOption(*pOption); } // 'more' option (moves down list) if ( gEquipmentSelectionMaxEntriesShown < gTemplateVector.size( ) ) { swprintf( pStr, pSkillMenuStrings[SKILLMENU_MORE] ); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_EquipmentSelection, 99999 ) ); GetPopup( )->addOption( *pOption ); } // cancel option swprintf(pStr, pSkillMenuStrings[SKILLMENU_CANCEL]); pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_EquipmentSelection, 99998 ) ); GetPopup()->addOption(*pOption); SetPos(usTraitMenuPosX, usTraitMenuPosY); } void EquipmentSelection::Functions(UINT32 aVal) { // this special value allows to 'scroll down' if ( aVal == 99999 ) { gEquipmentSelectionFirstEntryShown += gEquipmentSelectionMaxEntriesShown; if ( gEquipmentSelectionFirstEntryShown >= gTemplateVector.size( ) ) gEquipmentSelectionFirstEntryShown = 0; Cancel( ); EquipmentListMenu(); } else if ( aVal == 99998 ) { gEquipmentSelectionFirstEntryShown = 0; Cancel( ); } else if ( aVal < gTemplateVector.size( ) ) { SOLDIERTYPE* pSoldier = &Menptr[gCharactersList[bSelectedInfoChar].usSolID]; if ( pSoldier ) { std::string name = gTemplateVector[aVal]; ReadEquipmentTable( pSoldier, name ); } // Note that we don't close menu - this way we don't have to open it every time we want to apply a template } } /////////////////////////////// Trait Selection //////////////////////////////////////////// void EquipmentListMenu() { gEquipmentSelection.Setup(0); } void EquipmentListMenuCancel() { gEquipmentSelection.Cancel(); }