INT8 CalcTrapDetectLevel( SOLDIERTYPE * pSoldier, BOOLEAN fExamining ) { // return the level of trap which the guy is able to detect INT8 bDetectLevel; // formula: 1 pt for every exp_level // plus 1 pt for every 40 explosives // less 1 pt for every 20 wisdom MISSING bDetectLevel = EffectiveExpLevel( pSoldier ); bDetectLevel += (EffectiveExplosive( pSoldier ) / 40); bDetectLevel -= ((100 - EffectiveWisdom( pSoldier ) ) / 20); // if the examining flag is true, this isn't just a casual glance // and the merc should have a higher chance if (fExamining) { bDetectLevel += (INT8) PreRandom(bDetectLevel / 3 + 2); } // if substantially bleeding, or still in serious shock, randomly lower value if ((pSoldier->bBleeding > 20) || (pSoldier->bShock > 1)) { bDetectLevel -= (INT8) PreRandom(3); } if (bDetectLevel < 1) { bDetectLevel = 1; } return( bDetectLevel ); }
INT8 RandomPointPatrolAI(SOLDIERTYPE *pSoldier) { INT16 sPatrolPoint; INT8 bOldOrders, bPatrolIndex; INT8 bCnt; sPatrolPoint = pSoldier->usPatrolGrid[pSoldier->bNextPatrolPnt]; // if we're already there, advance next patrol point if (pSoldier->sGridNo == sPatrolPoint || pSoldier->bNextPatrolPnt == 0) { // find next valid patrol point // we keep a count of the # of times we are in here to make sure we don't get into an endless //loop bCnt = 0; do { // usPatrolGrid[0] gets used for centre of close etc patrols, so we have to add 1 to the Random # bPatrolIndex = (INT8) PreRandom( pSoldier->bPatrolCnt ) + 1; sPatrolPoint = pSoldier->usPatrolGrid[ bPatrolIndex]; bCnt++; } while ( (sPatrolPoint == pSoldier->sGridNo) || ( (sPatrolPoint != NOWHERE) && (bCnt < pSoldier->bPatrolCnt) && (NewOKDestination(pSoldier,sPatrolPoint,IGNOREPEOPLE, pSoldier->bLevel ) < 1)) ); if (bCnt == pSoldier->bPatrolCnt) { // ok, we tried doing this randomly, didn't work well, so now do a linear search pSoldier->bNextPatrolPnt = 0; do { sPatrolPoint = NextPatrolPoint(pSoldier); } while ((sPatrolPoint != NOWHERE) && (NewOKDestination(pSoldier,sPatrolPoint,IGNOREPEOPLE, pSoldier->bLevel) < 1)); } // do nothing this time around if (pSoldier->sGridNo == sPatrolPoint) { return( FALSE ); } } // if we don't have a legal patrol point if (sPatrolPoint == NOWHERE) { #ifdef BETAVERSION NumMessage("PointPatrolAI: ERROR - no legal patrol point for %d",pSoldier->ubID); #endif // over-ride orders to something safer pSoldier->bOrders = FARPATROL; return(FALSE); } // make sure we can get there from here at this time, if we can't get all // the way there, at least do our best to get close if (LegalNPCDestination(pSoldier,sPatrolPoint,ENSURE_PATH,WATEROK,0)) { pSoldier->bPathStored = TRUE; // optimization - Ian pSoldier->usActionData = sPatrolPoint; } else { // temporarily extend roaming range to infinity by changing orders, else // this won't work if the next patrol point is > 10 tiles away! bOldOrders = pSoldier->bOrders; pSoldier->bOrders = SEEKENEMY; pSoldier->usActionData = GoAsFarAsPossibleTowards(pSoldier,sPatrolPoint,pSoldier->bAction); pSoldier->bOrders = bOldOrders; // if it's not possible to get any closer, that's OK, but fail this call if (pSoldier->usActionData == NOWHERE) return(FALSE); } // passed all tests - start moving towards next patrol point #ifdef DEBUGDECISIONS sprintf(tempstr,"%s - POINT PATROL to grid %d",pSoldier->name,pSoldier->usActionData); AIPopMessage(tempstr); #endif return(TRUE); }
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 ); }
// WANNE - BMP: DONE! void LoadWorldItemsFromMap( INT8 **hBuffer, float dMajorMapVersion, int ubMinorMapVersion ) { // Start loading itmes... UINT32 i; WORLDITEM dummyItem; INT32 iItemIndex; UINT32 uiNumWorldItems; //If any world items exist, we must delete them now. TrashWorldItems(); //Read the number of items that were saved in the map. LOADDATA( &uiNumWorldItems, *hBuffer, 4 ); if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME && !gfEditMode ) { //The sector has already been visited. The items are saved in a different format that will be //loaded later on. So, all we need to do is skip the data entirely. if (dMajorMapVersion >= 6.0 && ubMinorMapVersion > 26 ) { for (unsigned int x = 0; x < uiNumWorldItems; ++x) { //ADB WORLDITEM's size on disk is unknown dummyItem.Load(hBuffer, dMajorMapVersion, ubMinorMapVersion); } } else { *hBuffer += sizeof ( OLD_WORLDITEM_101 ) * uiNumWorldItems; } return; } else for ( i = 0; i < uiNumWorldItems; i++ ) { //Add all of the items to the world indirectly through AddItemToPool, but only if the chance //associated with them succeed. dummyItem.Load(hBuffer, dMajorMapVersion, ubMinorMapVersion); gMapTrn.GetTrnCnt(dummyItem.sGridNo);//dnl ch44 270909 WORLDITEM translation if( dummyItem.object.usItem == OWNERSHIP ) { dummyItem.ubNonExistChance = 0; } if( gfEditMode || dummyItem.ubNonExistChance <= PreRandom( 100 ) || (gGameExternalOptions.ubMapItemChanceOverride > 0 && (gGameExternalOptions.ubMapItemChanceOverride >= PreRandom(100)) ) ) //Madd: map item chance override, note this calc is done in reverse { if( !gfEditMode ) { //check for matching item existance modes and only add if there is a match! //if we are in platinum mode, REALISTIC items are allowed, but not SCIFI items if( dummyItem.usFlags & WORLD_ITEM_SCIFI_ONLY && !(gGameOptions.ubGameStyle == STYLE_SCIFI) || dummyItem.usFlags & WORLD_ITEM_REALISTIC_ONLY && (gGameOptions.ubGameStyle == STYLE_SCIFI) ) { //no match, so don't add item to world continue; } /* if ( !gGameOptions.fGunNut ) { UINT16 usReplacement; // do replacements? if ( Item[ dummyItem.object.usItem ].usItemClass == IC_GUN ) { INT8 bAmmo, bNewAmmo; usReplacement = StandardGunListReplacement( dummyItem.object.usItem ); if ( usReplacement ) { // everything else can be the same? no. bAmmo = dummyItem.object[0]->data.gun.ubGunShotsLeft; bNewAmmo = (Weapon[ usReplacement ].ubMagSize * bAmmo) / Weapon[ dummyItem.object.usItem ].ubMagSize; if ( bAmmo > 0 && bNewAmmo == 0 ) { bNewAmmo = 1; } dummyItem.object.usItem = usReplacement; dummyItem.object[0]->data.gun.ubGunShotsLeft = bNewAmmo; } } if ( Item[ dummyItem.object.usItem ].usItemClass == IC_AMMO ) { usReplacement = StandardGunListAmmoReplacement( dummyItem.object.usItem ); if ( usReplacement ) { UINT8 ubLoop; // go through status values and scale up/down for ( ubLoop = 0; ubLoop < dummyItem.object.ubNumberOfObjects; ubLoop++ ) { dummyItem.object.status.bStatus[ ubLoop ] = dummyItem.object.status.bStatus[ ubLoop ] * Magazine[ Item[ usReplacement ].ubClassIndex ].ubMagSize / Magazine[ Item[ dummyItem.object.usItem ].ubClassIndex ].ubMagSize; } // then replace item # dummyItem.object.usItem = usReplacement; } } } */ } if( dummyItem.object.usItem == ACTION_ITEM && gfLoadPitsWithoutArming ) { //if we are loading a pit, they are typically loaded without being armed. if( dummyItem.object[0]->data.misc.bActionValue == ACTION_ITEM_SMALL_PIT || dummyItem.object[0]->data.misc.bActionValue == ACTION_ITEM_LARGE_PIT ) { dummyItem.usFlags &= ~WORLD_ITEM_ARMED_BOMB; dummyItem.bVisible = BURIED; dummyItem.object[0]->data.misc.bDetonatorType = 0; } } else if ( dummyItem.bVisible == HIDDEN_ITEM && dummyItem.object[0]->data.bTrap > 0 && ( Item[dummyItem.object.usItem].mine || dummyItem.object.usItem == TRIP_FLARE || dummyItem.object.usItem == TRIP_KLAXON) ) { ArmBomb( &dummyItem.object, BOMB_PRESSURE ); dummyItem.usFlags |= WORLD_ITEM_ARMED_BOMB; // this is coming from the map so the enemy must know about it. gpWorldLevelData[ dummyItem.sGridNo ].uiFlags |= MAPELEMENT_ENEMY_MINE_PRESENT; } if ( dummyItem.usFlags & WORLD_ITEM_ARMED_BOMB ) { //all armed bombs are buried dummyItem.bVisible = BURIED; } #if 0//dnl ch74 201013 this is already done in OBJECTTYPE::Load() //Madd: ok, so this drives me nuts -- why bother with default attachments if the map isn't going to load them for you? //this should fix that... for(UINT8 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS; cnt++) { if(Item [ dummyItem.object.usItem ].defaultattachments[cnt] == 0) break; OBJECTTYPE defaultAttachment; CreateItem(Item [ dummyItem.object.usItem ].defaultattachments[cnt],100,&defaultAttachment); dummyItem.object.AttachObject(NULL,&defaultAttachment, FALSE); } #endif AddItemToPoolAndGetIndex( dummyItem.sGridNo, &dummyItem.object, dummyItem.bVisible, dummyItem.ubLevel, dummyItem.usFlags, dummyItem.bRenderZHeightAboveLevel, dummyItem.soldierID, &iItemIndex ); gWorldItems[ iItemIndex ].ubNonExistChance = dummyItem.ubNonExistChance; } } if ( !gfEditMode ) { DeleteWorldItemsBelongingToTerroristsWhoAreNotThere(); if ( gWorldSectorX == 3 && gWorldSectorY == MAP_ROW_P && gbWorldSectorZ == 1 ) { DeleteWorldItemsBelongingToQueenIfThere(); } } }