void HourlyCamouflageUpdate( void ) { INT8 bMercID, bLastTeamID; SOLDIERTYPE * pSoldier; bMercID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID; // loop through all mercs for ( pSoldier = MercPtrs[ bMercID ]; bMercID <= bLastTeamID; bMercID++,pSoldier++) { if ( pSoldier->bActive ) { // if the merc has non-zero camo, degrade it by 1% if( ( pSoldier->bCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED) ) ) ) { pSoldier->bCamo -= 2; if (pSoldier->bCamo <= 0) { pSoldier->bCamo = 0; // Reload palettes.... if ( pSoldier->bInSector ) { CreateSoldierPalettes( pSoldier ); } ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WORN_OFF], pSoldier->name ); DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); } } // if the merc has non-zero monster smell, degrade it by 1 if ( pSoldier->bMonsterSmell > 0 ) { pSoldier->bMonsterSmell--; /* if (pSoldier->bMonsterSmell == 0) { // Reload palettes.... if ( pSoldier->bInSector ) { CreateSoldierPalettes( pSoldier ); } ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WORN_OFF], pSoldier->name ); DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); } */ } } } }
/////////////////////////////// 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<void,UINT32>( &Wrapper_Setup_ArtillerySector, uiCounter ) ); else if ( uiCounter == SKILLS_RADIO_CALLREINFORCEMENTS) pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &Wrapper_Setup_ReinforcementSector, uiCounter ) ); else pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &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<bool,void*>( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } } break; case VARIOUSSKILLS: { for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter) { swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &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<bool,void*>( &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<void,UINT32>( &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) ); } } break; case VARIOUSSKILLS: { for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter) { SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc(uiCounter) ); } } break; } } }
/////////////////////////////// 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 = 2; UINT8 traitarray[num]; traitarray[0] = RADIO_OPERATOR_NT; traitarray[1] = VARIOUSSKILLS; for ( int i = 0; i < num; ++i) { swprintf( pStr, gzMercSkillTextNew[traitarray[i]] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &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<bool,void*>( &Popup_OptionOff, NULL )); } GetPopup()->addOption( *pOption ); } // cancel option swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &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, 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); }
INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) { INT32 iSkill; INT32 iChance, iReportChance; INT32 iRoll, iMadeItBy; INT8 bSlot; INT32 iLoop; SOLDIERTYPE * pTeamSoldier; INT8 bBuddyIndex; BOOLEAN fForceDamnSound = FALSE; iReportChance = -1; switch (bReason) { case LOCKPICKING_CHECK: case ELECTRONIC_LOCKPICKING_CHECK: fForceDamnSound = TRUE; iSkill = EffectiveMechanical( pSoldier ); if (iSkill == 0) { break; } // adjust skill based on wisdom (knowledge) iSkill = iSkill * (EffectiveWisdom( pSoldier ) + 100) / 200; // and dexterity (clumsy?) iSkill = iSkill * (EffectiveDexterity( pSoldier ) + 100) / 200; // factor in experience iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3; if (HAS_SKILL_TRAIT( pSoldier, LOCKPICKING ) ) { // if we specialize in picking locks... iSkill += gbSkillTraitBonus[LOCKPICKING] * NUM_SKILL_TRAITS( pSoldier, LOCKPICKING ); } if (bReason == ELECTRONIC_LOCKPICKING_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) ) { // if we are unfamiliar with electronics... iSkill /= 2; } // adjust chance based on status of kit bSlot = FindObj( pSoldier, LOCKSMITHKIT ); if (bSlot == NO_SLOT) { // this should never happen, but might as well check... iSkill = 0; } iSkill = iSkill * pSoldier->inv[bSlot].bStatus[0] / 100; break; case ATTACHING_DETONATOR_CHECK: case ATTACHING_REMOTE_DETONATOR_CHECK: iSkill = EffectiveExplosive( pSoldier ); if (iSkill == 0) { break; } iSkill = (iSkill * 3 + EffectiveDexterity( pSoldier ) ) / 4; if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS )) ) { iSkill /= 2; } break; case PLANTING_BOMB_CHECK: case PLANTING_REMOTE_BOMB_CHECK: iSkill = EffectiveExplosive( pSoldier ) * 7; iSkill += EffectiveWisdom( pSoldier ) * 2; iSkill += EffectiveExpLevel( pSoldier ) * 10; iSkill = iSkill / 10; // bring the value down to a percentage if ( bReason == PLANTING_REMOTE_BOMB_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) ) { // deduct only a bit... iSkill = (iSkill * 3) / 4; } // Ok, this is really damn easy, so skew the values... // e.g. if calculated skill is 84, skewed up to 96 // 51 to 84 // 22 stays as is iSkill = (iSkill + 100 * (iSkill / 25) ) / (iSkill / 25 + 1); break; case DISARM_TRAP_CHECK: fForceDamnSound = TRUE; iSkill = EffectiveExplosive( pSoldier ) * 7; if ( iSkill == 0 ) { break; } iSkill += EffectiveDexterity( pSoldier ) * 2; iSkill += EffectiveExpLevel( pSoldier ) * 10; iSkill = iSkill / 10; // bring the value down to a percentage // penalty based on poor wisdom iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5; break; case DISARM_ELECTRONIC_TRAP_CHECK: fForceDamnSound = TRUE; iSkill = __max( EffectiveMechanical( pSoldier ) , EffectiveExplosive( pSoldier ) ) * 7; if ( iSkill == 0 ) { break; } iSkill += EffectiveDexterity( pSoldier ) * 2; iSkill += EffectiveExpLevel( pSoldier ) * 10; iSkill = iSkill / 10; // bring the value down to a percentage // penalty based on poor wisdom iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5; if ( !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS )) ) { iSkill = (iSkill * 3) / 4; } break; case OPEN_WITH_CROWBAR: // Add for crowbar... iSkill = EffectiveStrength( pSoldier ) + 20; fForceDamnSound = TRUE; break; case SMASH_DOOR_CHECK: iSkill = EffectiveStrength( pSoldier ); break; case UNJAM_GUN_CHECK: iSkill = 30 + EffectiveMechanical( pSoldier ) / 2; break; case NOTICE_DART_CHECK: // only a max of ~20% chance iSkill = EffectiveWisdom( pSoldier ) / 10 + EffectiveExpLevel( pSoldier ); break; case LIE_TO_QUEEN_CHECK: // competitive check vs the queen's wisdom and leadership... poor guy! iSkill = 50 * ( EffectiveWisdom( pSoldier ) + EffectiveLeadership( pSoldier ) ) / ( gMercProfiles[ QUEEN ].bWisdom + gMercProfiles[ QUEEN ].bLeadership ); break; case ATTACHING_SPECIAL_ITEM_CHECK: case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: iSkill = EffectiveMechanical( pSoldier ); if (iSkill == 0) { break; } // adjust skill based on wisdom (knowledge) iSkill = iSkill * (EffectiveWisdom( pSoldier ) + 100) / 200; // and dexterity (clumsy?) iSkill = iSkill * (EffectiveDexterity( pSoldier ) + 100) / 200; // factor in experience iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3; if (bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) ) { // if we are unfamiliar with electronics... iSkill /= 2; } break; default: iSkill = 0; break; } iSkill -= GetSkillCheckPenaltyForFatigue( pSoldier, iSkill ); iChance = iSkill + bChanceMod; switch (bReason) { case LOCKPICKING_CHECK: case ELECTRONIC_LOCKPICKING_CHECK: case DISARM_TRAP_CHECK: case DISARM_ELECTRONIC_TRAP_CHECK: case OPEN_WITH_CROWBAR: case SMASH_DOOR_CHECK: case ATTACHING_SPECIAL_ITEM_CHECK: case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: // for lockpicking and smashing locks, if the chance isn't reasonable // we set it to 0 so they can never get through the door if they aren't // good enough if (iChance < 30) { iChance = 0; break; } // else fall through default: iChance += GetMoraleModifier( pSoldier ); break; } if (iChance > 99) { iChance = 99; } else if (iChance < 0) { iChance = 0; } iRoll = PreRandom( 100 ); iMadeItBy = iChance - iRoll; if (iMadeItBy < 0) { if ( (pSoldier->bLastSkillCheck == bReason) && (pSoldier->sGridNo == pSoldier->sSkillCheckGridNo) ) { pSoldier->ubSkillCheckAttempts++; if (pSoldier->ubSkillCheckAttempts > 2) { if (iChance == 0) { // do we realize that we just can't do this? if ( (100 - (pSoldier->ubSkillCheckAttempts - 2) * 20) < EffectiveWisdom( pSoldier ) ) { // say "I can't do this" quote TacticalCharacterDialogue( pSoldier, QUOTE_DEFINITE_CANT_DO ); return( iMadeItBy ); } } } } else { pSoldier->bLastSkillCheck = bReason; pSoldier->ubSkillCheckAttempts = 1; pSoldier->sSkillCheckGridNo = pSoldier->sGridNo; } if ( fForceDamnSound || Random( 100 ) < 40 ) { switch( bReason ) { case UNJAM_GUN_CHECK: case NOTICE_DART_CHECK: case LIE_TO_QUEEN_CHECK: // silent check break; default: DoMercBattleSound( pSoldier, BATTLE_SOUND_CURSE1 ); break; } } } else { // A buddy might make a positive comment based on our success; // Increase the chance for people with higher skill and for more difficult tasks iChance = 15 + iSkill / 20 + (-bChanceMod) / 20; if (iRoll < iChance) { // If a buddy of this merc is standing around nearby, they'll make a positive comment. iLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; for ( pTeamSoldier = MercPtrs[ iLoop ]; iLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; iLoop++,pTeamSoldier++ ) { if ( OK_INSECTOR_MERC( pTeamSoldier ) ) { bBuddyIndex = WhichBuddy( pTeamSoldier->ubProfile, pSoldier->ubProfile ); if (bBuddyIndex >= 0 && SpacesAway( pSoldier->sGridNo, pTeamSoldier->sGridNo ) < 15) { switch( bBuddyIndex ) { case 0: // buddy #1 did something good! TacticalCharacterDialogue( pTeamSoldier, QUOTE_BUDDY_1_GOOD ); break; case 1: // buddy #2 did something good! TacticalCharacterDialogue( pTeamSoldier, QUOTE_BUDDY_2_GOOD ); break; case 2: // learn to like buddy did something good! TacticalCharacterDialogue( pTeamSoldier, QUOTE_LEARNED_TO_LIKE_WITNESSED ); break; default: break; } } } } } } return( iMadeItBy ); }