Jump to content

Switching weapon by saber to...


Go to solution Solved by Asgarath83,

Recommended Posts

Hello to alls, i am sorry for disturb but really is an entire week then i try in every way possible to do that and i have not success...

basically...

i am working on new AI for NPC of SP.

the new AI act like boba fett ai, basically, but without flamethrower attack. is an improved version of AI that i builded following suggest of Dusty, he has given to me with very kindness. ^_^

what is the problem... well basically this is an advaned AI for NPC. NPC class that use these AI act very smartly

- they dodge lightsaber if you try to cut they with sword.

- they randomly switch weapons get into NPC file on ext_data related to NPC that using this AI.

- they randomly use altfire.

- they can use force power lightning, grip and drain when they shoots, so you can create also advanced reborn or cultist shooter that fight very hard to defeat.

- If player is close on a distance lower of 512 map unit, and if a NPC is equipped with a saber on NPC file as weapon, it equip immediatly saber for fight player.

 

there is only one step that not work: i want that: if the player is suffcient far by NPC and NPC is using a saber a as weapon, and NPC have also shooting weapons into his NPC file, he switch by saber to a random shoot weapon present in NPC file. unfortunely, this last feature not works. the NPC still ostinated using saber chasing player with this weapon, also is player is pretty far or is in another platform or cliff or over an abyss. i think this is little stupid, because if i have a sword and a rifle, and i need to fight with someone very far from me, why i need to use the sword when i can shoot with rifle? this is the reason of my frustration.

 

i paste here the incriminated code that cause these issue. i think i need to edit the

"else if (enemyInShootRange2)" brank field for fixing that but i not know exactly how.

also, i have a little question: where is the difference by ent->s.weapon and ent->client->ps.weapon inside the code? what does one? what does the other exactly?

thanks to any answer.

@@Dusty

@@MGummelt

 

 

void    NPC_TacticsSelect()
{
    // Don't Change Tactics For A Little While
    //------------------------------------------
    TIMER_Set(NPC, "NPC_TacticsSelect", Q_irand(8000, 15000));
    int        nextState = NPCInfo->localState;


    // Get Some Data That Will Help With The Selection Of The Next Tactic
    //--------------------------------------------------------------------
    bool    enemyAlive2            = (NPC->enemy->health>0);
    float    enemyDistance2        = Distance(NPC->currentOrigin, NPC->enemy->currentOrigin);
    bool    enemyCloseRange2    = (enemyDistance2<NPC_SHOOTRANGEMIN);
    bool    enemyInShootRange2    = (enemyDistance2>NPC_SHOOTRANGEMIN && enemyDistance2<NPC_SHOOTRANGEMAX);
    bool    enemyRecentlySeen2    = NPC_CanSeeEnemy(NPC);
    
    if (!enemyAlive2)
    {
        nextState = NPC_MAGIC;
    }
    else if (enemyCloseRange2)// Enemy is pretty near, so use Saber!  
    {
        if ( HaveWeapon(NPC, WP_SABER ))// If Enemy is near, and NPC have a sword in his inventory, using that sword.
        {
            nextState = NPC_FENCER;
        }
                
        // If It's Been Long Enough Since Our Last Flame Blast, Try To Torch The Enemy
        //-----------------------------------------------------------------------------
        //if (TIMER_Done(NPC, "nextFlameDelay"))
        // DUSTY ADD
        else if (TIMER_Done(NPC, "nextFlameDelay") && (NPC->client->NPC_class == CLASS_BOBAFETT || NPC->client->NPC_class == CLASS_MANDA))
        {
            nextState = NPC_GLYPHIC;
        }

        // Otherwise, He's Probably Too Close, So Try To Get Clear Of Him
        //----------------------------------------------------------------
        else
        {
            nextState = NPC_MAGIC;
        }
    }
    else if (enemyInShootRange2)// Enemy is distance so use shoot atk
    {
          
    if ( HaveWeapon(NPC, WP_SABER ) || HaveWeapon(NPC, WP_MELEE ) ||
        HaveWeapon(NPC, WP_TUSKEN_STAFF ) || HaveWeapon(NPC, WP_STUN_BATON ))
        // You are a warrior and have a sword, but enemy is far and at shoot distance
        // Put away the sword and use shoot weapons!  
    {
        if ( HaveWeapon(NPC, WEAPS_BLASTER ))// Enemy is distance, you are a wizard? shoot with magic
        {
            nextState = NPC_MAGIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVY ))// Enemy is distance? You are an Hunter? use glyphic weapons
        {
            nextState = NPC_GLYPHIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_LIGHTBLASTER ))// You are an archer? use arrows!  
        {
            nextState = NPC_ARROWS;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVYBLASTER ))// You are a Necromancer or a chieric? Use this attacks!  
        {
            nextState = NPC_NEC_HOLY;
        }    
    }    
    else
    { // If you have shooting weapons, use that!
        if ( HaveWeapon(NPC, WEAPS_BLASTER ))// Enemy is distance, you are a wizard? shoot with magic
        {
            nextState = NPC_MAGIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVY ))// Enemy is distance? You are an Hunter? use glyphic weapons
        {
            nextState = NPC_GLYPHIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_LIGHTBLASTER ))// You are an archer? use arrows!  
        {
            nextState = NPC_ARROWS;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVYBLASTER ))// You are a Necromancer or a chieric? Use this attacks!  
        {
            nextState = NPC_NEC_HOLY;
        }
        else if ( HaveWeapon(NPC, WEAPS_MELEE ))// this is really stupid but okay...  
        {
            nextState = NPC_WARRIOR;
        }
    }
        
    }
    else if (!enemyInShootRange2 && !enemyCloseRange2) // Enemy is pretty far, try distance atk
    {
        // If It's Been Long Enough Since Our Last Flame Blast, Try To Torch The Enemy
        //-----------------------------------------------------------------------------
        //if (TIMER_Done(NPC, "nextFlameDelay"))
        // DUSTY ADD
        if ( HaveWeapon(NPC, WP_SABER ) || HaveWeapon(NPC, WP_MELEE ) ||
        HaveWeapon(NPC, WP_TUSKEN_STAFF ) || HaveWeapon(NPC, WP_STUN_BATON ))
        // You are a warrior and have a sword, but enemy is far and at shoot distance
        // Put away the sword and use shoot weapons!  
    {
        if ( HaveWeapon(NPC, WEAPS_BLASTER ))// Enemy is distance, you are a wizard? shoot with magic
        {
            nextState = NPC_MAGIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVY ))// Enemy is distance? You are an Hunter? use glyphic weapons
        {
            nextState = NPC_GLYPHIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_LIGHTBLASTER ))// You are an archer? use arrows!  
        {
            nextState = NPC_ARROWS;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVYBLASTER ))// You are a Necromancer or a chieric? Use this attacks!  
        {
            nextState = NPC_NEC_HOLY;
        }    
    }    
    else
    { // If you have shooting weapons, use that!
        if ( HaveWeapon(NPC, WEAPS_BLASTER ))// Enemy is distance, you are a wizard? shoot with magic
        {
            nextState = NPC_MAGIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVY ))// Enemy is distance? You are an Hunter? use glyphic weapons
        {
            nextState = NPC_GLYPHIC;
        }
        else if ( HaveWeapon(NPC, WEAPS_LIGHTBLASTER ))// You are an archer? use arrows!  
        {
            nextState = NPC_ARROWS;
        }
        else if ( HaveWeapon(NPC, WEAPS_HEAVYBLASTER ))// You are a Necromancer or a chieric? Use this attacks!  
        {
            nextState = NPC_NEC_HOLY;
        }
        else if ( HaveWeapon(NPC, WEAPS_MELEE ))// this is really stupid but okay...  
        {
            nextState = NPC_WARRIOR;
        }
    }
            
    
    }


    // Recently Saw The Enemy, Time For Some Good Ole Fighten!
    //---------------------------------------------------------
    else if (enemyRecentlySeen2)
    {
        // At First, Boba will prefer to use his blaster against the player, but
        //  the more times he is driven away (NPC->count), he will be less likely to
        //  choose the blaster, and more likely to go for the missile launcher
        //nextState = (!enemyInShootRange || Q_irand(0, NPC->count)<1)?(NPC_MAGIC):(NPC_FENCER);


    }

    // Hmmm...  Havn't Seen The Player In A While, We Might Want To Try Something Sneaky
    //-----------------------------------------------------------------------------------
    else
    {
        bool    SnipePointsNear = false;         // TODO
        bool    AmbushPointNear = false;         // TODO

        if (Q_irand(0, NPC->count)>0)
        {
            int        SniperPoint = NPC_FindCombatPoint(NPC->currentOrigin, 0, NPC->currentOrigin, CP_SNIPE|CP_CLEAR|CP_HAS_ROUTE|CP_TRYFAR|CP_HORZ_DIST_COLL, 0, -1);
            if (SniperPoint!=-1)
            {
                NPC_SetCombatPoint(SniperPoint);
                NPC_SetMoveGoal( NPC, level.combatPoints[SniperPoint].origin, 20, qtrue, SniperPoint );
                TIMER_Set(NPC, "PickNewSniperPoint", Q_irand(15000, 25000));
                SnipePointsNear = true;
            }
        }

        // DUSTY ADD
         //if (SnipePointsNear && TIMER_Done(NPC, "NPC_NoSniperTime"))
        if (SnipePointsNear && TIMER_Done(NPC, "NPC_NoSniperTime") && HaveWeapon(NPC, WP_DISRUPTOR))
        {
            TIMER_Set(NPC, "NPC_NoSniperTime", 120000);                // Don't snipe again for a while
            TIMER_Set(NPC, "NPC_TacticsSelect", Q_irand(35000, 45000));// More patience here
            nextState = NPC_ARROWS;
        }
        else if (AmbushPointNear)
        {
            TIMER_Set(NPC, "NPC_TacticsSelect", Q_irand(15000, 25000));// More patience here
            nextState = NPC_AMBUSHWAIT;
        }
        else
        {
            nextState = (!enemyInShootRange2 || Q_irand(0, NPC->count)<1)?(NPC_GLYPHIC):(NPC_ARROWS);
        }
    }



    // The Next State Has Been Selected, Now Change Weapon If Necessary
    //------------------------------------------------------------------
    // DUSTY ADD VERSION
    // The Next State Has Been Selected, Now Change Weapon If Necessary
     //------------------------------------------------------------------
    NPCInfo->localState = nextState;
    int weapon = 0;

    switch (NPCInfo->localState)
     {
    case NPC_FENCER:
        if (HaveWeapon(NPC, WP_SABER))
         {
            //NPC_Printf("NEW TACTIC: Sniper");
            NPC_ChangeWeapon(WP_SABER);
             break;
        }
        
    case NPC_MAGIC:    
        weapon = ChooseWeaponRandom(NPC, WEAPS_BLASTER);
        if (weapon)
        {
             //NPC_Printf("NEW TACTIC: Rifle");
            NPC_ChangeWeapon(weapon);
             break;
        }
    case NPC_NEC_HOLY:
        weapon = ChooseWeaponRandom(NPC, WEAPS_HEAVYBLASTER);
        if (weapon)
        {
             //NPC_Printf("NEW TACTIC: Rocket Launcher");
            NPC_ChangeWeapon(weapon);
             break;
        }
        
    case NPC_GLYPHIC: //kinda stuck at this point if doesn't have flamethrower
        //NPC_Printf("NEW TACTIC: Flame Thrower");
        weapon = ChooseWeaponRandom(NPC, WEAPS_HEAVY);
        if (weapon)
        {
             //NPC_Printf("NEW TACTIC: Rocket Launcher");
            NPC_ChangeWeapon(weapon);
             break;
        }
    case NPC_WARRIOR: //kinda stuck at this point if doesn't have flamethrower
        //NPC_Printf("NEW TACTIC: Flame Thrower");
        weapon = ChooseWeaponRandom(NPC, WEAPS_MELEE);
        if (weapon)
        {
             //NPC_Printf("NEW TACTIC: Rocket Launcher");
            NPC_ChangeWeapon(weapon);
             break;
        }
    case NPC_ARROWS: //kinda stuck at this point if doesn't have flamethrower
        //NPC_Printf("NEW TACTIC: Flame Thrower");
        weapon = ChooseWeaponRandom(NPC, WEAPS_LIGHTBLASTER);
        if (weapon)
        {
             //NPC_Printf("NEW TACTIC: Rocket Launcher");
            NPC_ChangeWeapon(weapon);
             break;
        }
        
    case NPC_AMBUSHWAIT:
        //NPC_Printf("NEW TACTIC: Ambush");
        weapon = ChooseWeaponRandom(NPC, WEAPS_ALL);
        if (weapon)
        {
             //NPC_Printf("NEW TACTIC: Rocket Launcher");
            NPC_ChangeWeapon(weapon);
             break;
        }
    }    
 }
 

NOTE: weapons are grouped into cathegories.

on weapons.h

 

////////////// WEAPON GROUPS
typedef enum {
WEAPS_ALL,
WEAPS_BLASTER,
WEAPS_HEAVY,// Glifiche
WEAPS_LIGHTBLASTER,// Arrows
WEAPS_HEAVYBLASTER,// nec Holy
WEAPS_EXPLOSIVE, // Explosive
WEAPS_MELEE, //Warrior
WEAPS_OTHER
} weaponGroup;

 

they are associated at int definitions on npc_combat.cpp:

 

qboolean WeaponInGroup(int weapon, int wpnGroup, int altFire = 0)
{//this and the funcs it calls do the heavy lifting for weapon grouping
    if ((heavyWeap(weapon) && wpnGroup == WEAPS_HEAVY) // Glifiche
        || (lightBlasterWeap(weapon) && wpnGroup == WEAPS_LIGHTBLASTER) // Arrows
        || (heavyBlasterWeap(weapon) && wpnGroup == WEAPS_HEAVYBLASTER) // nec Holy
        || (blasterWeap(weapon) && wpnGroup == WEAPS_BLASTER )// Magic  
        || ( meleeWeap(weapon) && wpnGroup == WEAPS_MELEE )  // Warrior
        || wpnGroup == WEAPS_ALL )
    {
            return qtrue;
    }
    return qfalse;
}

and they are groped in that way on g_weapons.cpp:

 

 

qboolean heavyWeap(int wp)//humans
{
    switch (wp) {
    case WP_CANNON:
    case WP_TUSKEN_RIFLE:
    case WP_BRYAR_PISTOL:
    case WP_BLOODGUN:
    case WP_THERMAL:
    case WP_TRIP_MINE:
    case WP_DET_PACK:
    case WP_EMPLACED_GUN:
        return qtrue;
    }

    return qfalse;
}

qboolean blasterWeap(int wp)//elementals
{
    switch (wp) {
    case WP_BLASTER_PISTOL:
    case WP_BLASTER:
    case WP_REPEATER:
    case WP_BOWCASTER:
    case WP_ROCKET_LAUNCHER:
    case WP_FLECHETTE:
    case WP_JAWA:
    case WP_POISON:
    case WP_CONCUSSION:
    case WP_DEMP2:
    case WP_NOGHRI_STICK:
    case WP_ATST_MAIN:
    case WP_ATST_SIDE:
        return qtrue;
    }

    return qfalse;
}

qboolean lightBlasterWeap(int wp)// Arrows
{
    switch (wp) {
    case WP_TUSKEN_RIFLE:
    case WP_DISRUPTOR:
    case WP_NOGHRI_STICK:
    case WP_BRYAR_PISTOL:
        return qtrue;
    }

    return qfalse;
}

qboolean heavyBlasterWeap(int wp)// Life&Necro
{
    switch (wp) {
    case WP_CONCUSSION:
    case WP_DEMP2:
        return qtrue;
    }

    return qfalse;
}

qboolean meleeWeap(int wp) // Melee fight
{
    switch (wp) {
    case WP_MELEE:
    case WP_STUN_BATON:
    case WP_TUSKEN_STAFF:
        return qtrue;
    }

    return qfalse;
}

// End Weapon categories

 

 

 

 

 

 

 

 

Link to comment
  • Solution

Nevermind, i found the problem: when a NPC go into NPC_FENCER state and use the saber when enemy is close, it's also called a function in NPC.cpp that set behavour state of NPC to defauit jedi state (turning off my AI ) . this is valid for all saberist classes and is the motivation because is so difficult to switch weapons in code between sabers and projectiles.

the problem is about the condition that set jedi behavour for all NPC equipped with WP_SABER. i fixed setting the condition for all NPC that give a saber and of a class different by the class when i am testing the AI. now is okay. and there is a perfect switch between ranged and sword attack. :D so the code i'm working is fine, but i need a little fix on npc.cpp for avoid this problem. also is a careful thing because there is the risk to deactivate AI for all saberist of other classes.

MGummelt likes this
Link to comment

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...