Home » PLAYER'S HQ 1.13 » JA2 Complete Mods & Sequels » JA2 Wildfire » Stealthy, Night Ops and mathematics
Stealthy, Night Ops and mathematics[message #330310] Tue, 04 February 2014 17:51 Go to next message
tigerpunch is currently offline tigerpunch

 
Messages:8
Registered:May 2012
Hi there,

I've built my IMP to have stealthy and night ops skills. In my previous game, my IMP had 87 agility and it had night ops/stealthy combination as well (now it has 90 agility).

The problem is, my previous IMP had no problems with running/crawling with the stealth mode. But this character prduces sound when running or crawling with the stealth mde (I mean not always but it still does)

To clarify the test, I've picked Magic the guy with 98 agility and stealth skill slipped over the ground with abslutely no sound...

The questions are: Are there any formulations for us to calculate and observe the effects of skills such as teaching, knifing, night ops and stealth etc since the effects I read are null and meaningless (I mean what does +25 stealth benefit? Or what is the penalty for wielding 2 weapons and how does ambidexter skill and ambidexter (expert) skill let us overcome those hardships) also I 'd like to see some formulas to calculate the total values of those skills.

Also as a night attacker I want to know all combinations with details such as night ops/stealth, stealth (expert), night ops (expert)

Report message to a moderator

Private
Re: Stealthy, Night Ops and mathematics[message #330324] Tue, 04 February 2014 21:36 Go to previous messageGo to next message
Flugente

 
Messages:3509
Registered:April 2009
Location: Germany
That is a question that isn't easy to answer. While the formulas involve no complicated functions, they are long, and I'm currently not in the mood to explain them entirely, you'll see why in a moment Wink

This is actually a problem in most games with stats - if you really want to know the exact effect of a stat, the answer becomes very complicated. I fondly remember Diablo 2, where %LifeLeech was influenced, among others, by damage, global physical resistance, individual physical resistance, crushing blow/critical hit, global lifeleech penalties and numerous other stuff.

This are the two relevant functions for stealth:
#define MAX_MOVEMENT_NOISE 9

UINT8 MovementNoise( SOLDIERTYPE *pSoldier )
{
	INT32	iStealthSkill, iRoll;
	UINT8	ubMaxVolume, ubVolume, ubBandaged, ubEffLife;
	INT8		bInWater = FALSE;

	if ( pSoldier->bTeam == ENEMY_TEAM )
	{
		return( (UINT8) (MAX_MOVEMENT_NOISE - PreRandom( 2 )) );
	}

	// CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE
	//iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveDexterity( pSoldier ) * 4) / 10); // 24-100
	iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveAgility( pSoldier, FALSE ) * 4) / 10); // 24-100

	// big bonus for those "extra stealthy" mercs
	if ( pSoldier->ubBodyType == BLOODCAT )
	{
		iStealthSkill += 50;
	}
	// SANDRO - new/old traits
	else if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT ))
	{
		iStealthSkill += gSkillTraitValues.ubSTBonusToMoveQuietly;
	}
	else if ( !gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_OT ))
	{
		iStealthSkill += 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT );
	}

	INT16 wornstealth = GetWornStealth(pSoldier);
	if ( wornstealth > 0 )
		iStealthSkill += wornstealth / 2;


 //NumMessage("Base Stealth = ",stealthSkill);


	ubBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
	ubEffLife = pSoldier->stats.bLife + (ubBandaged / 2);

 // IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50
	if (ubEffLife < 50)
	{
		// reduce effective stealth skill by up to 50% for low life
		iStealthSkill -= (iStealthSkill * (50 - ubEffLife)) / 100;
	}

	// if breath is below 50%
	if (pSoldier->bBreath < 50)
	{
		// reduce effective stealth skill by up to 50%
		iStealthSkill -= (iStealthSkill * (50 - pSoldier->bBreath)) / 100;
	}

	// if sneaker is moving through water
	if (Water( pSoldier->sGridNo ) )
	{
		iStealthSkill -= 10; // 10% penalty
	}
	else if (DeepWater( pSoldier->sGridNo ) )
	{
		iStealthSkill -= 20; // 20% penalty
	}

	if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ] )
	{
		// minus 3 percent per bonus AP from adrenaline
		iStealthSkill -= 3 * pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ];
	}

/*
	// if sneaker is too eager and impatient to "do it right"
	if ((pSoldier->bTrait == OVER_ENTHUS) || (pSoldier->aiData.bAttitude == AGGRESSIVE))
	{
		ubStealthSkill -= 10;	// 10% penalty
	}
*/
 //NumMessage("Modified Stealth = ",stealthSkill);

	iStealthSkill = __max( iStealthSkill, 0 );

	if (!pSoldier->bStealthMode)	// REGULAR movement
	{
		ubMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16);	// 9 - (0 to 6) => 3 to 9

		if (bInWater)
		{
			ubMaxVolume++;		// in water, can be even louder
		}
		switch (pSoldier->usAnimState)
		{
			case CRAWLING:
				ubMaxVolume -= 2;
				break;
			case SWATTING:
				ubMaxVolume -= 1;
				break;
			case RUNNING:
				ubMaxVolume += 3;
				break;
		}

		if (ubMaxVolume < 2)
		{
			ubVolume = ubMaxVolume;
		}
		else
		{
			ubVolume = 1 + (UINT8) PreRandom(ubMaxVolume);	// actual volume is 1 to max volume
		}
	}
	else			// in STEALTH mode
	{
		iRoll = (INT32) PreRandom(100);	// roll them bones!

		if (iRoll >= iStealthSkill)	// v1.13 modification: give a second chance!
		{
			iRoll = (INT32) PreRandom(100);
		}

		if (iRoll < iStealthSkill)
		{
			ubVolume = 0;	// made it, stayed quiet moving through this tile
		}
		else	// OOPS!
		{
			ubVolume = 1 + ((iRoll - iStealthSkill + 1) / 16);	// volume is 1 - 7 ...
			switch (pSoldier->usAnimState)
			{
				case CRAWLING:
					ubVolume -= 2;
					break;
				case SWATTING:
					ubVolume -= 1;
					break;
				case RUNNING:
					ubVolume += 3;
					break;
			}
			if (ubVolume < 1)
			{
				ubVolume = 0;
			}

			// randomize at which movement step the sneaking failure will happen
//			Status.stepsTilNoise = Random(MAXMOVESTEPS);	// 0 - 6
		}
	}

	//NumMessage("Volume = ",volume);

	// save noise volume where stepped HandleSteppedLook can back get at it later
//	Status.moveNoiseVolume = ubVolume;
	return( ubVolume );
}

...

INT16 GetWornStealth( SOLDIERTYPE * pSoldier )
{
	//note: Stealth bonus is capped at 100
	//note: Stealth is not a perk! Stealth bonus only applies to equipment, and stacks with camouflage
	//note: stealth bonus is not affected by terrain like the camo bonus, otherwise they're very similar
	//note: stealth bonus also affects noise made by characters walking
	INT8	bLoop;
	INT16 ttl=0;

	for (bLoop = HELMETPOS; bLoop <= LEGPOS; ++bLoop)
	{
		if ( pSoldier->inv[bLoop].exists() == true )
			ttl += GetStealthBonus(&pSoldier->inv[bLoop]);
	}

	// Add some default stealth ability to mercs with STEALTHY trait - SANDRO 
	if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT ))
		ttl += gSkillTraitValues.ubSTStealthBonus; 

	ttl += pSoldier->GetBackgroundValue(BG_PERC_STEALTH);

	return __min( ttl, 100 );
}
The Night ops stuff is pretty easy to understand (you are looking at the values in Skills_Settings.ini, are you?) - You see better, hear better, interrupt better. Here's the stuff for interrupts:
INT8 CalcInterruptDuelPts( SOLDIERTYPE * pSoldier, UINT8 ubOpponentID, BOOLEAN fUseWatchSpots )
{
	INT32 iPoints;
	INT8 bLightLevel;
	UINT8	ubDistance;
	DebugMsg (TOPIC_JA2INTERRUPT,DBG_LEVEL_3,"CalcInterruptDuelPts");

	// extra check to make sure neutral folks never get interrupts
	if (pSoldier->aiData.bNeutral)
	{
		return( NO_INTERRUPT );
	}

	// Old: BASE is one point for each experience level.
	// Snap: Agility should be a factor, since it is a measure of
	// a person's reactions.	We'll give more weight to experience
	// though, since combat initiative is too important to be left up
	// to an ordinary skill like agility.
	// BASE = (2*lev + agi/10) / 3
	// Robot has interrupt points based on the controller...
	// Controller's interrupt points are reduced by 2 for being distracted...
	if ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT && pSoldier->CanRobotBeControlled( ) )
	{
		//iPoints = EffectiveExpLevel( MercPtrs[ pSoldier->ubRobotRemoteHolderID ] ) - 2;
		// Snap: (do some proper rounding here)
		iPoints = ( 20*EffectiveExpLevel( MercPtrs[ pSoldier->ubRobotRemoteHolderID ] )
			+ EffectiveAgility( MercPtrs[ pSoldier->ubRobotRemoteHolderID ], FALSE ) + 15 ) / 30 - 2;
	}
	else
	{
		//iPoints = EffectiveExpLevel( pSoldier );
		// Snap:
		iPoints = ( 20*EffectiveExpLevel( pSoldier ) + EffectiveAgility( pSoldier, FALSE ) + 15 ) / 30;

		/*
		if ( pSoldier->bTeam == ENEMY_TEAM )
		{
			// modify by the difficulty level setting
			iPoints += gbDiff[ DIFF_ENEMY_INTERRUPT_MOD ][ SoldierDifficultyLevel( pSoldier ) ];
			iPoints = __max( iPoints, 9 );
		}
		*/

		if ( pSoldier->ControllingRobot( ) )
		{
			iPoints -= 2;
		}
	}

	if (fUseWatchSpots)
	{
		// if this is a previously noted spot of enemies, give bonus points!
		iPoints += GetWatchedLocPoints( pSoldier->ubID, MercPtrs[ ubOpponentID ]->sGridNo, MercPtrs[ ubOpponentID ]->pathing.bLevel );
	}

	// LOSE one point for each 2 additional opponents he currently sees, above 2
	if (pSoldier->aiData.bOppCnt > 2)
	{
		// subtract 1 here so there is a penalty of 1 for seeing 3 enemies
		iPoints -= (pSoldier->aiData.bOppCnt - 1) / 2;
	}

	// LOSE one point if he's trying to interrupt only by hearing
	if (pSoldier->aiData.bOppList[ubOpponentID] == HEARD_THIS_TURN)
	{
		iPoints--;
	}

	//hayden, multiplayer add advantage for a ready'd reapon
	if(is_networked)
	{
		if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) ))
		{
			iPoints=(iPoints + cWeaponReadyBonus);
			
		}
	}

	// if soldier is still in shock from recent injuries, that penalizes him
	iPoints -= pSoldier->aiData.bShock;

	ubDistance = (UINT8) PythSpacesAway( pSoldier->sGridNo, MercPtrs[ ubOpponentID ]->sGridNo );

	// if we are in combat mode - thus doing an interrupt rather than determine who gets first turn -
	// then give bonus
	if ( (gTacticalStatus.uiFlags & INCOMBAT) && (pSoldier->bTeam != gTacticalStatus.ubCurrentTeam) )
	{
		// passive player gets penalty due to range
		iPoints -= (ubDistance / 10);
	}
	else
	{
		// either non-combat or the player with the current turn... i.e. active...
		// unfortunately we can't use opplist here to record whether or not we saw this guy before, because at this point
		// the opplist has been updated to seen.	But we can use gbSeenOpponents ...

		// this soldier is moving, so give them a bonus for crawling or swatting at long distances
		if ( !gbSeenOpponents[ ubOpponentID ][ pSoldier->ubID ] )
		{
			if (pSoldier->usAnimState == SWATTING && ubDistance > (MaxNormalDistanceVisible() / 2) ) // more than 1/2 sight distance
			{
				iPoints++;
			}
			else if (pSoldier->usAnimState == CRAWLING && ubDistance > (MaxNormalDistanceVisible() / 4) ) // more than 1/4 sight distance
			{
				iPoints += ubDistance / STRAIGHT;
			}
		}
	}

	// whether active or not, penalize people who are running
	if ( pSoldier->usAnimState == RUNNING && !gbSeenOpponents[ pSoldier->ubID ][ ubOpponentID ] )
	{
		iPoints -= 2;
	}

	if (pSoldier->ubServicePartner != NOBODY)
	{
		// distracted by being bandaged/doing bandaging
		iPoints -= 2;
	}

	if (gGameOptions.fNewTraitSystem) // new/old traits check - SANDRO
	{
		if ( HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ) )
		{
			bLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel);
			if (bLightLevel > NORMAL_LIGHTLEVEL_DAY + 3)
			{
				// it's dark, give a bonus for interrupts
				iPoints += gSkillTraitValues.ubNOIterruptsBonusInDark;
			}
		}
		// Phlegmatics get a small penalty to interrupts
		if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC )
		{
			iPoints -= 1;
		}
	}
	else
	{
		if ( HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ) )
		{
			bLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel);
			if (bLightLevel > NORMAL_LIGHTLEVEL_DAY + 3)
			{
				// it's dark, give a bonus for interrupts
				iPoints += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT );
			}
		}
	}

	// Flugente: interrupt modifier from special stats
	iPoints += pSoldier->GetInterruptModifier( ubDistance );

	// if he's a computer soldier

	// CJC note: this will affect friendly AI as well...

	if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC )
	{
		if ( pSoldier->bAssignment >= ON_DUTY )
		{
			// make sure don't get interrupts!
			iPoints = -10;
		}

		// GAIN one point if he's previously seen the opponent
		// check for TRUE because -1 means we JUST saw him (always so here)
		if (gbSeenOpponents[pSoldier->ubID][ubOpponentID] == TRUE)
		{
			iPoints++;	// seen him before, easier to react to him
		}
	}
	else if ( pSoldier->bTeam == ENEMY_TEAM )
	{
		// GAIN one point if he's previously seen the opponent
		// check for TRUE because -1 means we JUST saw him (always so here)
		if (gbSeenOpponents[pSoldier->ubID][ubOpponentID] == TRUE)
		{
			iPoints++;	// seen him before, easier to react to him
		}
		else if (gbPublicOpplist[pSoldier->bTeam][ubOpponentID] != NOT_HEARD_OR_SEEN)
		{
			// GAIN one point if opponent has been recently radioed in by his team
			iPoints++;
		}
	}

	if ( TANK( pSoldier ) )
	{
		// reduce interrupt possibilities for tanks!
		iPoints /= 2;
	}

	if (iPoints >= AUTOMATIC_INTERRUPT)
	{
#ifdef BETAVERSION
		NumMessage("CalcInterruptDuelPts: ERROR - Invalid bInterruptDuelPts calculated for soldier ",pSoldier->guynum);
#endif
		iPoints = AUTOMATIC_INTERRUPT - 1;	// hack it to one less than max so its legal
	}

	#ifdef DEBUG_INTERRUPTS
		DebugMsg( TOPIC_JA2INTERRUPT, DBG_LEVEL_3, String("Calculating int pts for %d vs %d, number is %d", pSoldier->ubID, ubOpponentID, iPoints ) );
	#endif
if(is_networked)
{
	SOLDIERTYPE	*pOpp = &Menptr[ubOpponentID];
		#ifdef JA2BETAVERSION
			ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_MPSYSTEM, L"Interrupt: '%s' vs '%s' = %d points.",pSoldier->name,pOpp->name, iPoints );
		#endif
}
	DebugMsg (TOPIC_JA2INTERRUPT,DBG_LEVEL_3,"CalcInterruptDuelPts done");
	return( (INT8)iPoints );
}

TL;DR: If you really want to know it exactly, read the code Smile

Report message to a moderator

Captain

Re: Stealthy, Night Ops and mathematics[message #330333] Wed, 05 February 2014 01:35 Go to previous messageGo to next message
tigerpunch is currently offline tigerpunch

 
Messages:8
Registered:May 2012
thank you for your answer it really helped to understand Smile

But for istealth= exp lvl+ (dex*4/ 10) really? such a shame so max value you can get w/o the bonus is 50 (100 dex 10 lvl) if the formula would have been like that Magic would still make sound

at here I ve read http://jaggedalliance.wikia.com/wiki/Skills_(stats)

(DEX / 2) + (LVL * 5) and my Wildfire is probably a retail version v6.04 which I couldnt find the file you proposed

Also I understand stealth is only required for not making noises. It probably does not make you harder to be spotted visually? (if we ignore your sound penalty).

I've heard that expert stat is like the three times of the speficic non expert stat (night ops or stealth) so I'm rather confused. If that is so expertising 1 stat instead of learning 2 maybe more benefical dont you think? I sticked with the mid range assasination with colt commando strategy in mid/late game so night ops/stealth made good combination in my previous campaign. I'm scared to lose my range if I sacrifice night ops and go expert stealth and if I do the opoosite I might not get too close with my silenced weapon, cannot sneak-dive to a roof. With only night ops I was able to detect anyone within my colt range so I might lose my silenced-range control if I sacrifice stealth (of course I assumed stealth already makes you harder to be detected visually is it so?)

Report message to a moderator

Private
Re: Stealthy, Night Ops and mathematics[message #330335] Wed, 05 February 2014 01:51 Go to previous messageGo to next message
Flugente

 
Messages:3509
Registered:April 2009
Location: Germany
Read the code. Dexterity isn't relevant to stealth anymore, it's agility:
iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveAgility( pSoldier, FALSE ) * 4) / 10); // 24-100
The highest value you can achieve here is 100 with a lvl 10 merc with 100 AGI, not taking into account squadleader boni, drugs and backgrounds. The stealth boni come later in that formula.

That wiki is, to say it politely, inaccurate and should be taken only as a very broad generalisation.

tigerpunch
(DEX / 2) + (LVL * 5) and my Wildfire is probably a retail version v6.04 which I couldnt find the file you proposed
Dex is irrelevant, and... eh... what?

Stealth does not hide you visually. Camouflage does that.

Read the Skills_Settings.ini, and read the code bit I've quoted. In most cases, the expert level of traits simply gives 2 times the normal level of boni. It would also be helpful to know wether you play with old or new traits - for example, Night Ops and Stealth only have one level in the new Trait system.

Report message to a moderator

Captain

Re: Stealthy, Night Ops and mathematics[message #330378] Thu, 06 February 2014 22:23 Go to previous messageGo to next message
Flugente

 
Messages:3509
Registered:April 2009
Location: Germany
Hmm. Didn't see that this a pure wildfire thread. In case you are playing with a truly ancient game version (no 1.13, no nothing), then some of the facts I dismissed as wrong might actually be true for that old exe. No telling without knowing what version you are using.

Report message to a moderator

Captain

Re: Stealthy, Night Ops and mathematics[message #362146 is a reply to message #330378] Thu, 31 December 2020 07:23 Go to previous message
Bullpup is currently offline Bullpup

 
Messages:42
Registered:December 2020
If Stealth is capped at 100 and you can get that with lvl 10 Agi 100 merc, does that mean that the Stealth perk or the Spotter/Stalker backgrounds get less usefull in late game?

Edit: I just noticed this is Wildfire thread, I was asking for 8914 1.13.

[Updated on: Thu, 31 December 2020 07:26]

Report message to a moderator

Corporal
Previous Topic: IMP editor for Wildfire?
Next Topic: How to get rid of Brenda in San Mona ?
Goto Forum:
  


Current Time: Fri Mar 29 07:45:25 GMT+2 2024

Total time taken to generate the page: 0.00842 seconds