Jump to content

Ask me anything about the Jedi source code


Recommended Posts

I do two edit one in BS_Fighter_Default

void NPC_BSFighter_Default( void )
{
    NPC->client->forced_forwardmove = 127;

and the other on bg_pmove.cpp on void pmove, near to end of file.

i added the last condition

}

    if ( pm->ps->pm_flags & PMF_SLOW_MO_FALL )
    {//half grav
        pm->ps->gravity *= 2;
    }

    // FIX FOR NPC MOVE FORWARD
    if ( pm->gent && pm->gent->NPC && pm->gent->NPC->force_forwardmove != 0)
    {// Boost up forward! EVER!
        pm->cmd.forwardmove = pm->gent->NPC->force_forwardmove;
    }
}

when i build i get a build error because forceforwardmove is not a member of gNPC_t (on b_public.h)

Okay i am adding on gNPC_t . but is forced_forwardmove not forceforward. now i understand the code errors.

stilling building Dll. :)

 

You're setting it on the NPC's client struct and checking it on the NPC's NPC struct.  That won't work, obviously.  Either set and check it on the client struct or set and check it on the NPC struct.  If you want to use the NPC struct, you need to add that variable to the gNPC_t struct in b_public.h.

Link to comment

@@MGummelt

Hello pal! Good to hear/read of you once again ☺

 

I really hope you can help me out a little, or if any at all would be nice.

 

In g.client at the bottom in clientspawn, I've edited the on loading of a map different models for Kyle, but the problem occurs when I save a game and on loading of that save, the ghoul2 model's animations are locked is the best way I can describe it; he fires always in the same direction and float across the screen with the navigation all wrong. I've had it working with changing loadtransition ==qtrue, but I start back at the map beginning and looking up.

 

How can I leave loadtransition==qfalse but unlock my models animation?

In g.main right at the very bottom, there is a bit of code tbat calls playerlocked.. Does that have anything to do with it?

 

Kind Regards

 

Can you show me what the edit you made was?  My guess is you changed one place that gets/sets the player model but another place is setting/getting a different value.

Link to comment
Guest Redemption

Can you show me what the edit you made was?  My guess is you changed one place that gets/sets the player model but another place is setting/getting a different value.

Hi Mike!

 

My internet is down at the moment and I'm using the data roaming on my mobile, so I cannot get into this right now. From what I can tell you is in g_client at the bottom in clientspawn, where the model is loaded on map starting, I've created it for each level a different model is used. I was looking in g_savegame and realised.. OpenJK changed the save code so that it would be compatable cross-platformed so, I may have to discuss this with them.

 

I think your right in what your saying about 'gets set and is reading something different elsewhere..' You see the code uses npc type for the player in the scripted levels(I can save/load no problem on the 'Pit' map), I think what is happening is that its calling for the npc model and its conflicting with the different model I had saved with... Maybe, maybe not but thats the best I've got so far pal.

Link to comment

You're setting it on the NPC's client struct and checking it on the NPC's NPC struct.  That won't work, obviously.  Either set and check it on the client struct or set and check it on the NPC struct.  If you want to use the NPC struct, you need to add that variable to the gNPC_t struct in b_public.h.

That's explain a very lot of things. infact after build nothing is changed to my fighter (but they are NOT vehicle, myster they are really NPC... basically they are like droids... but i want they move and fight like a vehicle. something like that. i do that with NPC code instead of vehicle because NPC is more simply to use, not need a driver and have more weapons and weapons can be easy switchable (i want my fighters using seekers if enemy is far and blaster if near, and bomb and chaff and flare and other original weapons too, is for a science fiction mod not only star wars ) basically i want to recreate this movement:

https://www.youtube.com/watch?v=CDntDe7eazAleaving out 

leaving force forward move, and using a vector movement imbued into NPC AI client code that force NPC to move a walkspeed into his idle \ patrol state and runspeed at his attack \ flee \ hunt \ strafe  behavour state, there is some other way to do that with a simple vector move along Y axis? i am not familiar with vector so i need an example of a little function that force an entity to move forward along a vector direction. there is into the code the command about SET_MOVEMENT X \ Y \ Z of something like that and it work on every entity, npc included, but i tryed and it move with absolutely direction, not with a vector related to X Y Z left \ right

forward \ backward  and up \ down of NPC. i need just to push a fighter along Y axis with + values, but NOT with absolutely map Y vector, but with Y axis vector relative to entity.

 

mmm strange, video link not work :( try to dive into google with search about "rogue squadron 3d escape on fest gold medal" and you see what i want to recreate.

Link to comment

Hi Mike!

 

My internet is down at the moment and I'm using the data roaming on my mobile, so I cannot get into this right now. From what I can tell you is in g_client at the bottom in clientspawn, where the model is loaded on map starting, I've created it for each level a different model is used. I was looking in g_savegame and realised.. OpenJK changed the save code so that it would be compatable cross-platformed so, I may have to discuss this with them.

 

I think your right in what your saying about 'gets set and is reading something different elsewhere..' You see the code uses npc type for the player in the scripted levels(I can save/load no problem on the 'Pit' map), I think what is happening is that its calling for the npc model and its conflicting with the different model I had saved with... Maybe, maybe not but thats the best I've got so far pal.

 

Yeah, I can't offer advice on modded codebases like OpenJK, I've not looked at them.

Link to comment

That's explain a very lot of things. infact after build nothing is changed to my fighter (but they are NOT vehicle, myster they are really NPC... basically they are like droids... but i want they move and fight like a vehicle. something like that. i do that with NPC code instead of vehicle because NPC is more simply to use, not need a driver and have more weapons and weapons can be easy switchable (i want my fighters using seekers if enemy is far and blaster if near, and bomb and chaff and flare and other original weapons too, is for a science fiction mod not only star wars ) basically i want to recreate this movement:

https://www.youtube.com/watch?v=CDntDe7eazAleaving out 

leaving force forward move, and using a vector movement imbued into NPC AI client code that force NPC to move a walkspeed into his idle \ patrol state and runspeed at his attack \ flee \ hunt \ strafe  behavour state, there is some other way to do that with a simple vector move along Y axis? i am not familiar with vector so i need an example of a little function that force an entity to move forward along a vector direction. there is into the code the command about SET_MOVEMENT X \ Y \ Z of something like that and it work on every entity, npc included, but i tryed and it move with absolutely direction, not with a vector related to X Y Z left \ right

forward \ backward  and up \ down of NPC. i need just to push a fighter along Y axis with + values, but NOT with absolutely map Y vector, but with Y axis vector relative to entity.

 

mmm strange, video link not work :( try to dive into google with search about "rogue squadron 3d escape on fest gold medal" and you see what i want to recreate.

 

I think the function I mentioned (that uses force_forwardmove) might show you how to turn a vector into ucmd directions.  But, if not, it's pretty simple.  The basic procedure is like this:

 

You have to turn the world velocity/vector into a local one.  The easiest way to do this is vector multiplying.

 

First, normalize the velocity with VectorNormalize() (this will also return the scale of the vector - your desired speed - you won't need this).  Something like this:

 

desiredSpeed = VectorNormalize( desiredVelocity );

 

Now desiredVelocity is a vector with a magnitude of 1 (a direction, not a velocity anymore) and your desiredSpeed is the speed you want to go in that direction (again, this won't be used unless you want to use this to set the vehicle's current speed or something)

 

Next, use the angles of your entity to get your forward, right and up vectors.  There should be a command something like "VectorAngles" or "AnglesToVector" - something like that.  You pass in your angles and it should pass you back 3 normalized vectors - forward, right and up.

 

Then multiply each of these normalized vectors times the desired velocity/vector.  That will give you the normalized (-1 to 1) *magnitude* (or speed) that you need to travel along in that local direction.

 

For example:

 

float forwardAmt = forward * desiredVelocity;

 

(I don't recall, offhand, if you can multiply vectors directly like that in Jedi code, you may need to use VectorMultiply() or something like that? - EDIT: in Jedi, we used dot_product() for this...)

 

Do that for all 3 local vectors (forward, right, up).  Now you should have 3 vectors from -1 to 1.  All you need to do now is multiply them by 128 and turn them into ints with int().

 

Ultimately, these will be used to turn this back into a normalized vector which gets multiplied by your current speed.

 

EDIT:

Was able to look up the function that does this:

void G_UcmdMoveForDir( gentity_t *self, usercmd_t *cmd, vec3_t dir )
Smoo, Asgarath83 and Archangel35757 like this
Link to comment

Dear MGummelt, thanks for time you spend to answer to me and to alls coder of JKHUB. here in italy is pretty hot summer and is not easy stay on computer to do coding with hot weather. but i'll do as soon as i can. i really want to see the result and i think your suggests are pretty valid and interessing. thanks again and have nice holiday. i'will let you know my progress ;)

Smoo likes this
Link to comment

Dear MGummelt, thanks for time you spend to answer to me and to alls coder of JKHUB. here in italy is pretty hot summer and is not easy stay on computer to do coding with hot weather. but i'll do as soon as i can. i really want to see the result and i think your suggests are pretty valid and interessing. thanks again and have nice holiday. i'will let you know my progress ;)

 

No problem, and good luck!

Smoo likes this
Link to comment

@@MGummelt

 

okay, this is what i am trying to archieve.

I have my fighter AI, and this is the default behavour.

 

void NPC_BSFighter_Default( void )
{
    NPC->client->forced_forwardmove = 127;
    // WORK IN PROGRESS
    //NPC->e_DieFunc = dieF_Fighter_die;

    /*if ( NPC->targetname )
    {
        //NPC->e_UseFunc = useF_TieFighter_use;
        NPC->e_UseFunc = useF_TieFighterUse;
    }*/
    
    if ( NPC->enemy )
    {
        if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
        {
            NPCInfo->goalEntity = NPC->enemy;
        }
        Fighter_Hunt();
        Fighter_AttackDecision();
        Fighter_Update();
    }    
    /*{
        NPCInfo->goalEntity = NPC->enemy;
        Fighter_Hunt();
        Fighter_AttackDecision();
    }*/
    else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
    {
        Fighter_Patrol();
    }
    else
    {
        Fighter_Idle();
    }
}
 

as you can see, the fighter have the following statements:

Idle: do nothing, is the behavor that assume when it spawn. is in wait of order.

Patrol: move throught waypoint and Navgoal, like a sentry, following desired icarus scripted path.

Hunt: chase an Enemy

Update: update the AI fight boba fett fighting advanced ai commands and behavours.

AttackDecision: remind to tacticts: fighter decide what kind of approach have on the Enemy, switching and selecting the properly weapons of his arsenal to attack, this is  set by calculating variable like the distance from opponent and other tnings.

this works like an half way between a sentry Ai and Bobafett AI.

now, i want that fighter get an autoforward movement when is in idle and patrol. this movement are not a specified speed. should be more better if the speed value can be definied throught NPC file.

for Idle and Patrol behavour i want to force fighter to move forward at his walkspeed.

for Hunt and attack behavour, when shoot and chase enemy, i wanna force the fighter to move forward to his NPC Runspeed.

 

so, i start with my Fighter_Idle code.

 

void Fighter_Idle( void )
{
    Fighter_MaintainHeight();
    Fighter_flyforward1();
    
    
    // Is he waking up?
    if (NPCInfo->localState == FSTATE_WAKEUP)
    {
        if (NPC->client->ps.torsoAnimTimer<=0)
        {
            NPCInfo->scriptFlags |= SCF_LOOK_FOR_ENEMIES;
            NPCInfo->burstCount = 0;
        }
    }
    else
    {
        NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_SLEEP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
        NPC->flags |= FL_SHIELDED;

        NPC_BSIdle();
    }
}

where Fighter_flyforward is the void function called for take the automovement to the fighter.

now is the hardest way... WRITE the fighter_flyforward function.

 

void Fighter_flyforward1( gentity_t *self, usercmd_t *cmd, vec3_t dir )
{
    vec3_t    forward, right;
    AngleVectors( self->currentAngles, forward, right, NULL );
    
    // Automoving forward at walkspeed.
    FighterSpeed = VectorNormalize(FighterVelocity);
    float forwardAmt = forward*FighterVelocity;
    // ????!?!??! what i need to do now?!?!?
    // CODE PAST BY AI_JEDI.CPP
    if ( VectorCompare( NPC->client->ps.moveDir, vec3_origin )
        && (ucmd.forwardmove||ucmd.rightmove) )
    {//using ucmds to move this turn, not NAV
        
        
        
        if ( (ucmd.buttons&BUTTON_WALKING) )
        {//FIXME: NAV system screws with speed directly, so now I have to re-set it myself!
            NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
        }
        else
        {
            NPC->client->ps.speed = NPCInfo->stats.runSpeed;
        }
    }*/

    // CODE PASTE BY NPC_MOVE.CPP
    dir[2] = 0;
    VectorNormalize( dir );
    //NPCs cheat and store this directly because converting movement into a ucmd loses precision
    VectorCopy( dir, self->client->ps.moveDir );

    float fDot = DotProduct( forward, dir ) * 127.0f;
    float rDot = DotProduct( right, dir ) * 127.0f;
    //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte
    if ( fDot > 127.0f )
    {
        fDot = 127.0f;
    }
    if ( fDot < -127.0f )
    {
        fDot = -127.0f;
    }
    if ( rDot > 127.0f )
    {
        rDot = 127.0f;
    }
    if ( rDot < -127.0f )
    {
        rDot = -127.0f;
    }
    cmd->forwardmove = floor(fDot);
    cmd->rightmove = floor(rDot);
}

 

basically, i not know much of C++ just the base and i have not familiarity with vector. for my curse, i never ended the high schools for heal problems, so i lack of math knowledge i need for understand that. 

i pasted for have an hint two chunks of code: one is the function you direct to me, that sect the movement in base of direction to an NPC when is moving. the second chunks of code i picked up from Ai_JEDI.CPP.

i Not need directly that, but i just wanna to give a look about how to force , with code way, an NPC to move at walkspeed NPC data value or runspeed. this chunk of code contain the answer.

so now, what i need is to merge the two stuff into something that my Fighter can understand.

at the start of file, i setted FighterSpeed as an int

Int FighterSpeed; 

vec3_t FighterVelocity;

That's are my version of your suggested desiredSpeed and DesiredVelocity.

 

This is the part that i really not anderstand. because there is not any forwardAmt on my code.

 float forwardAmt = forward*FighterVelocity;

 

Well, so basically... i reached a dead lock point.

i not know exactly how to write this function. i not want to abuse of your time and your patience, you are very kind with me and other coder, but... well, i should need an hint, or  little better because i not understand much vector maths, (vectors are simply directions, X, Y, Z, on a cartesian 3d grid, for what i understood, they are necessaty for tell to the entity how to move and in what direction on the 3Dspace of game).

well, i need a step by step little guide about that.

Thanks for every reply. :\

i spend 3 hours on that and i get a painful headache.

Link to comment

i tryed this but with no much result

 

vec3_t    forward, right;
    FighterSpeed = NPC->client->ps.speed;  
    //float forwardAmt = forward*FighterVelocity;
    //FighterVelocity = forwardAmt;
       
    NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
    //AngleVectors( self->currentAngles, forward, right, NULL );
    AngleVectors( NPC->currentAngles, forward, NULL, NULL );
    FighterSpeed = VectorNormalize(FighterVelocity);
  

i cannot use float forwardAmt because visual studio give me error. it require an editable Lvalue... o.O.

Link to comment

i Did a lot of progress but again i not have the desired movement. i am working on the

fighter_flyforward function but again it not work... or crashes if i enable the fighter_hunt past code about visible and advance.

is just a first step. i need to study this for understand exactly what i need to do for boost my fighters. they move fine when they attack,. but when they spawn they are passive. i wanna they move at their walkspeed when they spawn, with forceforwarding, or a vector or any other code possibilities. . 

i paste here the code, in the case of someone desires to give me a little hint of what is wrong on this fly AI. except fighter_forward function, this is again work in progress. ^_^

 

 

///////////////////////////////// FLIGHT AI /////////////////////////////////

/*
-------------------------
Fighter_Strafe
-------------------------
*/
void Fighter_Strafe( void )
{
    int        dir;
    vec3_t    end, right;
    trace_t    tr;

    AngleVectors( NPC->client->renderInfo.eyeAngles, NULL, right, NULL );

    // Pick a random strafe direction, then check to see if doing a strafe would be
    //    reasonable valid
    dir = ( rand() & 1 ) ? -1 : 1;
    VectorMA( NPC->currentOrigin, FIGHTER_STRAFE_DIS * dir, right, end );

    gi.trace( &tr, NPC->currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID, (EG2_Collision)0, 0 );

    // Close enough
    if ( tr.fraction > 0.9f )
    {
        VectorMA( NPC->client->ps.velocity, FIGHTER_STRAFE_VEL * dir, right, NPC->client->ps.velocity );

        // Add a slight upward push
        NPC->client->ps.velocity[1] += FIGHTER_UPWARD_PUSH;
        //NPC->client->ps.velocity[2] += FIGHTER_UPWARD_PUSH;

        // Set the strafe start time so we can do a controlled roll
        NPC->fx_time = level.time;
        NPCInfo->standTime = level.time + 3000 + random() * 500;
    }
}
//extern void rocketThink ( gentity_t *ent );
/*
-------------------------
Fighter_Hunt
-------------------------
*/
void Fighter_Hunt( qboolean visible, qboolean advance )
{
    float    distance, speed;
    vec3_t    forward;

    //If we're not supposed to stand still, pursue the player
    if ( NPCInfo->standTime < level.time )
    {
        // Only strafe when we can see the player
        if ( visible )
        {
            Fighter_Strafe();
            return;
        }
    }

    //If we don't want to advance, stop here
    if ( !advance && visible )
        return;

    //Only try and navigate if the player is visible
    if ( visible == qfalse )
    {
        // Move towards our goal
        NPCInfo->goalEntity = NPC->enemy;
        NPCInfo->goalRadius = 1024;
        NPC_MoveToGoal(qtrue);


        return;
    }
    else
    {
        VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, forward );
        distance = VectorNormalize( forward );
    }

    speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;
    VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
}

/*
-------------------------
Fighter_RangedAttack
-------------------------
*/
void Fighter_RangedAttack( qboolean visible, qboolean advance )
{
    if ( TIMER_Done( NPC, "attackDelay" ) && NPC->attackDebounceTime < level.time && visible )    // Attack?
    {
        if ( NPCInfo->burstCount > 6 )
        {
            if ( !NPC->fly_sound_debounce_time )
            {//delay closing down to give the player an opening
                NPC->fly_sound_debounce_time = level.time + Q_irand( 500, 2000 );
            }
            else if ( NPC->fly_sound_debounce_time < level.time )
            {
                NPCInfo->localState = FSTATE_ACTIVE;
                NPC->fly_sound_debounce_time = NPCInfo->burstCount = 0;
                TIMER_Set( NPC, "attackDelay", Q_irand( 2000, 3500) );
                NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_FLY_SHIELDED, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
                G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/Fighter/misc/Fighter_shield_close" );
                // Fighter high ranked shield itself when chase the player.
                if ( NPCInfo->rank > RANK_LT_COMM )
                {
                    NPC->flags |= FL_SHIELDED;
                }
            }
        }
        else
        {
            Fighter_Fire();
        }
    }

    if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
    {
        Fighter_Hunt( visible, advance );
    }
}



/*
-------------------------
Fighter_MaintainHeight
-------------------------
*/
void Fighter_MaintainHeight( void )
{    
    float    dif;

    NPC->s.loopSound = G_SoundIndex( "sound/chars/Fighter/misc/Fighter_hover_1_lp" );

    // Update our angles regardless
    NPC_UpdateAngles( qtrue, qtrue );

    // If we have an enemy, we should try to hover at about enemy eye level
    if ( NPC->enemy )
    {
        // Find the height difference
        dif = (NPC->enemy->currentOrigin[2]+NPC->enemy->maxs[2]) - NPC->currentOrigin[2];

        // cap to prevent dramatic height shifts
        if ( fabs( dif ) > 8 )
        {
            if ( fabs( dif ) > FIGHTER_HOVER_HEIGHT )
            {
                dif = ( dif < 0 ? -24 : 24 );
            }

            NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
        }
    }
    else
    {
        gentity_t *goal = NULL;

        if ( NPCInfo->goalEntity )    // Is there a goal?
        {
            goal = NPCInfo->goalEntity;
        }
        else
        {
            goal = NPCInfo->lastGoalEntity;
        }

        if (goal)
        {
            dif = goal->currentOrigin[2] - NPC->currentOrigin[2];

            if ( fabs( dif ) > FIGHTER_HOVER_HEIGHT )
            {
                ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 );
            }
            else
            {
                if ( NPC->client->ps.velocity[2] )
                {
                    NPC->client->ps.velocity[2] *= FIGHTER_VELOCITY_DECAY;

                    if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
                    {
                        NPC->client->ps.velocity[2] = 0;
                    }
                }
            }
        }
        // Apply friction to Z
        else if ( NPC->client->ps.velocity[2] )
        {
            NPC->client->ps.velocity[2] *= FIGHTER_VELOCITY_DECAY;

            if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
            {
                NPC->client->ps.velocity[2] = 0;
            }
        }
    }

    // Apply friction
    if ( NPC->client->ps.velocity[0] )
    {
        NPC->client->ps.velocity[0] *= FIGHTER_VELOCITY_DECAY;

        if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
        {
            NPC->client->ps.velocity[0] = 0;
        }
    }

    if ( NPC->client->ps.velocity[1] )
    {
        NPC->client->ps.velocity[1] *= FIGHTER_VELOCITY_DECAY;

        if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
        {
            NPC->client->ps.velocity[1] = 0;
        }
    }

    NPC_FaceEnemy( qtrue );
}

void Fighter_flyforward1( void )
{
    //qboolean visible, advance;
    // Rate our distance to the target and visibilty
    /*float        distance2    = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );    
    qboolean    visible2    = NPC_ClearLOS( NPC->enemy );
    qboolean    advance2       = (qboolean)(distance2 > FIGHTER_MIN_DISTANCE_SQR);*/

    
    
    //visible, int advance;
    float    distance, speed;
    vec3_t    forward;
    speed = NPCInfo->stats.walkSpeed;
    //speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;
    VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
    distance = VectorNormalize( forward );


    //We're not supposed to stand still, move forward at run speed!
    if ( NPCInfo->standTime < level.time )
    {
        speed = NPCInfo->stats.walkSpeed;
        //FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;
        VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
        distance = VectorNormalize( forward );

        // Only strafe when we can see the player
        /*if ( visible2 )
        {
            Fighter_Strafe();
            return;
        }*/
    }

    //If we don't want to advance, stop here
    /*if ( !advance2 && visible2 )
        return;*/

    //Only try and navigate if the player is visible
    /*if ( visible2 == qfalse )
    {
        // Move towards our goal
        NPCInfo->goalEntity = NPC->enemy;
        NPCInfo->goalRadius = 1024;
        NPC_MoveToGoal(qtrue);


        return;
    }
    else
    {
        VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, forward );
        distance = VectorNormalize( forward );
    }*/

    
    /*
    vec3_t    forward, right;
    FighterSpeed = NPC->client->ps.speed;  
    //float forwardAmt = forward*FighterVelocity;
    //FighterVelocity = forwardAmt;
       
    NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
    //AngleVectors( self->currentAngles, forward, right, NULL );
    AngleVectors( NPC->currentAngles, forward, NULL, NULL );
    FighterSpeed = VectorNormalize(FighterVelocity);
    
    //else if

    
    /*vec3_t    forward, right;
    //AngleVectors( self->currentAngles, forward, right, NULL );
    
    // Automoving forward at walkspeed.
    FighterSpeed = VectorNormalize(FighterVelocity);
    //float forwardAmt = forward*FighterVelocity;
    // ????!?!??! what i need to do now?!?!?
    // CODE PAST BY AI_JEDI.CPP
    if ( VectorCompare( NPC->client->ps.moveDir, vec3_origin )
        && (ucmd.forwardmove||ucmd.rightmove) )
    {//using ucmds to move this turn, not NAV
        if ( (ucmd.buttons&BUTTON_WALKING) )
        {//FIXME: NAV system screws with speed directly, so now I have to re-set it myself!
            NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
        }
        else
        {
            NPC->client->ps.speed = NPCInfo->stats.runSpeed;
        }
    }

    // CODE PASTE BY NPC_MOVE.CPP
    /*dir[2] = 0;
    VectorNormalize( dir );
    //NPCs cheat and store this directly because converting movement into a ucmd loses precision
    VectorCopy( dir, self->client->ps.moveDir );

    float fDot = DotProduct( forward, dir ) * 127.0f;
    float rDot = DotProduct( right, dir ) * 127.0f;
    //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte
    if ( fDot > 127.0f )
    {
        fDot = 127.0f;
    }
    if ( fDot < -127.0f )
    {
        fDot = -127.0f;
    }
    if ( rDot > 127.0f )
    {
        rDot = 127.0f;
    }
    if ( rDot < -127.0f )
    {
        rDot = -127.0f;
    }
    cmd->forwardmove = floor(fDot);
    cmd->rightmove = floor(rDot);*/
}


    
/*
-------------------------
Fighter_Idle
-------------------------
*/
void Fighter_Idle( void )
{
    Fighter_MaintainHeight();
    //Fighter_flyforward1();
    


    
    // Is he waking up?
    if (NPCInfo->localState == FSTATE_WAKEUP)
    {
        if (NPC->client->ps.torsoAnimTimer<=0)
        {
            NPCInfo->scriptFlags |= SCF_LOOK_FOR_ENEMIES;
            NPCInfo->burstCount = 0;
        }
    }
    else
    {
        NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_SLEEP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
        NPC->flags |= FL_SHIELDED;

        NPC_BSIdle();
    }
}


/*
-------------------------
Fighter_AttackDecision
-------------------------
*/
void Fighter_AttackDecision( void )
{
    // Always keep a good height off the ground
    Fighter_MaintainHeight();

    NPC->s.loopSound = G_SoundIndex( "sound/chars/Fighter/misc/Fighter_hover_2_lp" );

    //randomly talk
    if ( TIMER_Done(NPC,"patrolNoise") )
    {
        if (TIMER_Done(NPC,"angerNoise"))
        {
            G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/Fighter/misc/talk%d", Q_irand(1, 3)) );

            TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) );
        }
    }

    // He's dead.
    if (NPC->enemy->health<1)
    {
        NPC->enemy = NULL;
        Fighter_Idle();
        return;
    }

    // If we don't have an enemy, just idle
    if ( NPC_CheckEnemyExt() == qfalse )
    {
        Fighter_Idle();
        return;
    }

    // Rate our distance to the target and visibilty
    float        distance    = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );    
    qboolean    visible        = NPC_ClearLOS( NPC->enemy );
    qboolean    advance        = (qboolean)(distance > FIGHTER_MIN_DISTANCE_SQR);

    // If we cannot see our target, move to see it
    if ( visible == qfalse )
    {
        if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
        {
            Fighter_Hunt( visible, advance );
            return;
        }
    }

    NPC_FaceEnemy( qtrue );

    Fighter_RangedAttack( visible, advance );
}

qboolean NPC_CheckFighterTeamStealth( void );





/*
-------------------------
Fighter_Hunt
- look for enemy.
-------------------------`
*/

void Fighter_Hunt(void)
{

    if ( NPCInfo->goalEntity == NULL )
    {
        NPCInfo->goalEntity = NPC->enemy;
    }

    NPC_FaceEnemy( qtrue );

    NPCInfo->combatMove = qtrue;
    NPC_MoveToGoal( qtrue );
}
/*
-------------------------
Fighter_Patrol
-------------------------
*/
void Fighter_Patrol( void )
{
    
    Fighter_MaintainHeight();
    //SENTRY CODE
    //If we have somewhere to go, then do that
    if (!NPC->enemy)
    {
        if ( NPC_CheckPlayerTeamStealth() )
        {
            //NPC_AngerSound();
            NPC_UpdateAngles( qtrue, qtrue );
            return;
        }

        if ( UpdateGoal() )
        {
            //start loop sound once we move
            ucmd.buttons |= BUTTON_WALKING;
            NPC_MoveToGoal( qtrue );
        }

        //randomly talk
        if (TIMER_Done(NPC,"patrolNoise"))
        {
            G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/Fighter/misc/talk%d", Q_irand(1, 3)) );

            TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) );
        }
    }

    NPC_UpdateAngles( qtrue, qtrue );
    
    //// MARK CODE
    
    if ( NPC_CheckPlayerTeamStealth() )
    {
        G_Sound( NPC, G_SoundIndex("sound/chars/Fighter/misc/Fighter_wakeup"));
        NPC_UpdateAngles( qtrue, qtrue );
        return;
    }

    //If we have somewhere to go, then do that
    if (!NPC->enemy)
    {
        if ( UpdateGoal() )
        {
            ucmd.buttons |= BUTTON_WALKING;
            NPC_MoveToGoal( qtrue );
            NPC_UpdateAngles( qtrue, qtrue );
        }

        //randomly talk
        if (TIMER_Done(NPC,"patrolNoise"))
        {
            G_Sound( NPC, G_SoundIndex(va("sound/chars/Fighter/misc/talk%d.wav",    Q_irand(1, 4))));

            TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) );
        }
    }

}

/*
-------------------------
NPC_BSFighter_Default
-------------------------
*/

void NPC_BSFighter_Default( void )
{
    // When you spawn immediatly execute this!!
    Fighter_flyforward1();
    
    //NPC->client->forced_forwardmove = 127;
    // DA PROGRAMMARE PER ORA E' INERTE.
    //NPC->e_DieFunc = dieF_Fighter_die;

    /*if ( NPC->targetname )
    {
        //NPC->e_UseFunc = useF_TieFighter_use;
        NPC->e_UseFunc = useF_TieFighterUse;
    }*/
    
    if ( NPC->enemy )
    {
        if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
        {
            NPCInfo->goalEntity = NPC->enemy;
        }
        Fighter_Hunt();
//        Fighter_Hunt( visible, advance);
        Fighter_AttackDecision();
        Fighter_Update();
    }    
    /*{
        NPCInfo->goalEntity = NPC->enemy;
        Fighter_Hunt();
        Fighter_AttackDecision();
    }*/
    else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
    {
        Fighter_Patrol();
    }
    else
    {
        Fighter_Idle();
    }
}
Link to comment

The reason the fighters move fine when they attack is that the Hunt function is setting their velocity directly.

 

If that's all you want to do in idle or patrol, just set the velocity directly and ignore all the forwardmove and usercmd stuff. Like below:

    //Get your current forward dir
    AngleVectors( NPC->client->renderInfo.eyeAngles, forward, NULL, NULL );
   //or just this - not sure why you're trying to get the NPC's eye angles on a vehicle above?  That would be more for a player controlling a vehicle
    AngleVectors( self->currentAngles, forward, right, NULL );

   //Set speed to walkspeed or runspeed or whatever you want
    speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;

   //set velocity directly - note that this *adds* the new velocity to the old one, meaning it will keep accelerating - only do this if the speed hasn't reached max or you're changing direction
    VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
   //You can just do this, but this will go to the new velocity immediately - you'd have to smooth out acceleration yourself
    VectorMultiply( forward, speed, NPC->client->ps.velocity );
Archangel35757 likes this
Link to comment

 

The reason the fighters move fine when they attack is that the Hunt function is setting their velocity directly.

 

If that's all you want to do in idle or patrol, just set the velocity directly and ignore all the forwardmove and usercmd stuff. Like below:

    //Get your current forward dir
    AngleVectors( NPC->client->renderInfo.eyeAngles, forward, NULL, NULL );
   //or just this - not sure why you're trying to get the NPC's eye angles on a vehicle above?  That would be more for a player controlling a vehicle
    AngleVectors( self->currentAngles, forward, right, NULL );

   //Set speed to walkspeed or runspeed or whatever you want
    speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;

   //set velocity directly - note that this *adds* the new velocity to the old one, meaning it will keep accelerating - only do this if the speed hasn't reached max or you're changing direction
    VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
   //You can just do this, but this will go to the new velocity immediately - you'd have to smooth out acceleration yourself
    VectorMultiply( forward, speed, NPC->client->ps.velocity );

Thanks friend, i testing now.  well, as i told, my fighter is not a vehicle... the AI is building with a workaroung about AI_SENTRY (for flying) and AI_Bobafett (for combat and switch weapons) but all i obtains was some funny fighter droids NPC that fly and shoot like tornado assault chopter. (but they are not vehicles. they are characters, like jedi, lijke sith, like reborns, foir engines they are NPCs. they only appear as fighter because they have the tie fighter model that i have rigged with humanoid skeleton, only to pelvis bone (so i obtained a rigid body starfighter NPC) and i also added in front of tiefighter cannon the l_hand and r_hand tag, 

i also removed for fighter class the spawning of shooting weapons glm models (so fighter not have silly a blaster or a repeater or a rocket launcher attacked to his cannon)

i added also death efx explosion with corpse removal and customized FX of all shooting weapons for starfighter class. 

At moment, for avoid to make mistakes or some big error on AI without remember how things works before and how repairs

(i have backuped copy of my edited AI_sentry.cpp file) i have setted all the fighter parameter to another class so i am using this class for making all test and debugging for avoid of ruin fighter class with my noob c++ skills.

the test class is called CLASS_OLON i changed also the functions name for avoid redundance or conflict with fighters ruins.

in this AI, i tryed something of difference: instead of Sentry droid fly behavour i tryed the AI_REMOTE.cpp.

and yesterday i discover that flight is not setted by Fighter_hunt \ Olon_hunt functions as i wrong thinked...

the Hunt function control the chasing of the enemy.

the Flight of NPC, instead if setted by Fighter_MaintainHeight \ Olon_MantainHeight of my test code.

and here, on the olon workinprogress testing AI, i merged the remote and sentry maintain height functions.

the result for combat and dogfight is... Spectacular!

with some little adjustament (i added faceenemy, because Remote AI have not and i disable remote spin of model)  i obtain an NPC fighers that chase enemy and move like a remote instead of a sentry, but also strafing like a sentry... oh well, a good starfighter battle!

this is my work in progress edit:

 

/*
-------------------------
Olon_MaintainHeight
-------------------------
*/
void Olon_MaintainHeight( void )
{    
    float    dif;

    // Update our angles regardless
    ////////////////////////////////////////    
    NPC_FaceEnemy( qtrue );
    NPC_UpdateAngles( qtrue, qtrue );

    // Cambia il vettore 2 con l'1.
    if ( NPC->client->ps.velocity[2] )
    {
        NPC->client->ps.velocity[2] *= OLON_DECAY;

        if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
        {
            NPC->client->ps.velocity[2] = 0;
        }
    }
    // If we have an enemy, we should try to hover at or a little below enemy eye level
    if ( NPC->enemy )
    {
        //SENTRY
        // Find the height difference
        dif = (NPC->enemy->currentOrigin[2]+NPC->enemy->maxs[2]) - NPC->currentOrigin[2];
        // cap to prevent dramatic height shifts
        if ( fabs( dif ) > 8 )
        {
            if ( fabs( dif ) > OLON_HOVER_HEIGHT )
            {
                dif = ( dif < 0 ? -24 : 24 );
            }

            NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
        }
        //REMOTE
        if (TIMER_Done( NPC, "OlonheightChange"))
        {
            TIMER_Set( NPC,"OlonheightChange",Q_irand( 1000, 3000 ));

            // Find the height difference
            dif = (NPC->enemy->currentOrigin[2] +  Q_irand( 0, NPC->enemy->maxs[2]+8 )) - NPC->currentOrigin[2];

            // cap to prevent dramatic height shifts
            if ( fabs( dif ) > 2 )
            {
                if ( fabs( dif ) > 24 )
                {
                    dif = ( dif < 0 ? -24 : 24 );
                }
                dif *= 10;
                NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
                NPC->fx_time = level.time;
                //G_Sound( NPC, G_SoundIndex("sound/chars/Olon/misc/hiss.wav"));
            }
        }
    }
    else
    {
        //REMOTE
        gentity_t *goal = NULL;

        if ( NPCInfo->goalEntity )    // Is there a goal?
        {
            goal = NPCInfo->goalEntity;
        }
        else
        {
            goal = NPCInfo->lastGoalEntity;
        }

        if (goal)
        {
            dif = goal->currentOrigin[2] - NPC->currentOrigin[2];

            //REMOTE
            if ( fabs( dif ) > 24 )
            {
                dif = ( dif < 0 ? -24 : 24 );
                NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
            }
            //SENTRY
            if ( fabs( dif ) > OLON_HOVER_HEIGHT )
            {
                ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 );
            }
            else
            {
                if ( NPC->client->ps.velocity[2] )
                {
                    NPC->client->ps.velocity[2] *= OLON_VELOCITY_DECAY;

                    if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
                    {
                        NPC->client->ps.velocity[2] = 0;
                    }
                }
            }
        }
        // Apply friction to Z
        else if ( NPC->client->ps.velocity[2] )
        {
            NPC->client->ps.velocity[2] *= OLON_VELOCITY_DECAY;

            if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
            {
                NPC->client->ps.velocity[2] = 0;
            }
        }
        // Apply friction
        else if ( NPC->client->ps.velocity[0] )
        {
            NPC->client->ps.velocity[0] *= OLON_DECAY;

            if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
            {
                NPC->client->ps.velocity[0] = 0;
            }
        }
        else if ( NPC->client->ps.velocity[1] )
        {
            NPC->client->ps.velocity[1] *= OLON_DECAY;
            if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
            {
                NPC->client->ps.velocity[1] = 0;
            }
        }
    }
}

/*
-------------------------
Olon_Strafe
-------------------------
*/
void Olon_Strafe( void )
{
    int        dir;
    vec3_t    end, right;
    trace_t    tr;

    AngleVectors( NPC->client->renderInfo.eyeAngles, NULL, right, NULL );

    // Pick a random strafe direction, then check to see if doing a strafe would be
    //    reasonable valid
    dir = ( rand() & 1 ) ? -1 : 1;
    VectorMA( NPC->currentOrigin, OLON_STRAFE_DIS * dir, right, end );

    gi.trace( &tr, NPC->currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID, (EG2_Collision)0, 0 );

    // Close enough
    if ( tr.fraction > 0.9f )
    {
        VectorMA( NPC->client->ps.velocity, OLON_STRAFE_VEL * dir, right, NPC->client->ps.velocity );

        G_Sound( NPC, G_SoundIndex("sound/chars/remote/misc/hiss.wav"));

        // Every time strafing, Add also a slight forward push.
        // so you will go after your enemy and you can attack from back!
        NPC->client->ps.velocity[1] += OLON_FORWARD_PUSH;
        // Set the strafe start time so we can do a controlled roll
        NPC->fx_time = level.time;
        NPCInfo->standTime = level.time + 3000 + random() * 500;
    }
}


/*
-------------------------
Olon_Hunt
-------------------------
*/
void Olon_Hunt( qboolean olonvisible, qboolean olonadvance, qboolean olonretreat )
{
    float    olondistance, olonspeed;
    vec3_t    forward;

    //If we're not supposed to stand still, pursue the player
    if ( NPCInfo->standTime < level.time )
    {
        // Only strafe when we can see the player
        if ( olonvisible )
        {
            Olon_Strafe();
            return;
        }
    }

    //If we don't want to advance, stop here
    if ( olonadvance == qfalse && olonvisible == qtrue )
        return;

    //Only try and navigate if the player is visible
    if ( olonvisible == qfalse )
    {
        // Move towards our goal
        NPCInfo->goalEntity = NPC->enemy;
        NPCInfo->goalRadius = 12;

        NPC_MoveToGoal(qtrue);
        return;

    }
    else
    {
        VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, forward );
        olondistance = VectorNormalize( forward );
    }

    olonspeed = OLON_FORWARD_BASE_SPEED + OLON_FORWARD_MULTIPLIER * g_spskill->integer;
    if ( olonretreat == qtrue )
    {
        olonspeed *= -1;
    }
    VectorMA( NPC->client->ps.velocity, olonspeed, forward, NPC->client->ps.velocity );
    NPC_FaceEnemy( qtrue );
}


/*
-------------------------
Olon_Ranged
-------------------------
*/
void Olon_Ranged( qboolean olonvisible, qboolean olonadvance, qboolean olonretreat )
{

    if ( TIMER_Done( NPC, "attackDelay" ) )    // Attack?
    {
        TIMER_Set( NPC, "attackDelay", Q_irand( 500, 3000 ) );
        Olon_Fire();
    }

    if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
    {
        Olon_Hunt( olonvisible, olonadvance, olonretreat );
    }
}

#define    MIN_OLON_RANGE        8192
#define    MIN_OLON_RANGE_SQR    ( MIN_OLON_RANGE * MIN_OLON_RANGE )

#define MIN_OLON_DISTANCE        1024
#define MIN_OLON_SQR    ( MIN_OLON_DISTANCE * MIN_OLON_DISTANCE )

/*
-------------------------
Olon_Attack
-------------------------
*/
void Olon_Attack( void )
{
    //QQQ DISABLED FOR AVOID SILLY SPINNING MOVEMENT
    /*if ( TIMER_Done(NPC,"spin") )
    {
        TIMER_Set( NPC, "spin", Q_irand( 250, 1500 ) );
        NPCInfo->desiredYaw += Q_irand( -200, 200 );
    }*/
    // Always keep a good height off the ground
    Olon_MaintainHeight();

    // If we don't have an enemy, just idle
    if ( NPC_CheckEnemyExt() == qfalse )
    {
        Olon_Idle();
        return;
    }

    // Rate our distance to the target, and our visibilty
    float        olondistance    = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );    
//    distance_e    distRate    = ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE;
    qboolean    olonvisible        = NPC_ClearLOS( NPC->enemy );
    float        olonidealDist    = MIN_OLON_SQR+(MIN_OLON_SQR*Q_flrand( 0, 1 ));
    qboolean    olonadvance        = (qboolean)(olondistance > olonidealDist*1.25);
    qboolean    olonretreat        = (qboolean)(olondistance < olonidealDist*0.75);

    // If we cannot see our target, move to see it
    if ( olonvisible == qfalse )
    {
        if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
        {
            Olon_Hunt( olonvisible, olonadvance, olonretreat );
            return;
        }
    }

    Olon_Ranged( olonvisible, olonadvance, olonretreat );

}

/*
-------------------------
Olon automatic flyforwards functions
-------------------------
*/
void Olon_flyforward1( void )
{
    float speed;
    vec3_t    forward;
     //Get your current forward dir
    AngleVectors( NPC->client->renderInfo.eyeAngles, forward, NULL, NULL );
   //or just this - not sure why you're trying to get the NPC's eye angles on a vehicle above?  That would be more for a player controlling a vehicle
    //AngleVectors( self->currentAngles, forward, right, NULL );
    ucmd.forwardmove = NPC->client->forced_forwardmove;
    speed = NPCInfo->stats.walkSpeed;
    //Set speed to walkspeed or runspeed or whatever you want
    //speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;
     //set velocity directly - note that this *adds* the new velocity to the old one, meaning it will keep accelerating - only do this if the speed hasn't reached max or you're changing direction
    VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
        //You can just do this, but this will go to the new velocity immediately - you'd have to smooth out acceleration yourself
    //VectorMultiply( forward, speed, NPC->client->ps.velocity );
    NPC->client->ps.pm_time = 500;
    NPC->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
}    


/*
-------------------------
Olon Idle
-------------------------
*/
void Olon_Idle( void )
{
    Olon_flyforward1();//autoforward at walkspeed
    Olon_MaintainHeight();

    NPC_BSIdle();
}

/*
-------------------------
Olon_Patrol
-------------------------
*/
void Olon_Patrol( void )
{
    Olon_MaintainHeight();

    //If we have somewhere to go, then do that
    if (!NPC->enemy)
    {
        if ( UpdateGoal() )
        {
            //start loop sound once we move
            ucmd.buttons |= BUTTON_WALKING;
            NPC_MoveToGoal( qtrue );
        }
    }

    NPC_UpdateAngles( qtrue, qtrue );
}


/*
-------------------------
NPC_BSOlon_Default
-------------------------
*/
void NPC_BSOlon_Default( void )
{
    if ( NPC->enemy )
    {
        Olon_Attack();
    }
    else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
    {
        Olon_Patrol();
    }
    else
    {
        Olon_Idle();
    }
}
 
 

basically:

on hunt, i added the face enemy and disabled the spin of remote droid

on strafing, i changed the "add a slight upward push" that's because is a fighting between two NPC, one friend and other enemy, every time fighter are strafing they go upward a lot. result: after 10 minutes of battle they are on the top of skybox of the map

Lmao. XD

obvious, sentry and remote are not thinked for fight each other, i see also rockettroopers have this little problem.

so i changed the upward push of ps.velocity on vector 2 (up\down) to vector 1 (forward \ backward) in this way, the push will be forward and not up. i hjave not again tested but if i am correct the result is: every time fighter will strafing, they go a lot forward (i set the value for deal a big push forward) so fighter will go over his enemy and reach his backs and shoot on the back of fighter opponent to the next attack. teorically should works, now i need to test.

 

On olon maintain height i am testing a merged fabs vector functions that merge remote and sentry flying parameter. as i told, i obtained something of pretty interessing: the fighters on a dogfight, fight really as fighters!

they also are pretty smart: if i escape, the NPC fighter go over my fighter NPC, and face me and shoot me when is strafing on left \right with a frontal attack (but moving on left) this is nice! is better and more realistic of fighters that fight like F16 airplanes.

if i am on behind of a fighter, with this movement it is not so stupid to expose vulnerable parts are boosters and back. it turn for face opponent, (they are starfighter by the rest, so why fight as war airplanes . into the space there are not up\down distinction)

so, now in dogfight fighter escape, attack, strafing, fly around the enemy shooting very nicely and facing each others!

the only problem is i created a little logarithmic accelerations,... fighters become soon fast... too fast every time they turn and strafe into a new attack. (like speed vehicle but more madness movement!) so fast that at the end they are impossible to targetting and they fly into a spare of time by a corner of map, throw map itself, to other corner! really i will need to apply a STRONG friction on this acceleration.

for my luck there is this on the code i am testing.

 

// Apply friction to Z
        else if ( NPC->client->ps.velocity[2] )
        {
            NPC->client->ps.velocity[2] *= OLON_VELOCITY_DECAY;

            if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
            {
                NPC->client->ps.velocity[2] = 0;
            }
        }
        // Apply friction
        else if ( NPC->client->ps.velocity[0] )
        {
            NPC->client->ps.velocity[0] *= OLON_DECAY;

            if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
            {
                NPC->client->ps.velocity[0] = 0;
            }
        }
        else if ( NPC->client->ps.velocity[1] )
        {
            NPC->client->ps.velocity[1] *= OLON_DECAY;
            if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
            {
                NPC->client->ps.velocity[1] = 0;
            }
        }
so there is also a deceleration movement (but too weak for moment respect to acceleration movement) and so after a lot of time fighters normalize their speed and return to fight as fighters... and not as crazy comets. XD 

 

About the autoforceforward.

i am trying to do that now:

the Olon_idle calls this function

 

float speed;
    vec3_t    forward;
     //Get your current forward dir
    AngleVectors( NPC->client->renderInfo.eyeAngles, forward, NULL, NULL );
   //or just this - not sure why you're trying to get the NPC's eye angles on a vehicle above?  That would be more for a player controlling a vehicle
    //AngleVectors( self->currentAngles, forward, right, NULL );
    ucmd.forwardmove = NPC->client->forced_forwardmove;
    speed = NPCInfo->stats.walkSpeed;
    //Set speed to walkspeed or runspeed or whatever you want
    //speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer;
     //set velocity directly - note that this *adds* the new velocity to the old one, meaning it will keep accelerating - only do this if the speed hasn't reached max or you're changing direction
    VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
        //You can just do this, but this will go to the new velocity immediately - you'd have to smooth out acceleration yourself
    //VectorMultiply( forward, speed, NPC->client->ps.velocity );
    NPC->client->ps.pm_time = 500;
    NPC->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
}    
 

i pasted line you suggest me and now i want to test.

if works, i will fix next for have obtimal result. (also my crazy dogfight lol)

also, i am sorry for my sadly post of the other day. i take a lot of time of figure that NPC move just because AI imitated player movement. i never expected that and this mechanic is very interesting.

so, basiclaly, NPCs are like puppet moved by engines. and engine use virtual keyboard and joypand with ucmds for reproducing the player movement...now i understand why forceforward not work until now. 

>.<

now i test my little code. i will let you know the progress. Thanks!

Link to comment

@@MGummelt it works!!! after two years of headaches! thanks ! thanks 1 thousand time!!! :D

 

i need just to put on the equation some decay value like the "apply friction" and the decay int of Sentry Ai because you're right!

VectorMa create a logaritmic acceleration... but is also necessary for make all workings. so they need really a brake inside the code because i spawned fifty fighters with consolles and they go forward, boost up, accelerate in so crazy way that also if they seek me as enemy they fly for all map and skybox like crazy comets and explodes by impact damage with skybox to a mad speed! ROTFL!!!

it's funny to see but it works! now i need just to debug, finding the just values for making a decent flight :)

i am sure at the end i'll do that. and after that i can think to the player client fighter code and user UI HUD.

Because NPC is almost done.

thanks again!! :D

MGummelt and Noodle like this
Link to comment

@@Asgarath83 - CONGRATULATIONS!!! :winkthumb:

Thanks! but without MGummelt suggest i should again on brainstorming mode :3

i suppose i can fix crazy acceleration with

if NPC->client->ps.velocity > 1

NPC->client->ps.velocity = 1 after VectorMA. this should avoid to overflow the default speed value.

iif not, i can also try the ps.velocity < 1 ps.velocity = 0 by fighter_hunt or the decay multiplier with 0.(number.)f for a gradual decelerating. 

 

Instead about the client i thinks is sufficient:

- NPC and client starfighters scaled to 50 as modelsca on NPC files. that fix the camera problem with the "giant" tiefighter model vehicle.

moving the Playable fighter: well, i not know if is possible to use "playermodel sentry" or "playermodel remote" for see if player can move these droids class. if is possible should not be problem to allow my fighter class to be moved also by player (and adding forceforward command by icarus script at start of level player too can have the autoforward propulsion as rogue squadron 3d)

if instead droids are statics with players u.cmd (now i not remember, i need to test the default sentry and remote_sp NPC for see if player can move.) i can just set the player fighter fly like a rockettrooper fly (with some little edit on yawangle of flystart) and changing jetpack sound on the fighter engine sound loop and should be okay.)

After that, all it need is to customize UI (like atst HUD) for the fighter class and the works is done and i will share the code.)

Thanks again MGummelt, really :)

Archangel35757 likes this
Link to comment

@@MGummelt 

Hello There! 

I am typing here as the one of the MB2 maps creator now. I want ask you for help but i dont know if you will know the answer. 

In MP there is a strange bug - Player models can go through the walls, floor that are crateded with patch meshes (not brushes) in the map. There is some serious collision error. I mostly happens when player is using the special jump attack both dual and staff sabers. 

Player is getting through the patches like a ghost. For mods like MB2 it can be game breaking and it can change the overall gaming experience. As far as i know - this issue is not MB2 only. It happens in the default verion of jamp.

Link to comment

@@MGummelt hello there.

sorry if i stress again. i have some little bug again to fix on my fighters. not much deals. i was wondering if you can give me some suggest related to this.

the first problem reguard that: dogfight against fighters TEAM_PLAYER agains TEAM_ENEMY npcs. this problem occurs also if you try to create a friendly rockettrooper NPC and fight NPC rockettrooper. basiclaly, they shoot theirself on the air and their fight with repeater. during fight they have the little problem they do fly manouvre that ... in the course of some minutes, they fly ever up, up, up and more up, until they reach the skybox or the "roof" of the level map. this is not much good to see for a starfightning because in a battle NPC will lost on the Sky. i found the incriminated functions coming by AI_SENTRY and AI_REMOTE .CPP is the maintainheight function.

This:

 

void Olon_MaintainHeight( void )
{    
    float    dif;

    // Update our angles regardless
    ////////////////////////////////////////    
    NPC_FaceEnemy( qtrue );
    NPC_UpdateAngles( qtrue, qtrue );

    if ( NPC->client->ps.velocity[2] )
    {
        NPC->client->ps.velocity[2] *= OLON_DECAY;

        if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
        {
            NPC->client->ps.velocity[2] = 0;
        }
    }
    // If we have an enemy, we should try to hover at or a little below enemy eye level
    if ( NPC->enemy )
    {
        // FIXA QUESTA FUNZIONE E' QUA CHE SI SCAZZANO I CACCIA E IL COMBAT TENTE A MUOVERSI VEROS L'ALTO.
        //SENTRY
        // Find the height difference
        dif = (NPC->enemy->currentOrigin[2]+NPC->enemy->maxs[2]) - NPC->currentOrigin[2];
        // cap to prevent dramatic height shifts
        if ( fabs( dif ) > 8 )
        {
            if ( fabs( dif ) > OLON_HOVER_HEIGHT )
            {
                dif = ( dif < 0 ? -24 : 24 );
            }

            NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
        }
        //REMOTE
        if (TIMER_Done( NPC, "OlonheightChange"))
        {
            TIMER_Set( NPC,"OlonheightChange",Q_irand( 1000, 3000 ));

            // Find the height difference
            dif = (NPC->enemy->currentOrigin[2] +  Q_irand( 0, NPC->enemy->maxs[2]+8 )) - NPC->currentOrigin[2];

            // cap to prevent dramatic height shifts
            if ( fabs( dif ) > 2 )
            {
                if ( fabs( dif ) > 24 )
                {
                    dif = ( dif < 0 ? -24 : 24 );
                }
                dif *= 10;
                NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
                NPC->fx_time = level.time;
                //G_Sound( NPC, G_SoundIndex("sound/chars/Olon/misc/hiss.wav"));
            }
        }
    }
    else
    {
        //REMOTE
        gentity_t *goal = NULL;

        if ( NPCInfo->goalEntity )    // Is there a goal?
        {
            goal = NPCInfo->goalEntity;
        }
        else
        {
            goal = NPCInfo->lastGoalEntity;
        }

        if (goal)
        {
            dif = goal->currentOrigin[2] - NPC->currentOrigin[2];

            //REMOTE
            if ( fabs( dif ) > 24 )
            {
                dif = ( dif < 0 ? -24 : 24 );
                NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
            }
            //SENTRY
            if ( fabs( dif ) > OLON_HOVER_HEIGHT )
            {
                ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 );
                
            }
            else
            {
                if ( NPC->client->ps.velocity[2] )
                {
                    NPC->client->ps.velocity[2] *= OLON_VELOCITY_DECAY;

                    if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
                    {
                        NPC->client->ps.velocity[2] = 0;
                    }
                }
            }
        }
        // Apply friction to Z
        else if ( NPC->client->ps.velocity[2] )
        {
            NPC->client->ps.velocity[2] *= OLON_VELOCITY_DECAY;

            if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
            {
                NPC->client->ps.velocity[2] = 0;
            }
        }
        // Apply friction
        else if ( NPC->client->ps.velocity[0] )
        {
            NPC->client->ps.velocity[0] *= OLON_DECAY;

            if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
            {
                NPC->client->ps.velocity[0] = 0;
            }
        }
        else if ( NPC->client->ps.velocity[1] )
        {
            NPC->client->ps.velocity[1] *= OLON_DECAY;
            if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
            {
                NPC->client->ps.velocity[1] = 0;
            }
        }
    }
}

 

 

 

but if i disabled this line the fighters lost also their flight manouvre of dogfight and they fight simply silly fly 'round enemy target, like a seeker droid.

the problem is caused by chunks of code that force the enemy fight to try ever to be "at the same height of eyes height of enemy models. "

i merged up remoter and sentry question for doing this code.

the problem is HERE:

 

 

  // If we have an enemy, we should try to hover at or a little below enemy eye level
    if ( NPC->enemy ) blablabla
and is caused by the fab functions.

if disable the sentry code field i get by the sentry the problem is strongly reduced with remote parameters of fabs flight by is still again present, i not understand much this kind of expression:

 

dif = (NPC->enemy->currentOrigin[2]+NPC->enemy->maxs[2]) - NPC->currentOrigin[2];
        // cap to prevent dramatic height shifts
        if ( fabs( dif ) > 8 )
        {
            if ( fabs( dif ) > OLON_HOVER_HEIGHT )
            {
                dif = ( dif < 0 ? -24 : 24 );
            }

            NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;

 

can you explain a lot how works exaclty fabs and difs here?

there is some way to fix this for preserve this kind of movement removing this problem of the fighter NPC shifting to Up during a dogfight?

and there is also some better code that i can use for fighter movement during a dogfights? here is defined all my npc fighters flight movements when they have a goal or a enemy. is nice to see on a combat into a map but is again alot far for a true dogfights of games like Xwing alliance or rogue squadron3d , there is any way to improve that for create a nice battle against NPCs?  this is the last tecnical problem of my AI.

@@Archangel35757 can you give me an hand too to manage this? should be great a better dogfight code of that. :3

Link to comment

I just went through this whole thread. I don't have any programming skills, but making skins for JKO helped a lot with learning to use photoshop and getting interested into game design in general. It's pretty cool to see a game dev reaching out to us humble modders. Also very inspiring to know you started as a modder yourself.

 

I don't have any questions, just wanted to say this.

MGummelt and Langerd like this
Link to comment

@@MGummelt it works!!! after two years of headaches! thanks ! thanks 1 thousand time!!! :D

 

i need just to put on the equation some decay value like the "apply friction" and the decay int of Sentry Ai because you're right!

VectorMa create a logaritmic acceleration... but is also necessary for make all workings. so they need really a brake inside the code because i spawned fifty fighters with consolles and they go forward, boost up, accelerate in so crazy way that also if they seek me as enemy they fly for all map and skybox like crazy comets and explodes by impact damage with skybox to a mad speed! ROTFL!!!

it's funny to see but it works! now i need just to debug, finding the just values for making a decent flight :)

i am sure at the end i'll do that. and after that i can think to the player client fighter code and user UI HUD.

Because NPC is almost done.

thanks again!! :D

 

Awesome, glad to hear it!  Yeah, direct control over velocity is probably best for what you're trying to do.  If you want to see an example of how we make objects head to a target using velocity, looking at any homing missile code in Jedi.  And example is rocketThink() in g_weapon.cpp.  I pasted below, removing some stuff to simplify it to the important parts:

//---------------------------------------------------------
void rocketThink( gentity_t *ent )
//---------------------------------------------------------
{
	vec3_t newdir, targetdir, 
			up={0,0,1}, right; 
	vec3_t	org;
	float dot, dot2;

	if ( ent->enemy && ent->enemy->inuse )
	{

>>Here we get the old velocity of the rocket - if it's got spawnflag 1, we use its custom specified speed, otherwise we use the standard constant rocket speed
		float vel = (ent->spawnflags&1)?ent->speed:ROCKET_VELOCITY;
>>This is how much it "homes" or tracks the target - I think we used the "angle" field as a multiplier on how tightly the rocket could turn.
		float newDirMult = ent->angle?ent->angle*2.0f:1.0f;
		float oldDirMult = ent->angle?(1.0f-ent->angle)*2.0f:1.0f;

>>Important part:
>>Get the center of the target - some things have origins at their "feet", not their center
		VectorCopy( ent->enemy->currentOrigin, org );
		org[2] += (ent->enemy->mins[2] + ent->enemy->maxs[2]) * 0.5f;
>>This gets the direction from from the current position of the rocket to the target
		VectorSubtract( org, ent->currentOrigin, targetdir );
>>Turns the full vector above to a direction (normalized to a scale of 1)
		VectorNormalize( targetdir );

>>Here we need to figure out how much we need to turn from our current direction (ent->movedir) to our desired direction (that we just calculated above)
		// Now the rocket can't do a 180 in space, so we'll limit the turn to about 45 degrees.
		dot = DotProduct( targetdir, ent->movedir );

		// a dot of 1.0 means right-on-target.
>>Dot product is a normalized measure of the difference in angle between two directions - 1.0 is they both are going in the same direction, 0.0 is they're perpendicular, -1.0 means they're opposite directions.
>>Here we're checking to see if the target is "behind us" (more then 90 degrees off to the side)
		if ( dot < 0.0f )
		{	
>>Start turning us around - to the right or left, depending on which side the enemy is on
			// Go in the direction opposite, start a 180.
			CrossProduct( ent->movedir, up, right );
			dot2 = DotProduct( targetdir, right );

			if ( dot2 > 0 )
			{	
				// Turn 45 degrees right.
				VectorMA( ent->movedir, 0.3f*newDirMult, right, newdir );
			}
			else
			{	
				// Turn 45 degrees left.
				VectorMA(ent->movedir, -0.3f*newDirMult, right, newdir);
			}

			// Yeah we've adjusted horizontally, but let's split the difference vertically, so we kinda try to move towards it.
			newdir[2] = ( (targetdir[2]*newDirMult) + (ent->movedir[2]*oldDirMult) ) * 0.5;

			// slowing down coupled with fairly tight turns can lead us to orbit an enemy..looks bad so don't do it!
			//vel *= 0.5f;
		}
>>These handle if it's more in front of us - turning harder the more in front of us it is
		else if ( dot < 0.70f )
		{	
			// Still a bit off, so we turn a bit softer
			VectorMA( ent->movedir, 0.5f*newDirMult, targetdir, newdir );
		}
		else
		{	
			// getting close, so turn a bit harder
			VectorMA( ent->movedir, 0.9f*newDirMult, targetdir, newdir );
		}

>>This adds some randomness - the higher the ent->random, the more randomness ("drunkenness") there will be in the velocity - this could be done only every certain interval if desired, instead of every think/update
		// add crazy drunkenness
		for ( int i = 0; i < 3; i++ )
		{
			newdir[i] += crandom() * ent->random * 0.25f;
		}

>>This makes the randomness go away after a while - so the rocket will start "drunken", but then straighten itself out after a while
		// decay the randomness
		ent->random *= 0.9f;

>>This makes the homing rocket less likely to miss and pass the target - using an old Quake multiplayer trick - don't shoot the rocket at the player's center, shoot at their feet so that even if you miss them, you'll hit the floor and blow up close enough to damage them
		if ( ent->enemy->client
			&& ent->enemy->client->ps.groundEntityNum != ENTITYNUM_NONE )
		{//tracking a client who's on the ground, aim at the floor...?
			// Try to crash into the ground if we get close enough to do splash damage
			float dis = Distance( ent->currentOrigin, org );

			if ( dis < 128 )
			{
				// the closer we get, the more we push the rocket down, heh heh.
				newdir[2] -= (1.0f - (dis / 128.0f)) * 0.6f;
			}
		}

>>Back to the important stuff - now that we've got our new direction (calculated from our old direction and target direction and how much we can actually turn this think/update), normalize it to a scale of 1 so it's a direction, not a velocity
		VectorNormalize( newdir );

>>Take the new direction, scale it up to half our full speed and use that as our new velocity (I think we used half speed because otherwise it could miss targets too easily)
		VectorScale( newdir, vel * 0.5f, ent->s.pos.trDelta );
		VectorCopy( newdir, ent->movedir );
		SnapVector( ent->s.pos.trDelta );			// save net bandwidth
		VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
		ent->s.pos.trTime = level.time;
	}

>>Set the time of the next update
	ent->nextthink = level.time + ROCKET_ALT_THINK_TIME;	// Nothing at all spectacular happened, continue.
	return;
}
Link to comment

@@MGummelt 

 

Hello There! 

 

I am typing here as the one of the MB2 maps creator now. I want ask you for help but i dont know if you will know the answer. 

 

In MP there is a strange bug - Player models can go through the walls, floor that are crateded with patch meshes (not brushes) in the map. There is some serious collision error. I mostly happens when player is using the special jump attack both dual and staff sabers. 

 

Player is getting through the patches like a ghost. For mods like MB2 it can be game breaking and it can change the overall gaming experience. As far as i know - this issue is not MB2 only. It happens in the default verion of jamp.

 

Hmm, I'm not sure what this is, I wasn't a map designer or tech programmer.

 

Are they passing through the "front" side of the patch mesh or the back?

 

Does playerclipping the patch mesh fix it?

Link to comment

@@MGummelt hello there.

sorry if i stress again. i have some little bug again to fix on my fighters. not much deals. i was wondering if you can give me some suggest related to this.

the first problem reguard that: dogfight against fighters TEAM_PLAYER agains TEAM_ENEMY npcs. this problem occurs also if you try to create a friendly rockettrooper NPC and fight NPC rockettrooper. basiclaly, they shoot theirself on the air and their fight with repeater. during fight they have the little problem they do fly manouvre that ... in the course of some minutes, they fly ever up, up, up and more up, until they reach the skybox or the "roof" of the level map. this is not much good to see for a starfightning because in a battle NPC will lost on the Sky. i found the incriminated functions coming by AI_SENTRY and AI_REMOTE .CPP is the maintainheight function.

This:

 

dif = (NPC->enemy->currentOrigin[2]+NPC->enemy->maxs[2]) - NPC->currentOrigin[2];

        // cap to prevent dramatic height shifts

        if ( fabs( dif ) > 8 )

        {

            if ( fabs( dif ) > OLON_HOVER_HEIGHT )

            {

                dif = ( dif < 0 ? -24 : 24 );

            }

 

            NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;

 

can you explain a lot how works exaclty fabs and difs here?

there is some way to fix this for preserve this kind of movement removing this problem of the fighter NPC shifting to Up during a dogfight?

and there is also some better code that i can use for fighter movement during a dogfights? here is defined all my npc fighters flight movements when they have a goal or a enemy. is nice to see on a combat into a map but is again alot far for a true dogfights of games like Xwing alliance or rogue squadron3d , there is any way to improve that for create a nice battle against NPCs?  this is the last tecnical problem of my AI.

@@Archangel35757 can you give me an hand too to manage this? should be great a better dogfight code of that. :3

 

fabs() is just a function to turn a negative number into a positive number (f = float, abs = "absolute value).

 

Dif is the difference in height between the top of the enemy and the bottom of me (remember, this was written for NPCs, not vehicles - so this is keeping the height of the flying NPC above the head of the enemy, which it assumes is on the ground - the flying NPCs were never programmed to be able to fight other flying NPCs).

 

The obvious issue, here, is that both of them are trying to fly just above the head of the other, so they both just keep going up and up in a feedback loop.

 

You could make it so that the fighters are just trying to stay at about the same level as each other (same Z-height, within some reasonable tolerance, like +/- 64 units or so).

 

But, really, if they're fighting in 3D space and able to pitch up/down to track their enemy, you shouldn't need this at all.  Just angle them towards their enemy and make them chase them.  No height matching is needed.

Link to comment

I just went through this whole thread. I don't have any programming skills, but making skins for JKO helped a lot with learning to use photoshop and getting interested into game design in general. It's pretty cool to see a game dev reaching out to us humble modders. Also very inspiring to know you started as a modder yourself.

 

I don't have any questions, just wanted to say this.

 

Thanks, Raschu!

Asgarath83 and Raschu like this
Link to comment

fabs() is just a function to turn a negative number into a positive number (f = float, abs = "absolute value).

 

Dif is the difference in height between the top of the enemy and the bottom of me (remember, this was written for NPCs, not vehicles - so this is keeping the height of the flying NPC above the head of the enemy, which it assumes is on the ground - the flying NPCs were never programmed to be able to fight other flying NPCs).

 

The obvious issue, here, is that both of them are trying to fly just above the head of the other, so they both just keep going up and up in a feedback loop.

 

You could make it so that the fighters are just trying to stay at about the same level as each other (same Z-height, within some reasonable tolerance, like +/- 64 units or so).

 

But, really, if they're fighting in 3D space and able to pitch up/down to track their enemy, you shouldn't need this at all.  Just angle them towards their enemy and make them chase them.  No height matching is needed.

yeah a auto levelling code to match height of enemy was useful for some kind of aircraft with static flight like assault chopters i guess, but is is not the case. So they need just to chase each others with free pitch fly along the forward vector axis... mmm i think also NPC_faceenemy qtrue is unuseful in this function. i can set NPC_faceenemy of the Hunt function, so if They chasing a foe, they face him (and this have sense) but on maintain height \ flight function so is not necessary or use fabs for movement. on the remote movement it give a lot of better estethical flight manouvre, but also create a redundance loop that force enemy to go up and up. now i understand. mmm dif a parameter related to the "height" of the enemy NPC... interessing too. i see that in a part of code dif is multiplied for ten dif*=10 in this case NPC should fly at maximum height of ten times the height of opponent i guess... 

so for maintain height i deactivate just and i take only setting for a costant fly movement.

the faceenemy line i cut inside the fighter_hunt code. well at this point...

mmmm if i get hunt + autoforward propulsion and deactivate the fabs stuff, fighters tecnically SHOULD chase each other. when they reach enemy the autoforward movement force him to go over enemy, but their are also chasing the enemy and tracking and so... okay this should create a behavour like homing missile... it's a reasonable behavour for starfighters.

i wanna to try this and see what happened as result. i these days i am improving the flight and dogfight manouvre. is the hardest part. thanks again for explanation! :3

Link to comment

fabs() is just a function to turn a negative number into a positive number (f = float, abs = "absolute value).

 

Dif is the difference in height between the top of the enemy and the bottom of me (remember, this was written for NPCs, not vehicles - so this is keeping the height of the flying NPC above the head of the enemy, which it assumes is on the ground - the flying NPCs were never programmed to be able to fight other flying NPCs).

 

The obvious issue, here, is that both of them are trying to fly just above the head of the other, so they both just keep going up and up in a feedback loop.

 

You could make it so that the fighters are just trying to stay at about the same level as each other (same Z-height, within some reasonable tolerance, like +/- 64 units or so).

 

But, really, if they're fighting in 3D space and able to pitch up/down to track their enemy, you shouldn't need this at all.  Just angle them towards their enemy and make them chase them.  No height matching is needed.

mmm just a little question, how can i create a pitch up and down \ loop movement using fabs or vectors when they chase their opponents? i tryed without fabs and they hunts theirselves forward and backward, they go ahead and behind, forward and back, forward and back, here and there lol. running very fast, this is fun for some minutes but after a lot become silly. there is some way i can get more "vivacity" to the flight of fighters? or some code block or part of JKA that can give me an help on that?

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...