Custom LiftCenter NavigationPoint.

Discussions about Coding and Scripting
User avatar
ExpEM
Adept
Posts: 266
Joined: Wed Nov 09, 2016 1:48 am

Custom LiftCenter NavigationPoint.

Post by ExpEM » Tue Aug 02, 2022 9:24 am

Super fast explanation, I have a stack of boxes in a map with a Z difference of 64uu between each box.
I have set up a path by using LiftExits and LiftCenters to show bots where to jump.
This all works well except for "Classic Mode" with the non-boosted JumpHeight, "Hard Core" and "Turbo Mode" with the boosted JumpHeight work a treat.
Any ideas for a custom LiftCenter that becomes a null path on "Classic Mode"?
Signature goes here.

User avatar
sektor2111
Godlike
Posts: 6042
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Custom LiftCenter NavigationPoint.

Post by sektor2111 » Tue Aug 02, 2022 2:36 pm

Check "PlayerJumpZScalling" delivered by GameInfo child classes. Investigate first what values are given Classic vs HardCore.
Any value which is under "HardCore" mode jumping needs, will need whatever tweaking:

#1 Assign a value in PostBeginPlay (eg: bNoJumpOption if jumping is low from GameInfo ) - if this value goes True, then Cost for "Seeker" should return 100,000,000. If value is false proceed executing parent code - aiming function SpecialCost.

OR

#2 If this Jump-Scaling is lower than "HardCore" allows, call a "for" cycle for removing Paths/upStreamPaths from this node and those connected with this node - Code I think is already provided by TranslocDest class for games that don't use Translocator. In similar format you can remove paths if Jump Scaling doesn't match what route is requiring.

OR

#3 If Jump-Scaling is low, just increase cost of node and get rid of "bSpecialCost".

Extra-Note: Bots embedded in maps in first session won't jump anyway until they get killed at least one time. This is happening because they are not initialized normally which means to take in account this "PlayerJumpZScaling".

Edit: Here is some data - DeathMatchPlus:

Code: Select all

function float PlayerJumpZScaling()
{
	if ( bJumpMatch )
		return 3;
	else if ( bMegaSpeed )
		return 1.2;
	else if ( bHardCoreMode )
		return 1.1;
	else
		return 1.0;
}
And then LiftCenter can be locked/screwed if "Level.Game.PlayerJumpZScaling < 1.1". Increasing cost or removing paths I think are doable even with an external actor tracker not only with a custom LiftCenter...
Your idea is indeed an interesting one :tu: .

User avatar
ExpEM
Adept
Posts: 266
Joined: Wed Nov 09, 2016 1:48 am

Re: Custom LiftCenter NavigationPoint.

Post by ExpEM » Thu Aug 04, 2022 1:09 am

Thank you, I'll have a play around and see what I can get working.

Automatically merged

Worked a treat thank you sector2111!

here is the code:

Code: Select all

//=============================================================================
// ExpEM_JumpPath.
//=============================================================================
class ExpEM_JumpPath expands LiftExit;

function PostBeginPlay()
{
	local Actor Start, End;
	local NavigationPoint N;
	local int distance, reachFlags, i, j;
	local bool bFound;

	Super.PostBeginPlay();

	if ( Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).PlayerJumpZScaling() > 1.09 )
		return;

	// if this game type doesn't boost jump, then get rid of paths through this node
	bSpecialCost = false;
	for ( i=0; i<16; i++ )
	{
		Paths[i] = -1;
		if ( UpstreamPaths[i] != -1 )
		{
			DescribeSpec(UpstreamPaths[i], Start, End, reachFlags, distance);
			bFound = false;
			N = NavigationPoint(Start);
			if ( N != None )
			{
				for ( j=0; j<15; j++ )
				{
					if ( !bFound )
					{
						DescribeSpec(N.Paths[j], Start, End, reachFlags, distance);
						bFound = ( End == self );
					}
					if ( bFound )
						N.Paths[j] = N.Paths[j+1];
				}
				N.Paths[15] = -1;
			}
			UpstreamPaths[i] = -1;
		}
	}
}

event int SpecialCost(Pawn Seeker)
{
	if ( !Seeker.IsA('Bot') || ( Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).PlayerJumpZScaling() < 1.09 ) )
		return 10000000;
	return 300;
}
Note: I have only done the most minimal testing but it appears to be working perfectly.
Note that this is a LiftExit not a LiftCenter!

In my level I have two 64uu jumps in a row, one small box 64uu tall and another 128uu tall, this actor is placed as the start of the path on the ground level, normal LiftCenter (with MaxZdiff=128) on the first box, normal LiftExit on the second box.

Obscure usage case but could be useful for mappers!
I should probably make a custom LiftCenter for the super obscure case that a bot will get stuck trying to get up to the second box (starting from the LiftCenter) but lazy and not entirely sure if that is even possible.

Edit: Mods: the title of this thread can be changed to solved, I can't figure out how to do it ha.
Signature goes here.

User avatar
sektor2111
Godlike
Posts: 6042
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Custom LiftCenter NavigationPoint.

Post by sektor2111 » Thu Aug 04, 2022 2:51 pm

Epic was using something like LiftCenter probably because of speed and accuracy. Usually their "LiftCenter"s are connected only in two directions with 4 reachSpecs. A LiftExit might host links in more directions blocking paths for a larger spot supposed have some passing through. When a LiftCenter (internal point of a Combo) is locked, it's not needed anything else outside - all routing is closed there. But... of course any node can be locked more or less internally and it will work guaranteed if code runs logically. Patch plugins which I wrote are able to turn a PathNode into a sort of PathToggler locking/unlocking routes connected with some desired map event (even game situation).

User avatar
sektor2111
Godlike
Posts: 6042
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Custom LiftCenter NavigationPoint.

Post by sektor2111 » Sun Aug 21, 2022 11:47 am

Allow me a bit of bump concerning generic jumps that are not possible in "Classic" settings. The other solution for customized maps where navigation should be left alone and without processing constantly "SpecialCost" means to simply get rid of paths from outside of navigation network.
This means we can use a... KeyPoint where user will write connection that needs to be inactive in "Low Jump" gaming.
I wrote this stuff for recent edit... several functions are copied from elsewhere since I had them done and already tested.

Code: Select all

class JumpAdjust expands Keypoint;

var() NavigationPoint NStart, NEnd; //Path removed if conditions are not suitable for this spot
var float ZScale;

event PostBeginPlay()
{
	if ( Level.Game != None )
	{
		ZScale = Level.Game.PlayerJumpZScaling();
//		log ("Jump Data ="@ZScale,class.Name);
		if ( NStart != None && NEnd != None )
		{
			if ( ZScale < 1.100000 )
			{
				log("Game has low Jump capability. Removing path from"@NStart.Name@"to"@NEnd.Name$".",class.Name);
				RemovePath(NStart,NEnd);
			}
		}
		else
			log("Path Definition is Incomplete -> both NStart and NEnd are required.",Name);
	}
}

function RemovePath(NavigationPoint A,NavigationPoint B)
{
	local Actor Start, End;
	local int distance, reachFlags, i, j;
	local int Idx;

	Idx = -1;
	for ( i = 0; i < 16; i++ )
	{
		if ( A.Paths[i] > -1 )
		{
			A.DescribeSpec(A.Paths[i],Start,End,reachFlags,distance);
			if ( Start == A && End == B )
			{
				Idx = A.Paths[i];
				A.Paths[i] = -1;
				DefragPaths(A);
				break;
			}
		}
	}
	if ( Idx > -1 )
	{
		for ( j = 0; j < 16; j++)
		{
			if (B.upStreamPaths[j] == Idx)
			{
				B.upStreamPaths[j] = -1;
				DefragUpStreamPaths(B);
				break;
			}
		}
	}
}

final function DefragPaths(NavigationPoint N)
{
	local bool bInvalid;
	local int i, np, cnt;
	local int wrap[16];

	bInvalid = ( N == None || N.bDeleteMe );

	if ( !bInvalid )
	{
		for ( i = 0; i < 16; i++ )
		{
			wrap[i] = N.Paths[i];
			N.Paths[i] = -1;
		}
		cnt = 0;
		for ( np = 0; np < 16; np++ )
		{
			if ( wrap[np] != -1 )
			{
				N.Paths[cnt] = wrap[np];
				cnt++;
			}
		}
	}
	else
		log("Borked - DefragPaths Entry ( NavigationPoint == None )",'PathsListDefragmenter');
}

final function DefragUpstreamPaths(NavigationPoint N)
{
	local bool bInvalid;
	local int i, np, cnt;
	local int wrap[16];

	bInvalid = ( N == None || N.bDeleteMe );

	if ( !bInvalid )
	{
		for ( i = 0; i < 16; i++ )
		{
			wrap[i] = N.UpstreamPaths[i];
			N.UpstreamPaths[i] = -1;
		}
		cnt = 0;
		for ( np = 0; np < 16; np++ )
		{
			if ( wrap[np] != -1 )
			{
				N.UpstreamPaths[cnt] = wrap[np];
				cnt++;
			}
		}
	}
	else
		log("Borked - DefragUpstreamPaths Entry ( NavigationPoint == None )",'UpStreamPathsListDefragmenter');
}
When stage goes evil, we have the report:

Code: Select all

JumpAdjust: Game has low Jump capability. Removing path from PathNode16 to InventorySpot42.
JumpAdjust: Game has low Jump capability. Removing path from LiftExit2 to PathNode5.
JumpAdjust: Game has low Jump capability. Removing path from PathNode5 to LiftExit3.
JumpAdjust: Game has low Jump capability. Removing path from PlayerStart5 to PathNode22.
Of course it can be completed with more info, such as describing if that Path which needs to be removed doesn't exist because some boys are just pushing buttons and InventorySpot mentioned is gone for good at once with jumpy path. During run-time it won't be any processing of any SpecialCost except those valid needs from stock or whatever.
Sample Stage...
StalCastle_Tweak.PNG
The next chapter that can be used but code would need some hacks tweaking for getting compiled is to remove offender destination for jumpy Reachspec from Navigation chain. Engine won't be able to calculate the route here and no crash will occur because data is still in map but... not chained.
You do not have the required permissions to view the files attached to this post.