예제 #1
0
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 );
}
예제 #2
0
파일: Movement.c 프로젝트: bowlofstew/ja2
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);
}
예제 #3
0
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 );
}
예제 #4
0
// 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();
        }
    }
}