mirror of
https://github.com/1dot13/source.git
synced 2026-08-26 14:30:26 +02:00
Route PlotPath tile cost through the shared ActionPointCost
PlotPath carried its own inline copy of the per-tile movement-cost math, which had drifted from ActionPointCost (the function the real per-step movement and the AI path estimate both already use). That divergence is what made the movement cursor mis-predict the real AP spend - e.g. the start-run penalty getting the diagonal x1.4 in the real cost but not the cursor. Replace the inline switch (and its fence/start-run special-cases) with a per-tile EstimateActionPointCost call, threading the simulated previous tile mode so the one-time start-run charge lands exactly once. The cursor estimate now equals what movement deducts, by construction. Behavioural: player movement-cursor AP numbers (and path reachability colouring that keys off the same total) now match the real spend. Real per-step deduction and AI estimates are unchanged - they already used ActionPointCost. The footstep-colour budget still has its own cost copy; left for a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
majcosta
co-authored by
Claude Opus 4.8
parent
b0d4910a3c
commit
4af03075df
+14
-210
@@ -4138,7 +4138,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
|
||||
{
|
||||
INT16 sTileCost,sPoints=0,sAnimCost=0;
|
||||
INT16 sPointsWalk=0,sPointsCrawl=0,sPointsRun=0,sPointsSwat=0;
|
||||
INT16 sExtraCostStand,sExtraCostSwat,sExtraCostCrawl;
|
||||
INT16 sExtraCostStand;
|
||||
FLOAT sMovementAPsCost = 0; // added by SANDRO
|
||||
INT32 iLastGrid, sTempGrid;
|
||||
INT32 iCnt;
|
||||
@@ -4151,7 +4151,6 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
|
||||
LEVELNODE *pNode;
|
||||
UINT16 usMovementModeToUseForAPs;
|
||||
BOOLEAN bIgnoreNextCost = FALSE;
|
||||
INT32 sTestGridNo;
|
||||
|
||||
if ( bPlot && gusPathShown )
|
||||
{
|
||||
@@ -4191,23 +4190,12 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
|
||||
// Add to points, those needed to start from different stance!
|
||||
sPoints = sPoints + MinAPsToStartMovement( pSold, usMovementMode );
|
||||
|
||||
// We should reduce points for starting to run if first tile is a fence...
|
||||
sTestGridNo = NewGridNo(pSold->sGridNo, DirectionInc( (UINT8)guiPathingData[0]));
|
||||
|
||||
// WANNE: Quickfix for wrong pathing data (direction). This fixes crash that could rarly occur
|
||||
if ((UINT8)guiPathingData[0] > 7)
|
||||
{
|
||||
guiPathingData[0] = 0;
|
||||
}
|
||||
|
||||
if ( gubWorldMovementCosts[ sTestGridNo ][ guiPathingData[0] ][ pSold->pathing.bLevel] == TRAVELCOST_FENCE )
|
||||
{
|
||||
if ( usMovementMode == RUNNING && pSold->usAnimState != RUNNING )
|
||||
{
|
||||
sPoints -= GetAPsStartRun( pSold ); // changed by SANDRO
|
||||
}
|
||||
}
|
||||
|
||||
if (bStayOn)
|
||||
{
|
||||
iLastGrid = giPathDataSize+1;
|
||||
@@ -4256,8 +4244,6 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
|
||||
for ( iCnt=0; iCnt < iLastGrid; iCnt++ )
|
||||
{
|
||||
sExtraCostStand = 0;
|
||||
sExtraCostSwat = 0;
|
||||
sExtraCostCrawl = 0;
|
||||
// what is the next gridno in the path?
|
||||
sOldGrid = sTempGrid;
|
||||
|
||||
@@ -4281,14 +4267,12 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
|
||||
usMovementModeToUseForAPs = WALKING;
|
||||
}
|
||||
|
||||
//shadooow: moved inside loop because it can happen we (re)start running after we walked in water
|
||||
if (sSwitchValue != TRAVELCOST_FENCE && usMovementModeToUseForAPs == RUNNING && usMovementModeBefore != RUNNING)
|
||||
{
|
||||
sPoints += GetAPsStartRun(pSold);
|
||||
}
|
||||
// The previous tile's mode drives the one-time start-run charge; capture it before
|
||||
// advancing, so this tile's cost sees the prior mode and the next tile sees this one.
|
||||
const UINT16 usPrevMovementMode = (UINT16)usMovementModeBefore;
|
||||
usMovementModeBefore = usMovementModeToUseForAPs;
|
||||
|
||||
// get the tile cost for that tile based on WALKING
|
||||
|
||||
// get the tile cost for that tile based on WALKING (the footstep-colour budget below still needs it)
|
||||
sTileCost = TerrainActionPoints( pSold, sTempGrid, (INT8)guiPathingData[iCnt], pSold->pathing.bLevel );
|
||||
|
||||
if ( bIgnoreNextCost )
|
||||
@@ -4297,196 +4281,16 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
|
||||
}
|
||||
else
|
||||
{
|
||||
// ATE: If we have a 'special cost, like jump fence...
|
||||
// Single source of truth: charge exactly what the real per-step movement code
|
||||
// deducts (ActionPointCost), routed through EstimateActionPointCost so the
|
||||
// fence-continuation term is included, summed tile by tile. This is what keeps
|
||||
// the cursor estimate and the real spend from ever drifting apart.
|
||||
sPoints += EstimateActionPointCost( pSold, sTempGrid, (INT8)guiPathingData[iCnt], usMovementModeToUseForAPs, (INT8)iCnt, (INT8)iLastGrid, usPrevMovementMode );
|
||||
|
||||
// A fence hop covers its landing tile too - skip that tile's separate cost,
|
||||
// mirroring the two-tile path advance in HandleGotoNewGridNo.
|
||||
if ( sSwitchValue == TRAVELCOST_FENCE )
|
||||
{
|
||||
sPoints = sPoints + sTileCost;
|
||||
|
||||
bIgnoreNextCost = TRUE;
|
||||
|
||||
// If we are changing stance ( either before or after getting there....
|
||||
// We need to reflect that...
|
||||
switch( usMovementModeToUseForAPs )
|
||||
{
|
||||
case RUNNING:
|
||||
case WALKING :
|
||||
case WALKING_WEAPON_RDY:
|
||||
case WALKING_DUAL_RDY:
|
||||
case WALKING_ALTERNATIVE_RDY :
|
||||
|
||||
// silversurfer: It doesn't matter if we continue moving after the jump. If we were standing before we will stand up again.
|
||||
/* // Add here cost to go from crouch to stand AFTER fence hop....
|
||||
// Since it's AFTER.. make sure we will be moving after jump...
|
||||
if ( ( iCnt + 2 ) < iLastGrid )
|
||||
{
|
||||
sExtraCostStand += GetAPsCrouch(pSold, TRUE);
|
||||
|
||||
// ATE: if running, charge extra point to start again
|
||||
if ( usMovementModeToUseForAPs == RUNNING )
|
||||
{
|
||||
sExtraCostStand += GetAPsStartRun(pSold);
|
||||
}
|
||||
|
||||
sPoints = sPoints + sExtraCostStand;
|
||||
}*/
|
||||
// Add cost to stand up after jump
|
||||
sExtraCostStand += GetAPsCrouch(pSold, TRUE);
|
||||
if ( ( iCnt + 2 ) < iLastGrid && usMovementModeToUseForAPs == RUNNING )
|
||||
{
|
||||
sExtraCostStand += GetAPsStartRun(pSold);
|
||||
}
|
||||
sPoints = sPoints + sExtraCostStand;
|
||||
break;
|
||||
|
||||
case SWATTING:
|
||||
case CROUCHEDMOVE_RIFLE_READY:
|
||||
case CROUCHEDMOVE_PISTOL_READY:
|
||||
case CROUCHEDMOVE_DUAL_READY:
|
||||
|
||||
// Add cost to stand up once BEFORE....
|
||||
sExtraCostSwat += GetAPsCrouch(pSold, TRUE);
|
||||
sPoints = sPoints + sExtraCostSwat;
|
||||
break;
|
||||
|
||||
case CRAWLING:
|
||||
|
||||
// Add cost to stand up before and go prone again after jumping
|
||||
sExtraCostCrawl += GetAPsCrouch(pSold, TRUE) + ( 2 * GetAPsProne(pSold, TRUE) );
|
||||
sPoints = sPoints + sExtraCostCrawl;
|
||||
|
||||
// Can't do it here.....
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else if (sTileCost > 0)
|
||||
{
|
||||
// else, movement is adjusted based on mode...
|
||||
|
||||
if (sSwitchValue == TRAVELCOST_NOT_STANDING)
|
||||
{
|
||||
switch( usMovementModeToUseForAPs )
|
||||
{
|
||||
case RUNNING:
|
||||
case WALKING :
|
||||
case WALKING_WEAPON_RDY:
|
||||
case WALKING_DUAL_RDY:
|
||||
case WALKING_ALTERNATIVE_RDY :
|
||||
// charge crouch APs for ducking head!
|
||||
sExtraCostStand += GetAPsCrouch(pSold, TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// so, then we must modify it for other movement styles and accumulate
|
||||
// CHRISL: Force display path to calculate AP cost differently if we're wearing a backpack
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SANDRO - This part have been modified "a bit" (see also "TerrainActionPoints" in "points.cpp")
|
||||
// Check movement modifiers
|
||||
switch( usMovementModeToUseForAPs )
|
||||
{
|
||||
case RUNNING:
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_RUN];
|
||||
break;
|
||||
case WALKING:
|
||||
if ( 0 && !(pSold->MercInWater()) && ( (gAnimControl[ pSold->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ pSold->usAnimState ].uiFlags & ANIM_FIRE ) ))
|
||||
{
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_READY];
|
||||
}
|
||||
else
|
||||
{
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK];
|
||||
}
|
||||
break;
|
||||
case WALKING_ALTERNATIVE_RDY :
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK];
|
||||
break;
|
||||
case WALKING_WEAPON_RDY:
|
||||
case WALKING_DUAL_RDY:
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_READY];
|
||||
break;
|
||||
case SWATTING:
|
||||
case SIDE_STEP_CROUCH_RIFLE:
|
||||
case SIDE_STEP_CROUCH_PISTOL:
|
||||
case SIDE_STEP_CROUCH_DUAL:
|
||||
case CROUCHEDMOVE_RIFLE_READY:
|
||||
case CROUCHEDMOVE_PISTOL_READY:
|
||||
case CROUCHEDMOVE_DUAL_READY:
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_SWAT];
|
||||
break;
|
||||
case CRAWLING:
|
||||
sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_CRAWL];
|
||||
break;
|
||||
default:
|
||||
sMovementAPsCost = sTileCost;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for reverse mode
|
||||
if ( pSold->bReverse || bReverse )
|
||||
sMovementAPsCost += APBPConstants[AP_REVERSE_MODIFIER];
|
||||
|
||||
// STOMP traits - Athletics trait decreases movement cost
|
||||
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSold, ATHLETICS_NT ))
|
||||
{
|
||||
sMovementAPsCost = max(1, (sMovementAPsCost * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100.0f) );
|
||||
}
|
||||
|
||||
// Moa: scuba fins and swimming background
|
||||
if ( pSold->inv[LEGPOS].exists() && HasItemFlag( pSold->inv[LEGPOS].usItem, SCUBA_FINS ) )
|
||||
{
|
||||
if ( TERRAIN_IS_HIGH_WATER( ubTerrainID) )
|
||||
sMovementAPsCost /= 2;
|
||||
else
|
||||
sMovementAPsCost *= 2;
|
||||
}
|
||||
if ( TERRAIN_IS_HIGH_WATER( ubTerrainID) )
|
||||
sMovementAPsCost = sMovementAPsCost * (100 + pSold->GetBackgroundValue(BG_SWIMMING)) / 100.0f;
|
||||
|
||||
// Check if doors if not player's merc (they have to open them manually)
|
||||
if ( sSwitchValue == TRAVELCOST_DOOR && pSold->bTeam != gbPlayerNum )
|
||||
{
|
||||
sMovementAPsCost += GetAPsToOpenDoor( pSold ) + GetAPsToOpenDoor( pSold ); // Include open and close costs!
|
||||
}
|
||||
// Check for stealth mode
|
||||
if (pSold->bStealthMode || bStealth)
|
||||
{
|
||||
// STOMP traits - Stealthy trait decreases stealth AP modifier
|
||||
if (gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSold, STEALTHY_NT))
|
||||
{
|
||||
sMovementAPsCost += max(0.0f, (APBPConstants[AP_STEALTH_MODIFIER] * (100.0f - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
sMovementAPsCost += APBPConstants[AP_STEALTH_MODIFIER];
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: riot shields lower movement speed
|
||||
if ( pSold->IsRiotShieldEquipped( ) )
|
||||
{
|
||||
sMovementAPsCost *= gItemSettings.fShieldMovementAPCostModifier;
|
||||
}
|
||||
|
||||
// Flugente: dragging someone
|
||||
if ( pSold->IsDragging( ) )
|
||||
{
|
||||
sMovementAPsCost *= gItemSettings.fDragAPCostModifier;
|
||||
}
|
||||
|
||||
// Check for backpack
|
||||
sMovementAPsCost += usBackpackPenalty;
|
||||
|
||||
// moving diagonally
|
||||
if (guiPathingData[iCnt] & 1)
|
||||
sMovementAPsCost *= 1.4f;
|
||||
|
||||
sPoints += (INT16)(sMovementAPsCost + 0.5f) + sExtraCostStand;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
}
|
||||
|
||||
// THIS NEXT SECTION ONLY NEEDS TO HAPPEN FOR CURSOR UI FEEDBACK, NOT ACTUAL COSTING
|
||||
|
||||
Reference in New Issue
Block a user