Asgarath83 Posted February 27, 2017 Posted February 27, 2017 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
Solution Asgarath83 Posted February 28, 2017 Author Solution Posted February 28, 2017 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. 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now