Jump to content

Home

Tutorial: Altering force heal to mimic its SP counterpart


Primesghost

Recommended Posts

Modifying Force Heal in Jedi Knight 2: Jedi Outcast

 

I am currently working on a single player modification of Jedi Knight 2: Jedi Outcast (JK2). This modification requires that I take the multiplayer source code and rewrite it so that the force powers and other aspects very closely mimic their single player counterparts. After spending some time reviewing the source code I decided to begin my modifications with the force powers, in particular the force power heal. I noticed a lack of articles dealing with the force power source code in JK2 in the modifications programming community so I decided to write my own. This tutorial will assume that you have a current copy of the JK2 source code (JK2 SDK 2.0 as of this writing), the most recent JK2 update (patch 1.04 as of this writing), and working batch files (no the batch files that come with the SDK don’t work properly) in order to compile your source code into bytecode. Furthermore, this tutorial will assume that you know how to compile your source code into bytecode, and that you possess a working knowledge of the C programming language and standardized programming fundamentals. I’ll be showing you how to manipulate the heal power to make it very closely approximate its single player counterpart (no it’s not going to be a perfect match, you’ll have to work on it a bit but after this tutorial you should have a pretty good idea of how to do that). Now, lets get our hands dirty!

 

Files to be modified:

  1. [*]bg_pmove.c[*]bg_saber.c[*]w_force.c[/list=1]

 

First we will alter the code in bg_pmove.c in the forcePowerNeeded array at line 43. The original code is:

 

------------------------------------------------------------------------------



int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] =
{
{ //nothing should be usable at rank 0..
999,//FP_HEAL,//instant
999,//FP_LEVITATION,//hold/duration
999,//FP_SPEED,//duration
999,//FP_PUSH,//hold/duration
999,//FP_PULL,//hold/duration
999,//FP_TELEPATHY,//instant
999,//FP_GRIP,//hold/duration
999,//FP_LIGHTNING,//hold/duration
999,//FP_RAGE,//duration
999,//FP_PROTECT,//duration
999,//FP_ABSORB,//duration
999,//FP_TEAM_HEAL,//instant
999,//FP_TEAM_FORCE,//instant
999,//FP_DRAIN,//hold/duration
999,//FP_SEE,//duration
999,//FP_SABERATTACK,
999,//FP_SABERDEFEND,
999//FP_SABERTHROW,
//NUM_FORCE_POWERS
},
{
65,//FP_HEAL,//instant //was 25, but that was way too little
10,//FP_LEVITATION,//hold/duration
50,//FP_SPEED,//duration
20,//FP_PUSH,//hold/duration
20,//FP_PULL,//hold/duration
20,//FP_TELEPATHY,//instant
30,//FP_GRIP,//hold/duration
1,//FP_LIGHTNING,//hold/duration
50,//FP_RAGE,//duration
50,//FP_PROTECT,//duration
50,//FP_ABSORB,//duration
50,//FP_TEAM_HEAL,//instant
50,//FP_TEAM_FORCE,//instant
20,//FP_DRAIN,//hold/duration
20,//FP_SEE,//duration
0,//FP_SABERATTACK,
2,//FP_SABERDEFEND,
20//FP_SABERTHROW,
//NUM_FORCE_POWERS
},
{
60,//FP_HEAL,//instant
10,//FP_LEVITATION,//hold/duration
50,//FP_SPEED,//duration
20,//FP_PUSH,//hold/duration
20,//FP_PULL,//hold/duration
20,//FP_TELEPATHY,//instant
30,//FP_GRIP,//hold/duration
1,//FP_LIGHTNING,//hold/duration
50,//FP_RAGE,//duration
25,//FP_PROTECT,//duration
25,//FP_ABSORB,//duration
33,//FP_TEAM_HEAL,//instant
33,//FP_TEAM_FORCE,//instant
20,//FP_DRAIN,//hold/duration
20,//FP_SEE,//duration
0,//FP_SABERATTACK,
1,//FP_SABERDEFEND,
20//FP_SABERTHROW,
//NUM_FORCE_POWERS
},
{
50,//FP_HEAL,//instant //You get 5 points of health.. for 50 force points!
10,//FP_LEVITATION,//hold/duration
50,//FP_SPEED,//duration
20,//FP_PUSH,//hold/duration
20,//FP_PULL,//hold/duration
20,//FP_TELEPATHY,//instant
60,//FP_GRIP,//hold/duration
1,//FP_LIGHTNING,//hold/duration
50,//FP_RAGE,//duration
10,//FP_PROTECT,//duration
10,//FP_ABSORB,//duration
25,//FP_TEAM_HEAL,//instant
25,//FP_TEAM_FORCE,//instant
20,//FP_DRAIN,//hold/duration
20,//FP_SEE,//duration
0,//FP_SABERATTACK,
0,//FP_SABERDEFEND,
20//FP_SABERTHROW,
//NUM_FORCE_POWERS
}
};

 

Alter just three lines of the code. I’ll try to mark all my edits with the comments “Begin edit” and “End edit”:

 



999,//FP_SABERATTACK,
999,//FP_SABERDEFEND,
999//FP_SABERTHROW,
//NUM_FORCE_POWERS
},
{[color=red]
// Begin edit
16,//FP_HEAL,//instant //was 25, but that was way too little
// End edit[/color]
10,//FP_LEVITATION,//hold/duration
50,//FP_SPEED,//duration

[b]CODE SNIPPED[/b]

0,//FP_SABERATTACK,
2,//FP_SABERDEFEND,
20//FP_SABERTHROW,
//NUM_FORCE_POWERS
},
{[color=red]
// Begin edit
16,//FP_HEAL,//instant
// End edit[/color]
10,//FP_LEVITATION,//hold/duration
50,//FP_SPEED,//duration

[b]CODE SNIPPED[/b]

0,//FP_SABERATTACK,
1,//FP_SABERDEFEND,
20//FP_SABERTHROW,
//NUM_FORCE_POWERS
},
{[color=red]
// Begin edit
16,//FP_HEAL,//instant //You get 5 points of health.. for 50 force points!
// End edit[/color]
10,//FP_LEVITATION,//hold/duration
50,//FP_SPEED,//duration

[b]CODE SNIPPED[/b]

 

This bit of code initializes each force power’s availability within the game and how much force power is required to use each one. In the multiplayer game force power is instantly subtracted from the player’s force pool when heal is invoked and an incredible amount of power is needed in order to use it. Here we’ve basically set it so that players just need 16 points of force saved in their force pool before they can activate force heal. That’s all in bg_pmove.c, save the file.

 

Now lets modify the bg_saber.c file. We will be modifying the BG_ForcePowerDrain method located at line 22. The original code is:

 



void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overrideAmt )
{
//take away the power
int drain = overrideAmt;

/*
if (ps->powerups[PW_FORCE_BOON])
{
return;
}
*/
//No longer grant infinite force with boon.

if ( !drain )
{
drain = forcePowerNeeded[ps->fd.forcePowerLevel[forcePower]][forcePower];
}
if ( !drain )
{
return;
}

[b]CODE SNIPPED[/b]

 

Ok, we’re going to alter just a little bit:

 



if (ps->powerups[PW_FORCE_BOON])
{
return;
}
*/
//No longer grant infinite force with boon.
[color=red]
// Begin edit
if (forcePower = = FP_HEAL){
// Force power drain for heal will be handled in WP_ForcePowerRun
// It will constantly drain as it heals so get out of the method
return;
}
// End edit[/color]

if ( !drain )
{
drain = forcePowerNeeded[ps->fd.forcePowerLevel[forcePower]][forcePower];
}

[b]CODE SNIPPED[/b]

 

NOTE: For the purposes of formatting this document properly I was forced to add a space between the two equal signs in the line “if (forcePower = = FP_HEAL){“. Make sure to remove this space if you copy and paste this code or you’ll get an error.

 

Whenever a force power is activated, a call is made to this method to determine how much to deduct from the player’s force pool and then deduct that amount. As you can see from my comments, we will be writing the code for the force pool deduction somewhere else so we need to make sure that IF any calls are made to this method when you activate force heal, no force will be deducted by this method. Ok, that’s it for bg_saber.c, save the file and open up w_force.c.

 

Ok, now we’re going to edit the methods that actually control how force heal behaves. I won’t be able to just go top down and list the edits because they won’t make sense unless I explain it in the order in which they’re called.

 

Lets look at the ForceHeal method first on line 945. The original code is:

 



void ForceHeal( gentity_t *self )
{
if ( self->health <= 0 )
{
return;
}

if ( !WP_ForcePowerUsable( self, FP_HEAL ) )
{
return;
}

if ( self->health >= self->client->ps.stats[sTAT_MAX_HEALTH])
{
return;
}

if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3)
{
self->health += 25; //This was 50, but that angered the Balance God.

if (self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
}
BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
}
else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2)
{
self->health += 10;

if (self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
}
BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
}
else
{
self->health += 5;

if (self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
}
BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
}
/*
else
{
WP_ForcePowerStart( self, FP_HEAL, 0 );
}
*/
//NOTE: Decided to make all levels instant.

G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal.wav") );
}

 

Edit the code like so:

 



if ( self->health >= self->client->ps.stats[sTAT_MAX_HEALTH])
{
return;
}
[color=red]
// Begin edit
WP_ForcePowerStart( self, FP_HEAL, 0 );
[/color]
[color=lightgreen]
/*
if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3)
{
self->health += 25; //This was 50, but that angered the Balance God.

if (self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
}
BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
}
else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2)
{
self->health += 10;

if (self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
}
BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
}
else
{
self->health += 5;

if (self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
}
BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
}
*/[/color][color=red]
// End edit[/color]
/*
else
{
WP_ForcePowerStart( self, FP_HEAL, 0 );
}
*/
//NOTE: Decided to make all levels instant.

[b]CODE SNIPPED[/b]

 

Notice that I’ve commented out just about every part of this method and made a simple call to the WP_ForcePowerStart method. This is because we will be handling the increments to the players health and decrements to force in another method.

 

Lets move on to WP_ForcePowerStart on line 738 and see where the magic begins. Here’s the original source code:

 



void WP_ForcePowerStart( gentity_t *self, forcePowers_t forcePower, int overrideAmt )
{ //activate the given force power
int duration = 0;
qboolean hearable = qfalse;
float hearDist = 0;

if (!WP_ForcePowerAvailable( self, forcePower ))
{
return;
}

//hearable and hearDist are merely for the benefit of bots, and not related to if a sound is actually played.
//If duration is set, the force power will assume to be timer-based.
switch( (int)forcePower )
{
case FP_HEAL:
hearable = qtrue;
hearDist = 256;
self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
break;
case FP_LEVITATION:
hearable = qtrue;
hearDist = 256;
self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
break;

[b]CODE SNIPPED (the rest of this switch statement is irrelevant to our purpose)[/b]

default:
break;
}

if ( duration )
{
self->client->ps.fd.forcePowerDuration[forcePower] = level.time + duration;
}
else
{
self->client->ps.fd.forcePowerDuration[forcePower] = 0;
}

if (hearable)
{
self->client->ps.otherSoundLen = hearDist;
self->client->ps.otherSoundTime = level.time + 100;
}

self->client->ps.fd.forcePowerDebounce[forcePower] = 0;

if ((int)forcePower == FP_SPEED && overrideAmt)
{
BG_ForcePowerDrain( &self->client->ps, forcePower, overrideAmt*0.025 );
}
else if ((int)forcePower != FP_GRIP && (int)forcePower != FP_DRAIN)
{ //grip and drain drain as damage is done
BG_ForcePowerDrain( &self->client->ps, forcePower, overrideAmt );
}
}

 

Edit the code like this:

 



case FP_HEAL:
hearable = qtrue;
hearDist = 256;[color=red]
// Begin edit
duration = 7500
// End edit[/color]
self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
break;

 

We’re going to give heal a duration so that a check on it is made at every frame refresh. Every time the game refreshes it checks to see if any powers are active, then to see if those powers have a duration. If they have a duration set, the game makes a call to WP_ForcePowerRun to see what needs to be done. Notice that in the last few lines of code a call to BG_ForcePowerDrain is made, it’s a good thing we put that block in there to catch errant calls for force heal. I just caught that one as I was writing this, you can prevent that call with a simple “if” statement to check if the call would be sent for FP_HEAL.

 

Ok, let’s go on to WP_ForcePowerRun on line 3625 (this number will be a little higher because of our edits above). The original code looks like:

 



static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd_t *cmd )
{
extern usercmd_t ucmd;

switch( (int)forcePower )
{
case FP_HEAL:
if (self->client->ps.fd.forcePowerLevel[FP_HEAL] = = FORCE_LEVEL_1)
{
if (self->client->ps.velocity[0] || self->client->ps.velocity[1] || self->client->ps.velocity[2])
{
WP_ForcePowerStop( self, forcePower );
break;
}
}

if (self->health < 1 || self->client->ps.stats[sTAT_HEALTH] < 1)
{
WP_ForcePowerStop( self, forcePower );
break;
}

if (self->client->ps.fd.forceHealTime > level.time)
{
break;
}
if ( self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{ //rww - we might start out over max_health and we don't want force heal taking us down to 100 or whatever max_health is
WP_ForcePowerStop( self, forcePower );
break;
}
self->client->ps.fd.forceHealTime = level.time + 1000;
self->health++;
self->client->ps.fd.forceHealAmount++;

if ( self->health > self->client->ps.stats[sTAT_MAX_HEALTH]) // Past max health
{
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];
WP_ForcePowerStop( self, forcePower );
}

if ( (self->client->ps.fd.forcePowerLevel[FP_HEAL] = = FORCE_LEVEL_1 && self->client->ps.fd.forceHealAmount >= 25) ||
(self->client->ps.fd.forcePowerLevel[FP_HEAL] = = FORCE_LEVEL_2 && self->client->ps.fd.forceHealAmount >= 33))
{
WP_ForcePowerStop( self, forcePower );
}
break;
case FP_SPEED:
//This is handled in PM_WalkMove and PM_StepSlideMove
break;

[b]CODE SNIPPED (again the rest of the switch is irrelevant)[/b]

 

Edit like so:

 



case FP_HEAL:
// If you have level 1 heal
if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_1)
{[color=red]
// Begin edit
if (self->client->ps.velocity[0] ||
self->client->ps.velocity[1] ||
self->client->ps.velocity[2] ||
cmd->buttons & BUTTON_ATTACK ||
cmd->buttons & BUTTON_USE ||
cmd->buttons & BUTTON_ALT_ATTACK ||
cmd->buttons & BUTTON_FORCEGRIP ||
cmd->buttons & BUTTON_FORCE_LIGHTNING ||
cmd->buttons & BUTTON_FORCE_DRAIN ||
cmd->buttons & BUTTON_USE_HOLDABLE)
{
self->client->ps.fd.forcePowerDuration[FP_HEAL] = level.time;[/color]
// Stop the force power
WP_ForcePowerStop( self, forcePower );
break;
}
}
[color=red]
// Looks like if you're dead[/color]
if (self->health < 1 || self->client->ps.stats[sTAT_HEALTH] < 1)
{
// Stop the force power
WP_ForcePowerStop( self, forcePower );
break;
}

// If force heal time is greater than level time
if (self->client->ps.fd.forceHealTime > level.time)
{[color=red]
// This is how we control how fast you regenerate[/color]
// Break out of the switch
break;
}
[color=red]
// If you're over max health[/color]
if ( self->health > self->client->ps.stats[sTAT_MAX_HEALTH])
{ //rww - we might start out over max_health and we don't want force heal taking us down to 100 or whatever max_health is[color=red]
self->client->ps.fd.forcePowerDuration[FP_HEAL] = level.time;[/color]
WP_ForcePowerStop( self, forcePower );
break;
}
[color=red]
if (self->client->ps.fd.forcePowerLevel[FP_HEAL] = = FORCE_LEVEL_1 ||
self->client->ps.fd.forcePowerLevel[FP_HEAL] = = FORCE_LEVEL_2){
self->client->ps.fd.forceHealTime = level.time + 300;
}else{
self->client->ps.fd.forceHealTime = level.time;
}
[/color]
self->health++;
self->client->ps.fd.forceHealAmount++;
[color=red]
if (self->client->ps.fd.forcePower <= 3){
self->client->ps.fd.forcePowerDuration[FP_HEAL] = level.time;

if (self->client->ps.fd.forcePower <= 0){
self->client->ps.fd.forcePower = 0;
}
WP_ForcePowerStop(self, forcePower);
}else{
self->client->ps.fd.forcePower -= 4;
}

// If you go over max health[/color]
if ( self->health > self->client->ps.stats[sTAT_MAX_HEALTH]) // Past max health
{[color=red]
// set health to max and stop the healing[/color]
self->health = self->client->ps.stats[sTAT_MAX_HEALTH];[color=red]
self->client->ps.fd.forcePowerDuration[FP_HEAL] = level.time;[/color]
WP_ForcePowerStop( self, forcePower );
}
[color=red]
if (self->client->ps.fd.forceHealAmount >= 25){
self->client->ps.fd.forcePowerDuration[FP_HEAL] = level.time;
WP_ForcePowerStop( self, forcePower );
}
// End edit[/color]
break;
case FP_SPEED:
//This is handled in PM_WalkMove and PM_StepSlideMove
break;

 

Here’s where most of the magic takes place. First off it’s checking to see if the player is at level 1 heal, if so then we want to stop the healing if they move or attack or do anything other than look around. Notice how anytime we stop the power, we first set the power’s duration to level.time, this makes sure that on the next frame refresh it doesn’t do anything (this is not really necessary, just tying up any loose ends). Next we check to see if the player is at level 1 or 2 heal, if so we want them to heal at a slower speed so we set the heal time to 300 milliseconds (this equates to 25 health in 7.5 seconds at full force power which is very close to the single player game). If the player is at level 3 heal we want to let them heal at every frame refresh so we set heal time to level.time. This is handled a little higher in the “if” statement checking the heal time. Now we have to implement a little error handling to make sure we don’t go into negative force power. First we check to see if we’re at three or lower in the force pool, if so then stop the healing and make sure that if it’s below zero we reset it to zero (technically it should never be able to get below zero but, again, good programming practice). If we get past that first force pool check then we must have at least enough left to give us one more shot of health so go ahead and deduct 4 point from force (actual calculation: 100 force max / 25 max healing = 4 force points per health point returned). Finally we make sure that the player only gets 25 points of health so we check to see if they have been given 25 health, if so then reset duration and stop healing.

 

At this point you force heal will react in multiplayer exactly as it does in single player, but in single player mode when you heal yourself it plays an “ahhhhhh” sound when the power stops. Lets go ahead and include that part just for kicks.

 

Go to the WP_ForcePowerStop method at line 3173 (again this will be slightly off because of our edits). The original looks like:

 



void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower )
{
int wasActive = self->client->ps.fd.forcePowersActive;

self->client->ps.fd.forcePowersActive &= ~( 1 << forcePower );

switch( (int)forcePower )
{
case FP_HEAL:
self->client->ps.fd.forceHealAmount = 0;
self->client->ps.fd.forceHealTime = 0;
break;
case FP_LEVITATION:
break;
case FP_SPEED:
if (wasActive & (1 << FP_SPEED))
{
G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_2-50], CHAN_VOICE);
}
break;

[b]CODE SNIPPED (irrelevant beyond this point)[/b]

 

Make the following edits:

 



switch( (int)forcePower )
{
case FP_HEAL:[color=red]
// Begin edit
if (self->health >= self->client->ps.stats[sTAT_MAX_HEALTH] &&
self->client->ps.fd.forceHealAmount > 0){
G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal1.wav") );
}else{
if (self->health < self->client->ps.stats[sTAT_MAX_HEALTH] &&
self->client->ps.fd.forceHealAmount > 0 &&
self->health > 0){
G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal4.wav") );
}
}
// End edit[/color]
self->client->ps.fd.forceHealAmount = 0;
self->client->ps.fd.forceHealTime = 0;
break;

 

Ok, here we’re just saying if you’re ending force heal and you’re at max health and you were actually healed some then play a louder, longer “ahhhhhhh” sound (the sounds can be found inside the assets0.pk3 file). Otherwise if you’re ending force heal and you’re below max health and you were actually healed some and, well, you’re not dead, then play a softer, shorter “ahhhhhh” sound.

 

That’s about it, compile your jk2mpgame.qvm and load it up. Force heal should now behave very similarly to its single player counterpart. I hope this has been of help to other prospective mod makers in the community, especially ones trying to mimic the single player game. By the way, if you were paying close attention, you also learned how to play sounds in your mod at certain events.

 

Happy Coding,

Prime

Link to comment
Share on other sites

Still working on that part, I have figured out how to get kyle to go into the little meditating crouch at level 1 heal but unfortunately he stands right back up after finishing the animaiton. I'm on a friends PC right now so I don't have my code in front of me, I'll post it later. I can't remember which header file they're listed in but all the animations for SP are defined in the source. To find do a "find in files" for BOTH_DEATH and you should be able to find em. To use em you call the PM_Anim() method and pass which part of the player model to animate (torso, legs, both), the animation to perform, and a couple other arguments that I can't recall offhand. Do a search for PM_Anim and you should be able to pick it apart.

Link to comment
Share on other sites

Use the forcehandeextend and forcehandextendtime in the playerstate

I use it and it works nice.

 

just add the needed HANDEXTEN_HEALSTART and STOP and the QUiCKHEAL for level > 1

 

than search the part in the Update function of the force where the forcehandextendtime is checked to start the STOP anim after the Start anim for LEVEL = 1

Link to comment
Share on other sites

Ok so something like:

 

(pseudocode)

When starting FP_HEAL;

ps->pm->forceHandExtendTime = (however long the healing will take at full force) (approx level.time + 7500 msec);

ps->pm->forceHandExtend = HANDEXTEND_HEALSTART;

PM_Anim(proper args to start meditation animation for level 1 heal);

 

When handextendtime is checked:

 

if (ps->pm->forceHandExtendTime >= (level.time - (7500 - (time for animation to finish)) && ps->pm->forceHandExtendTime >= level.time && (pm->ps->fd.forcePowerActivated & (1 << FP_HEAL))){

(freeze it at the last frame of the animation);

}else{

if (ps->pm->handExtendTime >= (level.time - 100) && pm->ps->fd.forcePowerActivated & (1 << FP_HEAL){

(play the stand up animation);

}

 

That's all off the top of my head so forgive any errors. Think you could tell me the name of the methods that control pausing animations?

Link to comment
Share on other sites

there is a function that controlls the HANDEXTEND ANIMS.

I'll have a look for you.

 

You set handextend time to level.time + TIME A HEALING STEP TAKES

 

and you check it like the others

 

if(handextendtime < level.time)

 

ill give you the functionnames and code schnipsel:

 

 

bg_pmove.c

static void PM_Weapon( void )
{
...
else if (pm->ps->forceHandExtend != HANDEXTEND_NONE)
{ //nothing else should be allowed to happen during this time, including weapon fire
	int desiredAnim = 0;
	qboolean seperateOnTorso = qfalse;
	int desiredOnTorso = 0;

	switch(pm->ps->forceHandExtend)
	{
	case HANDEXTEND_FORCEPUSH:
		desiredAnim = BOTH_FORCEPUSH;
		break;
...

 

 

w_force.c

void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd )
{
...
else if (self->client->ps.forceHandExtend != HANDEXTEND_NONE &&
	self->client->ps.forceHandExtendTime < level.time)
{
	if (self->client->ps.forceHandExtend == HANDEXTEND_KNOCKDOWN &&
		!self->client->ps.forceDodgeAnim)
	{
		if (self->health < 1 || (self->client->ps.eFlags & EF_DEAD))
		{
			self->client->ps.forceHandExtend = HANDEXTEND_NONE;
		}
		else
		{
			if (self->client->pers.cmd.upmove &&
				self->client->ps.fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1)
			{ //force getup
				G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP);
				self->client->ps.forceDodgeAnim = 2;
				self->client->ps.forceHandExtendTime = level.time + 500;

				self->client->ps.velocity[2] = 400;
			}
			else if (self->client->ps.quickerGetup)
			{
				self->client->ps.quickerGetup = qfalse;
				G_EntitySound( self, CHAN_VOICE, G_SoundIndex("*jump1.wav") );
				self->client->ps.forceDodgeAnim = 3;
				self->client->ps.forceHandExtendTime = level.time + 500;
				self->client->ps.velocity[2] = 300;
			}
			else
			{
				self->client->ps.forceDodgeAnim = 1;
				self->client->ps.forceHandExtendTime = level.time + 1000;
			}
		}
	}
// added by Jaii der Herr =>
	else if (self->client->ps.forceHandExtend == HANDEXTEND_HEALSTART )
	{
		self->client->ps.forceHandExtend = HANDEXTEND_HEALSTOP;
		self->client->ps.forceHandExtendTime = level.time + 260;
	}

Link to comment
Share on other sites

WTF????

 

It says I can't reference level.time in bg_pmove.c

 

Says undeclared identifier 'level'

 

Then it says "left operand of . has incompatible type 'int'"

 

Maybe I'm just missing something, here's my code in bg_pmove.c:

 

if (pm->ps->forceHandExtend == HANDEXTEND_NONE &&
pm->ps->fd.forcePowersActive & (1 << FP_HEAL)){
if (pm->ps->fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_1){
	if (pm->ps->forceHandExtendTime > level.time){
		if (pm->ps->weapon == WP_SABER && (!pm->ps->saberHolstered)){
			pm->ps->saberHolstered = qtrue;
		}
		PM_SetAnim(SETANIM_BOTH, BOTH_FORCEHEAL_START, SETANIM_FLAG_HOLD, 0);
		pm->ps->forceHandExtendTime = level.time;
	}
}
}

 

It's probably just something really dumb that I'm overlooking.

Link to comment
Share on other sites

I'm not sure what you mean by "not using the existing code". There isn't any HANDEXTEND for healing unless I add one. I am using the HANDEXTEND_NONE for a reason though. It's the only one you can use without getting a wierd hand gesture before the other anims start. When you use any of the other hand extend vars the player does the force hand anim then goes into the other anims. I guess I'm just a perfectionist, if it's not exact, then I don't think it's right.

Link to comment
Share on other sites

Ohh ok, that earilier post was of the code I was sorta beta. The finalized version is a little longer :). You're right, a lot of that code is redundant but I learned a valuable lesson in school about validity checks and I've been kinda anal about it ever since. My final version of the code is in the switch statement, I added a case HANDEXTEND_NONE:

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...