Jump to content

Ask me anything about the Jedi source code


Recommended Posts

@@MGummelt

 

Would you happen to know if the .menu files were made by hand in a text editor, or the devs used a program?

 

You do realize they didn't create the .menu file system, right? It came from Q3: Team Arena. And it was all by hand in text editor almost certainly.  They may have prototyped what it should look like in some design program, however.

Link to comment

You do realize they didn't create the .menu file system, right? It came from Q3: Team Arena. And it was all by hand almost certainly. They may have prototyped what it should look like in some design program, however.

You do realize that I never said anything about Ravensoft creating the .menu system, right? Nor do I presume they did.

Link to comment

Oh, I've got one actually @@MGummelt especially since you were pretty much responsible for vehicles in MP.

 

Why is it that we see a line in the .VEH file for this?

hideRider          1

At the same time though deleting this or setting it's value to 0 doesn't seem to do anything? Is there something we are doing wrong? I'm asking because at one point I started work on an AT-RT which is a walker type that has an open mount. I couldn't get the player to be visible using the VEH_WALKER type so I was forced to switch it to the TAUNTAUN class NPC which of course didn't work right because the blasters wouldn't work properly.

Smoo and Cerez like this
Link to comment

The game's code refers to the Imperial Saboteurs being able to dodge blaster fire and a saboteur commando that uses dual blaster pistols. In the game he isn't any different than the regular pistol-wielding saboteur, but this can be mostly reimplemented from copying over from the cultist commando's .npc file, which, interestingly enough, is in the game's files but isn't ever seen ingame. Is the saboteur commando having only one pistol intentional or was it something someone forgot to change before the game shipped? And the Saboteur's dodging behavior doesn't seem to actually exist. Was it ever implemented?

Link to comment

In Jedi Academy the amount of time that the bodies of dead NPCs remain on screen can be changed with g_corpseRemovalTime command, but I was wondering if there is a similar console command or script change for the amount of time dead NPCs remain in Jedi Outcast?

Smoo likes this
Link to comment

heh, i made a forum account here just so I could ask about persistent corpses in outcast. looks like i was beat to the punch.

buuuuut, i have been doing some digging around in the source code, and in NPC.cpp there's a whole section on corpse removal and all the requirements for a corpse to be removed, etc.

this part here piques my interest:

#define REMOVE_DISTANCE 128
#define REMOVE_DISTANCE_SQR (REMOVE_DISTANCE * REMOVE_DISTANCE)
 
if i were to change remove_distance variable from 128 to, say, 999999, would that have the desired effect? if not, what would?
i really have no idea what i'm doing, but it seems to make sense.
 
Link to comment

@@MGummelt, another question/observation would be with regards to the saber system in general.

 

I'm sure many others can chime in but, simply recompiling the originally released SDK (also linux vs windows) even will cause differences in blocks and damages, more ghosting (visual hits that aren't hits) supposedly according to many people in the game and mod communities.  I guess the problems might stem from different floating point precisions etc and the original codebase being super picky about values in the collision code and w_saber.c.  But nobody has ever really nailed down what the causes are.  And obviously, most people aren't going to want to use ancient compiler versions anymore, its not realistic.  Someone had asked earlier on Discord what computer specs were used to compile JKA for Windows anyway?  And this problem isn't exactly new.  It's been highly debated and contested for many years as far as pure basers won't even use mods because the feels are different even if the code remains the same.

 Hmm, interesting.  I was not aware of this difference.  I'll have to ask James Monroe (the Lead Programmer on JKO/JKA) why that may be...

Smoo likes this
Link to comment

@MGummelt, how did you guys handle offsetting weapon projectiles from center, I.E. a right handed weapon? I've tried creating a vector offset relative to the view vector, but the offset always ends up being from the world vector. I am working to recreate the Fusion Cutter from Dark Forces (see image below). Most of my relevant experimentation with the community's help his here: https://jkhub.org/topic/7581-vexing-vectors/

 

CvhxSjA.jpg

Link to comment

@@MGummelt, I do have a specific question regarding the NPC waypointing system and ICARUS -- if you can help shed any light on this long bugging mystery:

 

Discussion thread: https://jkhub.org/topic/6594-walking-an-npc/

 

When assigning 3 waypoints, and giving an NPC the task of randomly walking between them in an endless loop, the walking behaviour sporadically breaks, with the NPC either changing direction midway, or walking to a waypoint, and then stopping.

 

 

 

rem ( "Random Walker Test Script" );

affect ( "walker", FLUSH )
{
	set ( "SET_WEAPON", "WP_NONE" );
	set ( "SET_PLAYER_TEAM", "TEAM_PLAYER" );
	set ( "SET_ENEMY_TEAM", "TEAM_ENEMY" );
	set ( "SET_BEHAVIOR_STATE", "BS_DEFAULT" );
	set ( "SET_CHASE_ENEMIES", "true" );
	set ( "SET_LOOK_FOR_ENEMIES", "true" );
	set ( "SET_IGNOREALERTS", "false" );
	set ( "SET_WALKING", "true" );
	set ( "SET_RUNNING", "false" );
	wait ( 4000.000 );
	loop ( -1.000 )
	{
		task ( "casualwalk" )
		{
			if ( random ( 0, 3 ) > 2 )
			{
				set ( "SET_NAVGOAL", "wpoint3" );
			}
			else ()
			{
				if ( random ( 0, 3 ) > 1 )
				{
					set ( "SET_NAVGOAL", "wpoint2" );
				}
				else ()
				{
					if ( random ( 0, 3 ) > 0 )
					{
						set ( "SET_NAVGOAL", "wpoint1" );
					}
				}
			}
		}
		do ( "casualwalk" );
		wait ( "casualwalk" );
		wait ( random ( 0, 4000 ) );
	}
}

 

 

What are the requirements for an NPC to be able to pick and follow a set of waypoints reliably? Do the waypoints need to be daisy chained ("targeted") to one another, or is it enough to define the movement behaviour in script? Do there need to be physical brushes (not just entities) for the waypoints? How does the waypointing system work (with ICARUS)?

 

Related, is there any way to increase the distance that NPCs are able to see waypoints from? The default distance seems to be rather short/limited.

 

On a side note (as trivia), who programmed ICARUS, and what language(s), if any, were used as the basis for it? :)

 

 

So I didn't write the navigation system - that was written by Chris Reed (also still at Raven).  ICARUS was written by Josh Weier (who left for Valve and who's last job I remember he had before retiring from the industry was project lead on Portal 2). I don't recall if he patterned it on anything, he just wanted it to be a high-level scripting system. Hence the name ICARUS (for the old myth of the father and son who escaped a prison tower by making wax wings). I reminded him that Icarus was the son who flew *too* high, causing his wings to melt and he plummeted to his death. I suggested DAEDALUS would be a more confidence-inspiring acronym, but he just liked the way ICARUS sounded better.   :)

 

Your script looks fine to me, for the most part. However, there are some things that could be causing the issue you're seeing:

 

One thing to note is that your "casualwalk" task is not guaranteed to make them do anything. It may pick the same goal the NPC is already at.  In that case the NPC will just stand there for the duration of the random wait time (0-4 seconds).  But, still, if everything is set up correctly, he should at least move the first time.  

 

Stopping in the middle or changing direction (to what? a different point?) could be him reacting to enemies?  Did you try setting him to ignore enemies instead of looking for and chasing enemies?  Those things would change his goal (from your navgoal to the enemy) if I recall.  However, that won't interrupt the script, so the script will wait a few seconds then make him go to a goal again.  So you'll see him start going for a goal, then diverge to go after an enemy, but then within 0-4 seconds (0 would seem like he's just aborting his original goal early and going to a different one), going back to another goal (possibly the same one, possibly not).  The way to prevent that is for your loop to not do anything if he has an enemy.  The other way is to SET_ANGERSCRIPT to a script that includes the flush() command - that will stop all other scripts.  For example, this script is run on guards on the Hoth3 level the first time they're attacked (from scripts/hoth3/1st_troopers_attacked.icarus):

//Generated by BehavEd
 
rem ( "comment" );
flush (  );
wait ( 200.000 );
set ( /*@SET_TYPES*/ "SET_BEHAVIOR_STATE", /*@BSTATE_STRINGS*/ "BS_DEFAULT" );
set ( /*@SET_TYPES*/ "SET_LOOK_FOR_ENEMIES", "true" );

 

 

It flushes whatever they were doing before, waits 200ms, then sets their behavior state back to default behavior and tells them it's okay to look for enemies now (they were having a conversation before).  That was set up as below in the script that starts their conversation (scripts/hoth3/guards_talking1.icarus):

 
set ( /*@SET_TYPES*/ "SET_PAINSCRIPT", "hoth3/1st_troopers_attacked" );
set ( /*@SET_TYPES*/ "SET_ANGERSCRIPT", "hoth3/1st_troopers_attacked" );
set ( /*@SET_TYPES*/ "SET_AWAKESCRIPT", "hoth3/1st_troopers_attacked" );
 

 

As for the pathfinding system itself, I believe it worked pretty well.  The map needs waypoints (the network of points used later for pathfinding) You lay down waypoints in your map (simple entities in Radiant), connect them by selecting the first one, then the second one and hitting K (that will automatically fill in the target field on the first one and, if need be, the targetname field on the second one).  This may seem annoying, but it doesn't take too long.  You don't need a whole lot of waypoints, just enough that you can see each area of the map from the point.  And it gives you some control over how the NPCs path through your map (go straight down the hall, or traffic stays to the right, etc.)  

 

In regards to the navgoals, you place a waypoint_navgoal in the map, making sure it's got a clear path to a normal waypoint (the nav network).  Like other waypoints, it will drop to the floor and autoconnect to the nav mesh.  However, it will not be used as a "pass-through" node for other pathing tasks - it is always a goal, and endpoint of a path. Alternatively, you can tell it to not autoconnect, but then it won't be reachable.  You will need to manually target it from your desired normal waypoint.

 

Normally, it will autoconnect navgoals and combat nodes to regular waypoints up to 500 units away and not too far above or below it - I believe 60 is the max Z difference allowed).  Autoconnections to *other* combat nodes and navgoals can only be 250 units away, max.  And, obviously, there has to be a clear path between the goals and waypoints to autoconnect them.  Note that it only has to do this the first time, then it saves those to a .nav or .navNEW file and just loads that for the next time.  If I recall, we shipped the game with those .nav files already, at least for MP.

 

Much of what I just described above is done in the function NAV::LoadFromEntitiesAndSaveToFile() in g_navigator.cpp.

 

When an NPC gets a command to go to a goal, it will calculate a path dynamically, using the waypoint connectivity network processed on map load.  I believe Chris Reed used the A* algorithm for this.  He got a degree in programming at UW and pathinding and AI are his specialties, so he does a pretty good job of it (he knows a lot more about writing fast, efficient, effective pathfinding algorithms than I do).

 

First, the pathfinding system will find the closest waypoint on the network for the desired goal.  If it can't find one, the path will fail.  See GetNearestNode().  The node must be withing 550 of the goal and no more than maybe 100 above or below (with exceptions for flying enemies maybe).

 

Assuming the pathfinding system found a closest node for the goal, then the system will continue with trying to find a path (there is a limit of 100 simultaneous pathers on PC, 60 on X-Box). I'm not aware of there being limits on how long the path can be (I imagine there are some), but I've never had any trouble getting an NPC to path all the way through a map if I recall.

 

ICARUS will wait for the NPC to reach their goal before continuing on from your SET_NAVGOAL command. If they never reach the goal, the script will not continue.

 

The only reason you would need to set multiple path nodes is if you want them to walk a patrol or stop and do something at each point or if you wanted to force them to take a certain route.

 

Hope this helps!

AnonMC, Asgarath83, Cerez and 1 other like this
Link to comment

@@MGummelt

 

Would you happen to know if the .menu files were made by hand in a text editor, or the devs used a program?

 

By hand.  Fun fact: most of the Call of Duty games still used this awful .menu system, though most recent ones have finally abandoned it (though Call of Duty Online still uses it for some things).

Smoo likes this
Link to comment

Oh, I've got one actually @@MGummelt especially since you were pretty much responsible for vehicles in MP.

 

Why is it that we see a line in the .VEH file for this?

hideRider          1

At the same time though deleting this or setting it's value to 0 doesn't seem to do anything? Is there something we are doing wrong? I'm asking because at one point I started work on an AT-RT which is a walker type that has an open mount. I couldn't get the player to be visible using the VEH_WALKER type so I was forced to switch it to the TAUNTAUN class NPC which of course didn't work right because the blasters wouldn't work properly.

 

This should behave exactly as it sounds.  If that's set to 1, the rider will not be visible or collidable.  Fighter type vehicles automatically make the player not collidable on the server when they board, but they should still be visible on the client.

 

I can't think of anything that should make Walkers different.  There's no special exceptions I can see in the code for VH_WALKER that pertains to not drawing the player.  There must be something doing it, but I don't see it.  I'd probably have to debug it and see where the client earlies-out on trying to draw the player.

 

Oh, wait. There is one quirk to AT-STs.  There's two types of AT-STs - NPCs and vehicles. I think when you "boarded" an NPC AT-ST, you actually are not boarding it like other vehicles.  You're changing your playermodel to the AT-ST (same as if you changed your playermodel to a stormtrooper or droid).  So it *is* drawing your playermodel, it's just that your playermodel has changed to be an AT-ST.  Heh.  

 

Still if this isn't an NPC AT-ST but an inert vehicle that can be boarded by the player, then I don't see why it wouldn't try to draw your playermodel assuming hideRider is not set to 1 in the .veh def...

Cerez likes this
Link to comment

The game's code refers to the Imperial Saboteurs being able to dodge blaster fire and a saboteur commando that uses dual blaster pistols. In the game he isn't any different than the regular pistol-wielding saboteur, but this can be mostly reimplemented from copying over from the cultist commando's .npc file, which, interestingly enough, is in the game's files but isn't ever seen ingame. Is the saboteur commando having only one pistol intentional or was it something someone forgot to change before the game shipped? And the Saboteur's dodging behavior doesn't seem to actually exist. Was it ever implemented?

Looks like it was implemented but commented out.  Look in AI_Jedi.cpp:

 

 

if ( Q_flrand( 0.25, 1 ) < facingAmt )
{//coming at/facing me!  
int whichDefense = 0;
/*if ( NPC->client->NPC_class == CLASS_SABOTEUR )
{
int sabDef = Q_irand( 0, 3 );
if ( sabDef )
{//25% chance of trying normal jedi defense logic
whichDefense = 100;
}
else
{
if ( sabDef == 1 )
{//25% chance of strafing
Jedi_Strafe( 300, 1000, 0, 1000, qfalse );
}
else
{//50% chance of trying to dodge/roll/jump using jedi missile evasion logic
Jedi_SaberBlock();
}
return;
}
}
else */

[\spoiler]

 

That could be easily uncommented and they would start dodging.

 

The commando has a blasterrifle if you look in saboteur.npc.  I don't recall if they were ever meant to have dual pistols or if dual pistols was ever implemented?

Asgarath83, T.Zealot and Smoo like this
Link to comment

In Jedi Academy the amount of time that the bodies of dead NPCs remain on screen can be changed with g_corpseRemovalTime command, but I was wondering if there is a similar console command or script change for the amount of time dead NPCs remain in Jedi Outcast?

No, but the relevant code could be ported from Academy to Outcast and it should work.

Cerez and Smoo like this
Link to comment

 

heh, i made a forum account here just so I could ask about persistent corpses in outcast. looks like i was beat to the punch.

buuuuut, i have been doing some digging around in the source code, and in NPC.cpp there's a whole section on corpse removal and all the requirements for a corpse to be removed, etc.

this part here piques my interest:

#define REMOVE_DISTANCE 128
#define REMOVE_DISTANCE_SQR (REMOVE_DISTANCE * REMOVE_DISTANCE)
 
if i were to change remove_distance variable from 128 to, say, 999999, would that have the desired effect? if not, what would?
i really have no idea what i'm doing, but it seems to make sense.

 

Yeah, that should make them not remove themselves until they're that far away, if I recall.  See the NPC_RemoveBody() function in NPC.cpp for the full logic.

slinky likes this
Link to comment

@MGummelt, how did you guys handle offsetting weapon projectiles from center, I.E. a right handed weapon? I've tried creating a vector offset relative to the view vector, but the offset always ends up being from the world vector. I am working to recreate the Fusion Cutter from Dark Forces (see image below). Most of my relevant experimentation with the community's help his here: https://jkhub.org/topic/7581-vexing-vectors/

 

 

CvhxSjA.jpg

[\spoiler]

I didn't work much on the non-saber weapons, but my guess would be that it was done by creating an off-center muzzle tag in the weapon's model.  In your case, you'd have 4 muzzle tags and the weapon def in weapons.dat would have 4 barrels?  I'd have to dig into the weapons system a bit more to be sure.  Do you have an example of a weapon we did that does something like you're asking?  With offset projectiles spawning?

Link to comment

The commando has a blasterrifle if you look in saboteur.npc.  I don't recall if they were ever meant to have dual pistols or if dual pistols was ever implemented?

 

Apparently dual pistols were implemented, at least technically. Quoting from this tutorial:

 

 

Class_Reborn: Allows gunners to ignore way points and use rolls and cartwheels. If you give them the blaster pistol, and also captain rank, they should have dual pistols which fire really fast. Also, you can't pull the weapons from these guys (I can't anyway with my NPCs). RANK_LT_JG and up will actively evade saber attacks.

MGummelt likes this
Link to comment
Guest Redemption

@@MGummelt - Hello and thank you very much. I don't know how there hasn't been another star wars game that has captured lightsaber combat this well :) Testament to you're work... Outcast is like 15 years old!!!

Anyway, what I'd like to ask is, what pieces of code do I have to look at to determine how blocking is done with saber to saber combat? I'd like to make it harder to hit/be hit. I have edited code that makes saber transitions block and the blocking is a lot better, but since you're here, I'd thought I'd ask :)

 

Thank you,

Kind Regards :)

Link to comment

ICARUS will wait for the NPC to reach their goal before continuing on from your SET_NAVGOAL command. If they never reach the goal, the script will not continue.

 

The only reason you would need to set multiple path nodes is if you want them to walk a patrol or stop and do something at each point or if you wanted to force them to take a certain route.

 

Hope this helps!

It certainly does! Thank you so much! I think I know what happened, now -- it's alarmingly simple:

 

My script is set to wait for the "casualwalk" task to finish. This is fine for when a character is moving to a navgoal, but what if he's already at the navgoal he's supposed to go to? That means the "casualwalk" task never returns the finished state, and my script is kept hanging in a wait. Hence why my character randomly stopped after reaching a navgoal, and didn't ever move again -- regardless of how much time passed. It was waiting to reach a navgoal it was already at, and never going to reach walking to (technically speaking).

 

The fix is to make sure that every time a different navgoal is picked by the random script, and never the same one.

Link to comment

@@MGummelt - Hello and thank you very much. I don't know how there hasn't been another star wars game that has captured lightsaber combat this well :) Testament to you're work... Outcast is like 15 years old!!!

Anyway, what I'd like to ask is, what pieces of code do I have to look at to determine how blocking is done with saber to saber combat? I'd like to make it harder to hit/be hit. I have edited code that makes saber transitions block and the blocking is a lot better, but since you're here, I'd thought I'd ask :)

 

Thank you,

Kind Regards :)

 

Good question.  If we're talking about single player Jedi Academy, it's in wp_saber.cpp. Look at the function WP_SaberDamageTrace().

 

This is sort of one of my classic "megafunctions" I used to write (and, honestly, sometimes still do).  I try to comment everything, but keep in mind I was working solo on this stuff and I never imagined the public would ever see this code.  So the comments aren't super-extensive or explanatory, they were mostly there for my own personal benefit.  Often I would write the comments in a function first, to get down the flow and logic and content of the function, then fill it in with code.  Then add more comments as I went along adding new features.

 

This function does a lot of stuff.  But the part you're interested in comes after this part:

 

 

 

if ( (saberHitFraction < 1.0f||(sabersCrossed>=0&&sabersCrossed<=32.0f)) && (ent->client->ps.weaponstate == WEAPON_FIRING || ent->client->ps.saberInFlight || G_InCinematicSaberAnim( ent ) ) )
{// The saber (in-hand) hit another saber, mano.

 
Further down, it checks to see if the saber it hit was also in someone's hand:

//Check deflections and broken parries
if ( hitOwner && hitOwner->health > 0 && ent->health > 0 //both are alive
&& !inFlightSaberBlocked && hitOwner->client && !hitOwner->client->ps.saberInFlight && !ent->client->ps.saberInFlight//both have sabers in-hand
&& ent->client->ps.saberBlocked != BLOCKED_PARRY_BROKEN 
&& ent->client->ps.saberLockTime < level.time
&& hitOwner->client->ps.saberLockTime < level.time )
{//2 in-hand sabers hit

 
Below that it does a bunch of checks to see the relative power level of the two sabers, then decides if the attack is strong enough to break through the defense or if it gets parried.
 
However, I suspect that's not what you meant, no?  I'm assuming that you actually wanted sabers to block each other more?  To actually have saber-vs-saber collision be a bit "larger"?  If that's the case, look in WP_SaberUpdate().  Here it sets the "size" of the saber entity (its mins and maxs - the minimum and maximum bounds of the axis-aligned bounding box of the lightsaber... in x, y and z coordinates... z is up in the Quake engine, unlike most other 3D coordinate systems).
 
Notice here how it checks to see what blocking type is being used (this is defined for each possible animation in the big saber animation data table, saberMoveData, in bg_animation.cpp):
 

else if ( self->client->ps.saberBlocking == BLK_TIGHT || self->client->ps.saberBlocking == BLK_WIDE )
{//FIXME: keep bbox in front of player, even when wide?
vec3_t saberOrg;
if ( ( (self->s.number&&!Jedi_SaberBusy(self)&&!g_saberRealisticCombat->integer) || (self->s.number == 0 && self->client->ps.saberBlocking == BLK_WIDE && (g_saberAutoBlocking->integer||self->client->ps.saberBlockingTime>level.time)) )
&& self->client->ps.weaponTime <= 0 
&& !G_InCinematicSaberAnim( self ) )
{//full-size blocking for non-attacking player with g_saberAutoBlocking on
vec3_t saberang={0,0,0}, fwd, sabermins={-8,-8,-8}, sabermaxs={8,8,8};

 
Below that, there's an "else" that then calculates a smaller bbox (bounding box) for the saber entity (this is what is hit by the other lightsaber's damage traces).  The size of the bbox is based on the number of blades, their length and orientation.  So a short, single-blade saber is going to have a much smaller bbox than, say, a 6-bladed saber with blades sticking out at all angles.
 

Now, something to note is that this is just used for the "rough" first check to see if 2 sabers have hit.  It's what the damage trace uses.  But that's just a big cuboid, it's not accurate at all.  Consider that check the "I could have possibly hit the other lightsaber blade because my blade intersected the cubical space that the other blade is somewhere inside of" check... :)

 

So, back in WP_SaberDamageTrace, after it does the trace, it does some fancy math to see if the two blades (just line segments really), came close enough to each other to have touched.  To figure that out, it calls a function named WP_SabersDistance() (this is a bit higher in the function that the section I quoted above:

 

 

 

{//sabers must actually collide with the attacking saber
sabersDist = WP_SabersDistance( attacker, owner );
if ( attacker && attacker->client && attacker->client->ps.saberInFlight )
{
sabersDist /= 2.0f;
if ( sabersDist <= 16.0f )
{
sabersIntersect = qtrue;
}
}
}
 
if ( sabersCrossed == -1 || sabersCrossed > sabersDist )
{
sabersCrossed = sabersDist;
}
 
float collisionDist;
if ( g_saberRealisticCombat->integer )
{
collisionDist = SABER_COLLISION_DIST;
}
else
{
collisionDist = SABER_COLLISION_DIST+6+g_spskill->integer*4;
}
 
if ( G_InCinematicSaberAnim( owner )
&& G_InCinematicSaberAnim( attacker ) )
{
sabersIntersect = qtrue;
}
 
if ( owner && owner->client && (attacker != NULL) 
&& (sabersDist > collisionDist )//|| !InFront( attacker->currentOrigin, owner->currentOrigin, owner->client->ps.viewangles, 0.35f )) 
&& !sabersIntersect )//was qtrue, but missed too much?
{//swing came from behind and/or was not stopped by a lightsaber
//re-try the trace without checking for lightsabers
gi.trace ( &tr, start, NULL, NULL, end2, ignore, mask&~CONTENTS_LIGHTSABER, G2_NOCOLLIDE, 10 );

 
So you can see, above, that the sabers aren't considered as hitting each other unless the sabersDist is less than the collisionDist.  Note that collisionDist goes up by 4 for every skill level in single player (meaning blocks are more common on higher difficulty levels).  If realistic combat is turned on, the collisionDist uses the default low value of SABER_COLLISION_DIST, which is the bare minimum distance 2 sabers can be from each other and look like they are barely touching.
 
That default value is defined right above the WP_SaberDamageTrace() function:
 

#define SABER_COLLISION_DIST 6

 
So on, say, medium difficulty, that distance will be 6 + 6 + 4, or 16.  That's pretty generous.
 
If you want to make sabers hit each other more, just raise that number.
 
Hopefully that helps.  
 
BTW, I wish I could get this board to keep the full formatting of the text I'm pasting in (color, tabbing, etc.)  The code snippets would be a bit more readable.  Anyone have any tips for that?
Boothand and Cerez like this
Link to comment

 

BTW, I wish I could get this board to keep the full formatting of the text I'm pasting in (color, tabbing, etc.)  The code snippets would be a bit more readable.  Anyone have any tips for that?

 

 

Hmm, you could try the 'code' button in the full editor. Might not be a huge improvement though.

//sabers must actually collide with the attacking saber

sabersDist = WP_SabersDistance( attacker, owner );
if ( attacker && attacker->client && attacker->client->ps.saberInFlight )
{
    sabersDist /= 2.0f;

    if ( sabersDist <= 16.0f )
    {
        sabersIntersect = qtrue;
    }
}
Link to comment

It certainly does! Thank you so much! I think I know what happened, now -- it's alarmingly simple:

 

My script is set to wait for the "casualwalk" task to finish. This is fine for when a character is moving to a navgoal, but what if he's already at the navgoal he's supposed to go to? That means the "casualwalk" task never returns the finished state, and my script is kept hanging in a wait. Hence why my character randomly stopped after reaching a navgoal, and didn't ever move again -- regardless of how much time passed. It was waiting to reach a navgoal it was already at, and never going to reach walking to (technically speaking).

 

The fix is to make sure that every time a different navgoal is picked by the random script, and never the same one.

Hmm, maybe.  But I would expect it to just complete immediately.  Unless maybe it fails to find a path because he's standing on it already?  I'm not sure, but I think the system is smart enough to say "oh, I'm already there, complete the task right away".  And that doesn't sound like it would cause the problems you were seeing where they would stop or change directions en route to another navgoal?  Maybe, but I'm a bit skeptical.  

 

You could rewrite your script to follow the navgoals in a more linear fashion (always 1-2-3 order in a loop) and see if it works more reliably?

 

My guess is still that something else is changing their goal (did you turn on the debug cvars that show what their current goal is?

 

Try this on the console:

 

\nav show nodes

\nav show navgoals

\nav show enemypath (I believe this will just show the path to your current goal, not just enemies)

 

That last one, I think, changes color depending on what's going on (can move forward, is blocked, etc).  Try it and see what it shows you.

Archangel35757, Cerez and AnonMC like this
Link to comment

The game's code refers to the Imperial Saboteurs being able to dodge blaster fire and a saboteur commando that uses dual blaster pistols. In the game he isn't any different than the regular pistol-wielding saboteur, but this can be mostly reimplemented from copying over from the cultist commando's .npc file, which, interestingly enough, is in the game's files but isn't ever seen ingame. Is the saboteur commando having only one pistol intentional or was it something someone forgot to change before the game shipped? And the Saboteur's dodging behavior doesn't seem to actually exist. Was it ever implemented?

 

There is a saboteur commando NPC into t1_fatal mission, when jaden look into the camera when imperial place the bombs in the core of volcanic factory.  but is just for cinematic. and on level not appear, if you edit the cinematic script for avoid his removing, it fight like a normal saboteur... i suppose is a cutted boss maybe , that should have the dual blaster pistols. D:

MGummelt likes this
Link to comment

Hey MGummelt just a short question, I'm no coder but I was wondering if it's possible to deactivate dismemberment on an specific model (I'm talking about MP only) I know that cg_dismember activates/deactivates it but that's for every single model. Can that be fixed with an specific command or will it need an individual script or something?

Link to comment
Guest Redemption

@@MGummelt - Its very good to know that, I was in the right place after all. Most of that was familiar and where I made some edits, like say at the bounding box part I had shortened it to -4-4-4 4 4 4. To hear you explain it really helps though. I put on Jedi Academy last night and to say it like I see it, the combat is perfect as it is without code edits. I play outcast mainly due to some of the movement animation changes in Academy, I don't like the movement, dunno why they had to change the style. Went from Matrix like realism to more Anime like style.

One last thing. In Academy and Outcast for the matter, when I lowered saberdefense I got better looking lightsaber battles due to not shunting away the enemy saber. Could you tell me where about in the code this bit of code is? I'd like to have a look.

 

Thank you for you're comment, its very much appreciated.

All the best to you

MGummelt likes this
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...