Asgarath83 Posted July 26, 2017 Author Posted July 26, 2017 drivable pretty far by working. when i spawn the "drivable" with npc tiefighter4 it follow player like a dog and is not usable...also bounding box is totally wrong...uff, i think i will take a break from that. i cannot solve the problems without an expert help.
Noodle Posted July 26, 2017 Posted July 26, 2017 uff, i think i will take a break from that. i cannot solve the problems without an expert help. It doesn't matter if you take a break, what matters is that now you know much more than you did when you started this
Asgarath83 Posted July 26, 2017 Author Posted July 26, 2017 It doesn't matter if you take a break, what matters is that now you know much more than you did when you started this well, i think is time to show my progress for moment. so i paste here the code edit. i hope someone can use that for some mod.almost can do some tiefighter nice boss for a end of a level or fighter NPC that chase and follow player in some canyon or in an open field shooting and bombard him.(just remove WP_POISON, BLOODGUN and WP_JAWA by stuff, is a my custom creation\ hacking)NPC file of tiefighters:first off, you need a tie fighter rigged to humanoid glm skeleton for a full working npc. is just necessary to import model on blender or max and rig all mesh to pelvis bone. bolt_l_hand, bolt_r_hand need to be placed into the muzzle flash bolt points of cannons. // Fighter class TieFighter // Test AI { playerModel tie weapon WP_BLOODGUN weapon WP_BRYAR_PISTOL weapon WP_JAWA weapon WP_POISON weapon WP_BLASTER_PISTOL weapon WP_BLASTER // weapon WP_DISRUPTOR weapon WP_DEMP2 weapon WP_BOWCASTER weapon WP_REPEATER weapon WP_FLECHETTE weapon WP_ROCKET_LAUNCHER weapon WP_THERMAL //d weapon WP_CONCUSSION // weapon WP_ATST_MAIN // weapon WP_ATST_SIDE FP_HEAL 0 FP_LEVITATION 0 FP_SPEED 0 FP_PUSH 0 FP_PULL 0 FP_TELEPATHY 0 FP_GRIP 0 FP_LIGHTNING 0 FP_RAGE 0 FP_PROTECT 0 FP_ABSORB 0 FP_DRAIN 0 FP_SEE 0 FP_SABERTHROW 0 FP_SABER_DEFENSE 0 FP_SABER_OFFENSE 0 FP_STUN 0 FP_HATE 0 FP_HEALOTHER 0 FP_CONTROLMIND 0 FP_WRACK 0 FP_FREEZE 0 FP_FORCEGLYPH 0 FP_STONEGLYPH 0 FP_FIREGLYPH 0 FP_WATERGLYPH 0 FP_DARKGLYPH 0 FP_WINDGLYPH 0 FP_SUNGLYPH 0 FP_HOLYGLYPH 0 FP_NECROGLYPH 0 FP_SOUNDGLYPH 0 forceRegenAmount 0 forcePowerMax 0 rank captain aggression 5 aim 5 intelligence 5 reactions 5 move 5 evasion 5 playerTeam TEAM_ENEMY enemyTeam TEAM_PLAYER class CLASS_FIGHTER health 1000 width 140 height 300 snd tie-fighter sndcombat tie-fighter sndextra tie-fighter sndjedi tie-fighter dismemberProbArms 0 dismemberProbHands 0 dismemberProbHead 0 dismemberProbLegs 0 dismemberProbWaist 0 } TieFighter1 // Test AI { playerModel tie // weapon WP_BLASTER_PISTOL // weapon WP_BRYAR_PISTOL // weapon WP_BLASTER weapon WP_DISRUPTOR weapon WP_ROCKET_LAUNCHER // weapon WP_REPEATER // weapon WP_FLECHETTE // weapon WP_BOWCASTER // weapon WP_DEMP2 // weapon WP_THERMAL // weapon WP_CONCUSSION // weapon WP_ATST_MAIN // weapon WP_ATST_SIDE FP_HEAL 0 FP_LEVITATION 0 FP_SPEED 0 FP_PUSH 0 FP_PULL 0 FP_TELEPATHY 0 FP_GRIP 0 FP_LIGHTNING 0 FP_RAGE 0 FP_PROTECT 0 FP_ABSORB 0 FP_DRAIN 0 FP_SEE 0 FP_SABERTHROW 0 FP_SABER_DEFENSE 0 FP_SABER_OFFENSE 0 FP_STUN 0 FP_HATE 0 FP_HEALOTHER 0 FP_CONTROLMIND 0 FP_WRACK 0 FP_FREEZE 0 FP_FORCEGLYPH 0 FP_STONEGLYPH 0 FP_FIREGLYPH 0 FP_WATERGLYPH 0 FP_DARKGLYPH 0 FP_WINDGLYPH 0 FP_SUNGLYPH 0 FP_HOLYGLYPH 0 FP_NECROGLYPH 0 FP_SOUNDGLYPH 0 forceRegenAmount 0 forcePowerMax 0 rank captain aggression 5 aim 5 intelligence 5 reactions 5 move 5 evasion 5 playerTeam TEAM_ENEMY enemyTeam TEAM_PLAYER class CLASS_FIGHTER health 1000 width 140 height 300 snd tie-fighter sndcombat tie-fighter sndextra tie-fighter sndjedi tie-fighter dismemberProbArms 0 dismemberProbHands 0 dismemberProbHead 0 dismemberProbLegs 0 dismemberProbWaist 0 } TieFighter2 // For player { playerModel tie weapon WP_BLOODGUN weapon WP_BRYAR_PISTOL weapon WP_JAWA weapon WP_POISON weapon WP_BLASTER_PISTOL weapon WP_BLASTER weapon WP_DISRUPTOR weapon WP_DEMP2 weapon WP_BOWCASTER weapon WP_REPEATER weapon WP_FLECHETTE weapon WP_ROCKET_LAUNCHER weapon WP_THERMAL //d weapon WP_CONCUSSION // weapon WP_ATST_MAIN // weapon WP_ATST_SIDE FP_HEAL 0 FP_LEVITATION 0 FP_SPEED 0 FP_PUSH 0 FP_PULL 0 FP_TELEPATHY 0 FP_GRIP 0 FP_LIGHTNING 0 FP_RAGE 0 FP_PROTECT 0 FP_ABSORB 0 FP_DRAIN 0 FP_SEE 0 FP_SABERTHROW 0 FP_SABER_DEFENSE 0 FP_SABER_OFFENSE 0 FP_STUN 0 FP_HATE 0 FP_HEALOTHER 0 FP_CONTROLMIND 0 FP_WRACK 0 FP_FREEZE 0 FP_FORCEGLYPH 0 FP_STONEGLYPH 0 FP_FIREGLYPH 0 FP_WATERGLYPH 0 FP_DARKGLYPH 0 FP_WINDGLYPH 0 FP_SUNGLYPH 0 FP_HOLYGLYPH 0 FP_NECROGLYPH 0 FP_SOUNDGLYPH 0 forceRegenAmount 0 forcePowerMax 0 rank captain aggression 5 aim 5 intelligence 5 reactions 5 move 5 evasion 5 playerTeam TEAM_PLAYER enemyTeam TEAM_ENEMY class CLASS_FIGHTER health 1000 width 140 height 300 snd tie-fighter sndcombat tie-fighter sndextra tie-fighter sndjedi tie-fighter dismemberProbArms 0 dismemberProbHands 0 dismemberProbHead 0 dismemberProbLegs 0 dismemberProbWaist 0 } TieFighter3 // For fun { playerModel tie weapon WP_EMPLACED_GUN FP_HEAL 0 FP_LEVITATION 0 FP_SPEED 0 FP_PUSH 0 FP_PULL 0 FP_TELEPATHY 0 FP_GRIP 0 FP_LIGHTNING 0 FP_RAGE 0 FP_PROTECT 0 FP_ABSORB 0 FP_DRAIN 0 FP_SEE 0 FP_SABERTHROW 0 FP_SABER_DEFENSE 0 FP_SABER_OFFENSE 0 FP_STUN 0 FP_HATE 0 FP_HEALOTHER 0 FP_CONTROLMIND 0 FP_WRACK 0 FP_FREEZE 0 FP_FORCEGLYPH 0 FP_STONEGLYPH 0 FP_FIREGLYPH 0 FP_WATERGLYPH 0 FP_DARKGLYPH 0 FP_WINDGLYPH 0 FP_SUNGLYPH 0 FP_HOLYGLYPH 0 FP_NECROGLYPH 0 FP_SOUNDGLYPH 0 forceRegenAmount 0 forcePowerMax 0 rank captain aggression 5 aim 5 intelligence 5 reactions 5 move 5 evasion 5 playerTeam TEAM_ENEMY enemyTeam TEAM_PLAYER class CLASS_FIGHTER health 1000 // width 140 // height 300 snd tie-fighter sndcombat tie-fighter sndextra tie-fighter sndjedi tie-fighter dismemberProbArms 0 dismemberProbHands 0 dismemberProbHead 0 dismemberProbLegs 0 dismemberProbWaist 0 } TieFighter4 // DRIVABLE For fun { playerModel tie FP_HEAL 0 FP_LEVITATION 0 FP_SPEED 0 FP_PUSH 0 FP_PULL 0 FP_TELEPATHY 0 FP_GRIP 0 FP_LIGHTNING 0 FP_RAGE 0 FP_PROTECT 0 FP_ABSORB 0 FP_DRAIN 0 FP_SEE 0 FP_SABERTHROW 0 FP_SABER_DEFENSE 0 FP_SABER_OFFENSE 0 FP_STUN 0 FP_HATE 0 FP_HEALOTHER 0 FP_CONTROLMIND 0 FP_WRACK 0 FP_FREEZE 0 FP_FORCEGLYPH 0 FP_STONEGLYPH 0 FP_FIREGLYPH 0 FP_WATERGLYPH 0 FP_DARKGLYPH 0 FP_WINDGLYPH 0 FP_SUNGLYPH 0 FP_HOLYGLYPH 0 FP_NECROGLYPH 0 FP_SOUNDGLYPH 0 forceRegenAmount 0 forcePowerMax 0 rank captain aggression 5 aim 5 intelligence 5 reactions 5 move 5 evasion 5 playerTeam TEAM_NEUTRAL enemyTeam TEAM_NEUTRAL class CLASS_FIGHTER health 1000 // width 140 // height 300 snd tie-fighter sndcombat tie-fighter sndextra tie-fighter sndjedi tie-fighter dismemberProbArms 0 dismemberProbHands 0 dismemberProbHead 0 dismemberProbLegs 0 dismemberProbWaist 0 } edit on code:teams.h - add on the end of class_t CLASS_FIGHTER, // Fighter npc class for air \ space battles. - generic fig q3_interace.cpp ENUM2STRING(CLASS_FIGHTER), on same enum value of classnpc.cpp - after boba fett definitation behavour else if ( NPC->client->NPC_class == CLASS_ROCKETTROOPER ) {//bounty hunter if ( RT_Flying( NPC ) || NPC->enemy != NULL ) { NPC_BSRT_Default(); } else { NPC_BehaviorSet_Stormtrooper( bState ); } G_CheckCharmed( NPC ); dontSetAim = qtrue; } else if ( NPC->client->NPC_class == CLASS_RANCOR || NPC->client->NPC_class == CLASS_SLUAGH || NPC->client->NPC_class == CLASS_BEAST ) { NPC_BehaviorSet_Rancor( bState ); } else if ( NPC->client->NPC_class == CLASS_SAND_CREATURE ) { NPC_BehaviorSet_SandCreature( bState ); } else if ( NPC->client->NPC_class == CLASS_WAMPA ) { NPC_BehaviorSet_Wampa( bState ); G_CheckCharmed( NPC ); } else if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH ) {//being forced to march NPC_BSDefault(); } else if ( NPC->client->ps.weapon == WP_TUSKEN_RIFLE ) { if ( (NPCInfo->scriptFlags & SCF_ALT_FIRE) ) { NPC_BehaviorSet_Sniper( bState ); G_CheckCharmed( NPC ); return; } else { NPC_BehaviorSet_Tusken( bState ); G_CheckCharmed( NPC ); return; } } else if ( NPC->client->ps.weapon == WP_TUSKEN_STAFF ) { NPC_BehaviorSet_Tusken( bState ); G_CheckCharmed( NPC ); return; } else if ( NPC->client->ps.weapon == WP_NOGHRI_STICK ) { NPC_BehaviorSet_Stormtrooper( bState ); G_CheckCharmed( NPC ); } else if ( NPC->client->NPC_class == CLASS_FIGHTER ) { Fighter_Update(); if (NPCInfo->surrenderTime) { Fighter_Flee(); } else { if (!Fighter_Tactics()) { if ( Fighter_Flying( NPC ) ) { NPC_BSFighter_Default(); } else { NPC_BehaviorSet_Jedi( bState ); } } dontSetAim = qtrue; } } npc_spawn.cpp - work in progress switch(ent->client->playerTeam) { case TEAM_PLAYER: //ent->flags |= FL_NO_KNOCKBACK; if ( ent->client->NPC_class == CLASS_SEEKER ) { ent->NPC->defaultBehavior = BS_DEFAULT; ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; ent->count = 30; // SEEKER shot ammo count return; } // An allied Fighter is drivable if you are sufficiently close! else if ( ent->client->NPC_class == CLASS_FIGHTER ) { ent->NPC->defaultBehavior = BS_DEFAULT; ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); // Spawn Floating until see an enemy! NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SWIM_IDLE1, SETANIM_FLAG_NORMAL ); NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); ent->client->ps.torsoAnimTimer = level.time + cg.time; } else if ( ent->client->NPC_class == CLASS_JEDI || ent->client->NPC_class == CLASS_KYLE || ent->client->NPC_class == CLASS_LUKE ) {//good jedi ent->client->enemyTeam = TEAM_ENEMY; if ( ent->spawnflags & JSF_AMBUSH ) {//ambusher ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS; ent->client->noclip = true;//hang } } else { if (ent->client->ps.weapon != WP_NONE && ent->client->ps.weapon != WP_SABER //sabers done above && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves { G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 ); } switch ( ent->client->ps.weapon ) { case WP_BRYAR_PISTOL://FIXME: new weapon: imp blaster pistol case WP_BLASTER_PISTOL: case WP_DISRUPTOR: case WP_BOWCASTER: case WP_REPEATER: case WP_DEMP2: case WP_FLECHETTE: case WP_ROCKET_LAUNCHER: case WP_CONCUSSION: default: break; case WP_THERMAL: case WP_BLASTER: //FIXME: health in NPCs.cfg, and not all blaster users are stormtroopers //ent->health = 25; //FIXME: not necc. a ST ST_ClearTimers( ent ); if ( ent->NPC->rank >= RANK_LT || ent->client->ps.weapon == WP_THERMAL ) {//officers, grenade-throwers use alt-fire //ent->health = 50; //ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; } } if ( ent->client->NPC_class == CLASS_PLAYER || ent->client->NPC_class == CLASS_VEHICLE || (ent->spawnflags & SFB_CINEMATIC) ) { ent->NPC->defaultBehavior = BS_CINEMATIC; } else { ent->NPC->defaultBehavior = BS_FOLLOW_LEADER; ent->client->leader = &g_entities[0];//player } break; case TEAM_NEUTRAL: if ( Q_stricmp( ent->NPC_type, "gonk" ) == 0 ) { // I guess we generically make them player usable ent->svFlags |= SVF_PLAYER_USABLE; // Not even sure if we want to give different levels of batteries? ...Or even that these are the values we'd want to use. switch ( g_spskill->integer ) { case 0: // EASY ent->client->ps.batteryCharge = MAX_BATTERIES * 0.8f; break; case 1: // MEDIUM ent->client->ps.batteryCharge = MAX_BATTERIES * 0.75f; break; default : case 2: // HARD ent->client->ps.batteryCharge = MAX_BATTERIES * 0.5f; break; } } break; if ( ent->client->NPC_class == CLASS_FIGHTER ) {// Drivable fighter vehicle ent->NPC->defaultBehavior = BS_CINEMATIC; ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); ent->svFlags |= SVF_PLAYER_USABLE; // HERE PAST CODE FOR MAKING DRIVABLE THE CLASS // Spawn Floating until see an enemy! NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SWIM_IDLE1, SETANIM_FLAG_NORMAL ); NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); ent->client->ps.torsoAnimTimer = level.time + cg.time; /*ent->e_ThinkFunc = thinkF_TieBomberThink; ent->e_ThinkFunc = thinkF_TieFighterThink; ent->nextthink = level.time + FRAMETIME; ent->attackDebounceTime = level.time + 1000; // We only take damage from a heavy weapon class missiles. ent->s.eFlags |= EF_LESS_ATTEN; extern void NPC_Fighter_Precache(void); //extern void NPC_PrecacheAnimationCFG( const char *NPC_type ); ent->s.modelindex = G_ModelIndex( "models/players/atst/model.glm" ); ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, "models/players/atst/model.glm", ent->s.modelindex, NULL_HANDLE, NULL_HANDLE, 0, 0 ); ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "model_root", qtrue ); ent->craniumBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cranium", qtrue ); //FIXME: need to somehow set the anim/frame to the equivalent of BOTH_STAND1... use to be that BOTH_STAND1 was the first frame of the glm, but not anymore //register my weapons, sounds and model RegisterItem( FindItemForWeapon( WP_ATST_MAIN )); //precache the weapon RegisterItem( FindItemForWeapon( WP_ATST_SIDE )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN )); //precache the weapon RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? G_SoundIndex( "sound/chars/fighter/fighter_hatch_open" ); G_SoundIndex( "sound/chars/fighter/fighter_hatch_close" ); NPC_Fighter_Precache(); ent->NPC_type = (char *)"atst"; //NPC_PrecacheAnimationCFG( ent->NPC_type ); //open the hatch gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "head_hatchcover", 0 ); ent->contents = CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; ent->max_health = ent->health; // cg_draw needs this G_SetOrigin( ent, ent->s.origin ); G_SetAngles( ent, ent->s.angles ); VectorCopy( ent->currentAngles, ent->s.angles2 ); gi.linkentity ( ent ); //FIXME: test the origin to make sure I'm clear? ent->e_UseFunc = useF_misc_atst_use; ent->svFlags |= SVF_PLAYER_USABLE; //make it able to take damage and die when you're not in it... //do an explosion and play the death anim, remove use func. ent->e_DieFunc = dieF_misc_atst_die;*/ } case TEAM_ENEMY: { ent->NPC->defaultBehavior = BS_DEFAULT; if ( ent->client->NPC_class == CLASS_SHADOWTROOPER && Q_stricmpn("shadowtrooper", ent->NPC_type, 13 ) == 0 || ent->client->NPC_class == CLASS_DARK || ent->client->NPC_class == CLASS_GOLEM_DARK || ent->client->NPC_class == CLASS_GOLEM_VOID || ent->client->NPC_class == CLASS_VOID || ent->client->NPC_class == CLASS_BLEED || ent->client->NPC_class == CLASS_SHIFTER || ent->client->NPC_class == CLASS_VAE ) {//FIXME: a spawnflag? Jedi_Cloak( ent ); } if( ent->client->NPC_class == CLASS_TAVION || ent->client->NPC_class == CLASS_ALORA || (ent->client->NPC_class == CLASS_REBORN && ent->client->ps.weapon == WP_SABER) || ent->client->NPC_class == CLASS_DESANN || ent->client->NPC_class == CLASS_SHADOWTROOPER ) { ent->client->enemyTeam = TEAM_PLAYER; if ( ent->spawnflags & JSF_AMBUSH ) {//ambusher ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS; ent->client->noclip = true;//hang } } else if( ent->client->NPC_class == CLASS_PROBE || ent->client->NPC_class == CLASS_REMOTE || ent->client->NPC_class == CLASS_INTERROGATOR || ent->client->NPC_class == CLASS_SENTRY || ent->client->NPC_class == CLASS_POLTER || ent->client->NPC_class == CLASS_BIRD || ent->client->NPC_class == CLASS_REAPER || ent->client->NPC_class == CLASS_DARK || ent->client->NPC_class == CLASS_LIGHT || ent->client->NPC_class == CLASS_FIRE || ent->client->NPC_class == CLASS_AIR || ent->client->NPC_class == CLASS_VOID ) { ent->NPC->defaultBehavior = BS_DEFAULT; ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; } else if ( ent->client->NPC_class == CLASS_FIGHTER ) { ent->NPC->defaultBehavior = BS_DEFAULT; ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); // Spawn Floating until see an enemy! NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SWIM_IDLE1, SETANIM_FLAG_NORMAL ); NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); ent->client->ps.torsoAnimTimer = level.time + cg.time; } else { if ( ent->client->ps.weapon != WP_NONE && ent->client->ps.weapon != WP_SABER//sabers done above && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves { G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 ); } // ALT FIRE CODE! switch ( ent->client->ps.weapon ) { case WP_BRYAR_PISTOL: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_BLOODGUN: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } if ( ent->client->NPC_class == CLASS_IMPERIAL && ent->NPC->rank >= RANK_LT_COMM && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves {//dual bloodgun pistols, so add the left-hand one, too G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handLBolt, 1 ); } break; case WP_CANNON: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_POISON: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_JAWA: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_BLASTER_PISTOL: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->client->NPC_class == CLASS_REBORN && ent->NPC->rank >= RANK_LT_COMM && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves {//dual blaster pistols, so add the left-hand one, too G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handLBolt, 1 ); } if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_DISRUPTOR: //Sniper //ent->NPC->scriptFlags |= SCF_ALT_FIRE;//FIXME: use primary fire sometimes? Up close? Different class of NPC? break; case WP_BOWCASTER: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_REPEATER: NPCInfo->scriptFlags |= SCF_PILOT; //machine-gunner if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_DEMP2: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_FLECHETTE: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; //shotgunner if ( !Q_stricmp( "stofficeralt", ent->NPC_type ) ) { //ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_ROCKET_LAUNCHER: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_CONCUSSION: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_THERMAL: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; //Gran, use main, bouncy fire // ent->NPC->scriptFlags |= SCF_ALT_FIRE; case WP_MELEE: NPCInfo->scriptFlags |= SCF_PILOT; if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; case WP_NOGHRI_STICK: break; default: case WP_BLASTER: //FIXME: health in NPCs.cfg, and not all blaster users are stormtroopers //FIXME: not necc. a ST NPCInfo->scriptFlags |= SCF_PILOT; ST_ClearTimers( ent ); if ( ent->NPC->rank >= RANK_COMMANDER && ent->s.weapon != WP_SABER ) {//commanders use alt-fire ent->NPC->scriptFlags |= SCF_ALT_FIRE; } if ( !Q_stricmp( "alora3", ent->NPC_type ) ) { ent->NPC->scriptFlags |= SCF_ALT_FIRE; } break; } } } break; default: ent->NPC->defaultBehavior = BS_DEFAULT; if ( ent->client->ps.weapon != WP_NONE && ent->client->ps.weapon != WP_MELEE && ent->client->ps.weapon != WP_SABER//sabers done above && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves { G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 ); } break; } if ( ent->client->NPC_class == CLASS_ATST || ent->client->NPC_class == CLASS_MARK1 ) // chris/steve/kevin requested that the mark1 be shielded also { ent->flags |= (FL_SHIELDED|FL_NO_KNOCKBACK); } // Set CAN FLY Flag for Navigation On The Following Classes //---------------------------------------------------------- if (ent->client->NPC_class==CLASS_PROBE || ent->client->NPC_class==CLASS_REMOTE || ent->client->NPC_class==CLASS_SEEKER || ent->client->NPC_class==CLASS_SENTRY || ent->client->NPC_class==CLASS_GLIDER || ent->client->NPC_class==CLASS_IMPWORKER || ent->client->NPC_class==CLASS_BOBAFETT || ent->client->NPC_class==CLASS_ROCKETTROOPER || ent->client->NPC_class == CLASS_BIRD || ent->client->NPC_class == CLASS_POLTER || ent->client->NPC_class == CLASS_REAPER || ent->client->NPC_class == CLASS_DARK || ent->client->NPC_class == CLASS_LIGHT || ent->client->NPC_class == CLASS_FIRE || ent->client->NPC_class == CLASS_VOID || ent->client->NPC_class == CLASS_FIGHTER ) { ent->NPC->scriptFlags |= SCF_NAV_CAN_FLY; } if (ent->client->NPC_class==CLASS_VEHICLE ) { Vehicle_Register(ent); } if ( ent->client->ps.stats[STAT_WEAPONS]&(1<<WP_SCEPTER) ) { if ( !ent->weaponModel[1] ) {//we have the scepter, so put it in our left hand if we don't already have a second weapon G_CreateG2AttachedWeaponModel( ent, weaponData[WP_SCEPTER].weaponMdl, ent->handLBolt, 1 ); } ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->weaponModel[1]], "*flash"); } if ( ent->client->ps.saber[0].type == SABER_SITH_SWORD ) { ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->weaponModel[0]], "*flash"); G_PlayEffect( G_EffectIndex( "scepter/sword.efx" ), ent->weaponModel[0], ent->genericBolt1, ent->s.number, ent->currentOrigin, qtrue, qtrue ); //how many times can she recharge? ent->count = g_spskill->integer*2; //To make sure she can do it at least once ent->flags |= FL_UNDYING; } if ( ent->client->ps.weapon == WP_NOGHRI_STICK && ent->weaponModel[0] ) { ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->weaponModel[0]], "*flash"); } G_ClassSetDontFlee( ent ); }
Asgarath83 Posted July 26, 2017 Author Posted July 26, 2017 AI: AI_SENTRYat the end of file.WIP: missing properly flight movement. void NPC_BSSentry_Default( void ) { if ( NPC->targetname ) { NPC->e_UseFunc = useF_sentry_use; } if (( NPC->enemy ) && (NPCInfo->localState != LSTATE_WAKEUP)) { // Don't attack if waking up or if no enemy Sentry_AttackDecision(); } else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES ) { NPC_Sentry_Patrol(); } else { Sentry_Idle(); } } ////////////////////////////////////////// FIGHTER AI /////////////////////////////// /////////////////////////////////////// BASIC FIGHTER AI LIKE AI DEFAULT //////////// void Fighter_Precache( void ); void Fighter_DustFallNear(const vec3_t origin, int dustcount); void Fighter_ChangeWeapon2(int wp); qboolean Fighter_StopKnockdown(gentity_t *self, gentity_t *pusher, const vec3_t pushDir, qboolean forceKnockdown = qfalse); // Flight Related Functions (used Only by flying classes) //-------------------------------------------------------- extern qboolean Fighter_Flying( gentity_t *self ); extern void Fighter_FlyStart( gentity_t *self ); extern void Fighter_FlyStop( gentity_t *self ); // Called From Fighter_Pain() //----------------------------- void Fighter_Pain( gentity_t *self, gentity_t *inflictor, int damage, int mod); // Local: Other Tactics //---------------------- void Fighter_DoAmbushWait( gentity_t *self); // Local: Respawning //------------------- //bool Fighter_Respawn(); // Called From Within AI_Jedi && AI_Seeker //----------------------------------------- void Fighter_Fire(); void Fighter_FireDecide(); // Local: Called From Tactics() //---------------------------- void Fighter_TacticsSelect(); bool Fighter_CanSeeEnemy( gentity_t *self ); // Called From Fighter_RunBehavior() //------------------------------- void Fighter_Update(); // Always Called First, Before Any Other Thinking bool Fighter_Tactics(); // If returns true, Jedi and Seeker AI not used bool Fighter_Flee(); // If returns true, Jedi and Seeker AI not used ////////////////////////////////////////////////////////////////////////////// // FLY FUNCTIONS CALLED FOR FLYING! //////////////////////////////// void Fighter_MaintainHeight(); void Fighter_Idle(); void Fighter_Strafe(); void Fighter_Hunt( qboolean visible, qboolean advance ); void NPC_Fighter_Patrol(); void Fighter_RangedAttack( qboolean visible, qboolean advance ); void Fighter_AttackDecision(); qboolean NPC_CheckPlayerTeamStealth(); void NPC_BSFighter_Default(); void Fighter_use( gentity_t *self, gentity_t *other, gentity_t *activator); void NPC_Fighter_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc ); //////////////////////////////////////////////////////////////////////////////////////// // External Functions //////////////////////////////////////////////////////////////////////////////////////// extern void G_SoundAtSpot( vec3_t org, int soundIndex, qboolean broadcast ); extern void G_CreateG2AttachedWeaponModel( gentity_t *ent, const char *weaponModel, int boltNum, int weaponNum ); extern void ChangeWeapon( gentity_t *ent, int newWeapon ); extern void WP_ResistForcePush( gentity_t *self, gentity_t *pusher, qboolean noPenalty ); extern void ForceJump( gentity_t *self, usercmd_t *ucmd ); extern void G_Knockdown( gentity_t *self, gentity_t *attacker, const vec3_t pushDir, float strength, qboolean breakSaberLock ); extern void WP_SaberAddG2SaberModels( gentity_t *ent, int specificSaberNum ); // DUSTY ADD //extern qboolean heavyWeap(int); //extern qboolean blasterWeap(int); extern int ChooseBestWeapon(gentity_t* ent); extern int ChooseWeaponRandom(gentity_t *ent, int wpnGroup); //extern qboolean lightBlasterWeap(int); //extern qboolean heavyBlasterWeap(int); //extern qboolean meleeWeap(int); // FIGHTER WEAPON CATEGORIES extern qboolean seekerWeap(int);//seeker missiles WP_ROCKET // WP_BOWCASTER extern qboolean bombsWeap(int);//REPEATER, POISON, THERMAL, TRIP, DETPACK extern qboolean laserWeap(int);// // BLASTER PISTOL: green laser - short stunner // BRYAR: red laser // POISON // chemical weapon // BLASTER // green laser big // JAWA // yellow // BLOODGUN // Blue laser extern qboolean chaffWeap(int);// FLECHETTE e DEMP2 extern qboolean specialWeap(int); // CONCUSSION AM ROCKET // DISGREGATOR // ATST MAIN // ATST SIDE // EMPLACED //////////////////////////////////////////////////////////////////////////////////////// // Defines //////////////////////////////////////////////////////////////////////////////////////// #define FIGHTER_SHOOTRANGEMIN 1024 // Bombs and contromisure #define FIGHTER_SHOOTRANGEMED 2048 // blasters #define FIGHTER_SHOOTRANGEMAX 8192 // max seeker and antimatter distance atk #define FIGHTER_SPECIALRANGE 16384 // special weapon ranged used for cruisers class #define FIGHTER_FORWARD_BASE_SPEED 75 #define FIGHTER_FORWARD_MULTIPLIER 5 #define FIGHTER_VELOCITY_DECAY 0.85f #define FIGHTER_STRAFE_VEL 512 #define FIGHTER_STRAFE_DIS 512 #define FIGHTER_UPWARD_PUSH 32 #define FIGHTER_HOVER_HEIGHT 24 extern gitem_t *FindItemForAmmo( ammo_t ammo ); #define FIGHTER_MIN_DISTANCE 1024 #define FIGHTER_MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE ) //Local state enums enum { FSTATE_NONE = 0, FSTATE_ASLEEP, FSTATE_WAKEUP, FSTATE_ACTIVE, FSTATE_POWERING_UP, FSTATE_ATTACKING, }; //////////////////////////////////////////////////////////////////////////////////////// // Global Data //////////////////////////////////////////////////////////////////////////////////////// bool FighterHadDeathScript = false; bool FighterActive = false; vec3_t AverageEnemyDirection3; int AverageEnemyDirectionSamples3; //////////////////////////////////////////////////////////////////////////////////////// // NPC NEW AGILITY SYSTEM FOR AVOID ATTACKS! //////////////////////////////////////////////////////////////////////////////////////// enum FighterTacticsState { FIGHTER_NONE, // Attack //-------- FIGHTER_CHAFF, // chaff and flare attack for enemy close FIGHTER_BOMBER, // bombardment mode against strategics targets FIGHTER_LASER, // laser standard atk FIGHTER_SEEKER, // seeker ranged atk FIGHTER_SPECIAL, // special and super weapons atk by lond distance (cruisers, \ star destroyers ) /// Waiting //--------- FIGHTER_AMBUSHWAIT, // Goto CP & Wait FIGHTER_MAX }; void Fighter_Precache( void ) { G_SoundIndex( "sound/chars/fighter/departure.wav" ); G_SoundIndex( "sound/chars/fighter/engine_lp.wav" ); G_SoundIndex( "sound/chars/fighter/landing.wav" ); G_EffectIndex( "volumetric/black_smoke" ); G_EffectIndex( "chunks/dustFall" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_explo" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_pain" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_shield_open" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_shield_close" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_hover_1_lp" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_hover_2_lp" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_explo" ); G_SoundIndex( "sound/chars/fighter/misc/fighter_pain" ); for ( int i = 1; i < 4; i++) { G_SoundIndex( va( "sound/chars/fighter/misc/talk%d", i ) ); } AverageEnemyDirectionSamples3 = 0; VectorClear(AverageEnemyDirection3); FighterHadDeathScript = false; FighterActive = true; } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Fighter_DustFallNear(const vec3_t origin, int dustcount) { if (!FighterActive) { return; } trace_t testTrace; vec3_t testDirection; vec3_t testStartPos; vec3_t testEndPos; VectorCopy(origin, testStartPos); for (int i=0; i<dustcount; i++) { testDirection[0] = (random() * 2.0f) - 1.0f; testDirection[1] = (random() * 2.0f) - 1.0f; testDirection[2] = 1.0f; VectorMA(origin, 1000.0f, testDirection, testEndPos); gi.trace (&testTrace, origin, NULL, NULL, testEndPos, (player && player->inuse)?(0):(ENTITYNUM_NONE), MASK_SHOT, (EG2_Collision)0, 0 ); if (!testTrace.startsolid && !testTrace.allsolid && testTrace.fraction>0.1f && testTrace.fraction<0.9f) { G_PlayEffect( "chunks/dustFall", testTrace.endpos, testTrace.plane.normal ); } } } qboolean Fighter_StopKnockdown( gentity_t *self, gentity_t *pusher, const vec3_t pushDir, qboolean forceKnockdown ) { if ( self->client->NPC_class == CLASS_BOBAFETT )// for others, not for boba. { return qfalse; } if ( self->client->moveType == MT_FLYSWIM ) {//can't knock me down when I'm flying return qtrue; } vec3_t pDir, fwd, right, ang = {0, self->currentAngles[YAW], 0}; float fDot, rDot; int strafeTime = Q_irand( 1000, 2000 ); AngleVectors( ang, fwd, right, NULL ); VectorNormalize2( pushDir, pDir ); fDot = DotProduct( pDir, fwd ); rDot = DotProduct( pDir, right ); if ( Q_irand( 0, 2 ) ) {//flip or roll with it usercmd_t tempCmd; if ( fDot >= 0.4f ) { tempCmd.forwardmove = 127; TIMER_Set( self, "moveforward", strafeTime ); } else if ( fDot <= -0.4f ) { tempCmd.forwardmove = -127; TIMER_Set( self, "moveback", strafeTime ); } else if ( rDot > 0 ) { tempCmd.rightmove = 127; TIMER_Set( self, "strafeRight", strafeTime ); TIMER_Set( self, "strafeLeft", -1 ); } else { tempCmd.rightmove = -127; TIMER_Set( self, "strafeLeft", strafeTime ); TIMER_Set( self, "strafeRight", -1 ); } G_AddEvent( self, EV_JUMP, 0 ); if ( !Q_irand( 0, 1 ) ) {//flip self->client->ps.forceJumpCharge = 280;//FIXME: calc this intelligently? //ForceJump( self, &tempCmd ); } else {//roll TIMER_Set( self, "duck", strafeTime ); } self->painDebounceTime = 0;//so we do something } else {//fall down return qfalse; } return qtrue; } qboolean Fighter_Flying( gentity_t *self ) { assert(self && self->client && self->client->NPC_class==CLASS_FIGHTER );//self->NPC && return ((qboolean)(self->client->moveType==MT_FLYSWIM)); // ONLY FOR FLYING CLASSES } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// bool Fighter_CanSeeEnemy( gentity_t *self ) { assert(self && self->NPC && self->client && self->client->NPC_class==CLASS_FIGHTER ); return ((level.time - self->NPC->enemyLastSeenTime)<1000); } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Fighter_Pain( gentity_t *self, gentity_t *inflictor, int damage, int mod) { if ( mod==MOD_SABER || mod !=MOD_SABER /*!(NPCInfo->aiFlags&NPCAI_FLAMETHROW)*/) { TIMER_Set( self, "NPC_TacticsSelect", 0); // Hurt By The Saber, Time To Try Something New } } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Fighter_FlyStart( gentity_t *self ) {//switch to seeker AI for a while if ( TIMER_Done( self, "jetRecharge" ) && !Fighter_Flying( self ) ) { self->client->ps.gravity = 0; self->svFlags |= SVF_CUSTOM_GRAVITY; self->client->moveType = MT_FLYSWIM; //start jet effect self->client->jetPackTime = level.time + Q_irand( 3000, 10000 ); //take-off sound G_SoundOnEnt( self, CHAN_ITEM, "sound/chars/fighter/departure.wav" ); //boost loop sound self->s.loopSound = G_SoundIndex( "sound/chars/fighter/engine_lp.wav" ); } } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Fighter_FlyStop( gentity_t *self ) { self->client->ps.gravity = g_gravity->value; self->svFlags &= ~SVF_CUSTOM_GRAVITY; self->client->moveType = MT_FLYSWIM; //Stop effect self->client->jetPackTime = 0; //stop jet loop sound G_SoundOnEnt( self, CHAN_ITEM, "sound/chars/fighter/landing.wav" ); self->s.loopSound = 0; if ( self->NPC ) { self->count = 0; // SEEKER shot ammo count TIMER_Set( self, "jetRecharge", Q_irand( 1000, 5000 ) ); TIMER_Set( self, "jumpChaseDebounce", Q_irand( 500, 2000 ) ); } } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Fighter_DoAmbushWait( gentity_t *self) { Fighter_TacticsSelect(); } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // Call This function to make Boba actually shoot his current weapon //////////////////////////////////////////////////////////////////////////////////////// void Fighter_Fire() { int bolt; WeaponThink(qtrue); // Which muzzle to fire from? int which = NPCInfo->burstCount % 3; switch( which ) { case 0: bolt = NPC->handLBolt; break; case 1: bolt = NPC->handRBolt; break; case 2: default: bolt = NPC->genericBolt3; } // If Actually Fired, Decide To Apply Alt Fire And Calc Next Attack Delay //------------------------------------------------------------------------ if (ucmd.buttons&BUTTON_ATTACK) { // DUSTY ADD - THIS WORK WITHOUT TROUBLE! if (seekerWeap(NPC->s.weapon)) { if (NPC->s.weapon == WP_ROCKET_LAUNCHER|| NPC->s.weapon == WP_BOWCASTER ) TIMER_Set(NPC, "nextAttackDelay", Q_irand(1000, 2000)); // Half of your rocket and bowcasters are Homing\Grapple Missile //------------------------------------- if (!Q_irand(0, 1)) { ucmd.buttons &= ~BUTTON_ATTACK; ucmd.buttons |= BUTTON_ALT_ATTACK; if (NPC->s.weapon == WP_ROCKET_LAUNCHER) { NPC->client->fireDelay = Q_irand(1000, 3000); } else if (NPC->s.weapon == WP_BOWCASTER ) { NPC->client->fireDelay = Q_irand(750, 2000); } } } else if (chaffWeap(NPC->s.weapon)) { if (NPC->s.weapon == WP_FLECHETTE|| NPC->s.weapon == WP_DEMP2 ) TIMER_Set(NPC, "nextAttackDelay", Q_irand(1000, 2000)); // Half of your rocket and bowcasters are Homing\Grapple Missile //------------------------------------- if (!Q_irand(0, 5)) { ucmd.buttons &= ~BUTTON_ATTACK; ucmd.buttons |= BUTTON_ALT_ATTACK; if (NPC->s.weapon == WP_FLECHETTE) { NPC->client->fireDelay = Q_irand(1000, 3000); } else if (NPC->s.weapon == WP_DEMP2 ) { NPC->client->fireDelay = Q_irand(1000, 1500); } } } else if (laserWeap(NPC->s.weapon)) { if (NPC->s.weapon == WP_BLASTER|| NPC->s.weapon == WP_BRYAR_PISTOL || NPC->s.weapon == WP_POISON || NPC->s.weapon == WP_JAWA || NPC->s.weapon == WP_BLOODGUN ) TIMER_Set(NPC, "nextAttackDelay", Q_irand(500, 1000)); // Laser weapons //------------------------------------- if (!Q_irand(0, 6)) { ucmd.buttons &= ~BUTTON_ATTACK; ucmd.buttons |= BUTTON_ALT_ATTACK; if (NPC->s.weapon == WP_BLASTER_PISTOL || NPC->s.weapon == WP_BRYAR_PISTOL ) // allied and enemy stunner lasers { NPC->client->fireDelay = Q_irand(250, 500); } else if (NPC->s.weapon == WP_BLASTER || WP_JAWA )// medium lasers { NPC->client->fireDelay = Q_irand(300, 750); } else if (NPC->s.weapon == WP_POISON || WP_BLOODGUN ) // strong lasers { NPC->client->fireDelay = Q_irand(1000, 1500); } } } else if (bombsWeap(NPC->s.weapon)) { if (NPC->s.weapon == WP_REPEATER|| NPC->s.weapon == WP_THERMAL || NPC->s.weapon == WP_POISON ) TIMER_Set(NPC, "nextAttackDelay", Q_irand(1000, 1500)); // These weapons are shooted ever with half fire. Ever! //------------------------------------- NPCInfo->scriptFlags |= SCF_ALT_FIRE; } else if (specialWeap(NPC->s.weapon)) { if (NPC->s.weapon == WP_CONCUSSION|| NPC->s.weapon == WP_DISRUPTOR || NPC->s.weapon == WP_ATST_MAIN || NPC->s.weapon == WP_ATST_SIDE || NPC->s.weapon == WP_EMPLACED_GUN ) TIMER_Set(NPC, "nextAttackDelay", Q_irand(1500, 2000)); // Special destructive massival weapons //------------------------------------- if (!Q_irand(0, 5))// very rare alt fire { ucmd.buttons &= ~BUTTON_ATTACK; ucmd.buttons |= BUTTON_ALT_ATTACK; if (NPC->s.weapon == WP_CONCUSSION ) // allied and enemy stunner lasers { NPC->client->fireDelay = Q_irand(1000, 5000); } else if (NPC->s.weapon == WP_DISRUPTOR )// medium lasers { NPC->client->fireDelay = Q_irand(1000, 2000); } else if (NPC->s.weapon == WP_ATST_MAIN || WP_ATST_SIDE ) // strong lasers { NPC->client->fireDelay = Q_irand(1000, 2000); } else if (NPC->s.weapon == WP_EMPLACED_GUN ) // strong lasers { NPC->client->fireDelay = Q_irand(750, 850); } } } } } //////////////////////////////////////////////////////////////////////////////////////// // Call this function to see if Fett should fire his current weapon //////////////////////////////////////////////////////////////////////////////////////// //helper function qboolean isFighterClass(int className) { if (NPC->client->NPC_class == CLASS_FIGHTER )// Add other special classes ) return qtrue; return qfalse; } void Fighter_FireDecide( void ) { // Any Reason Not To Shoot? //-------------------------- if (!NPC || // Only NPCs !NPC->client || // Only Clients //NPC->client->NPC_class!=CLASS_BOBAFETT || // Only Boba !isFighterClass(NPC->client->NPC_class) || // Only Boba !NPC->enemy || // Only If There Is An Enemy NPC->s.weapon == WP_NONE || // Only If Using A Valid Weapon !TIMER_Done(NPC, "nextAttackDelay") || // Only If Ready To Shoot Again !Fighter_CanSeeEnemy(NPC) // Only If Enemy Recently Seen ) { return; } // Now Check Weapon Specific Parameters To See If We Should Shoot Or Not //----------------------------------------------------------------------- // GOOD CODE // DUSTY VARIANTE if (laserWeap(NPC->s.weapon) || bombsWeap(NPC->s.weapon) || chaffWeap(NPC->s.weapon) || seekerWeap(NPC->s.weapon)|| specialWeap(NPC->s.weapon)) { // WHEN FIRE? if (Distance(NPC->currentOrigin, NPC->enemy->currentOrigin) > 400.0f) { Fighter_Fire(); } else { Fighter_Fire(); } } else { Fighter_Fire(); } } //////////////////////////////////////////////////////////////////////////////////////// // Tactics avaliable to Boba Fett: // -------------------------------- // FIGHTER_LASER, // Uses laser weapons and close \ medium combat // FIGHTER_BOMBER, // Close / medium distance, bombardment. // FIGHTER_CHAFF // Defensive action for close combat // FIGHTER_SEEKER, // medium \ long range seeker and rockets // FIGHTER_SPECIAL, // special weapons for cruisers, turbolasers, turrets etc // FIGHTER_AMBUSHWAIT, // Goto CP & Wait // extern void WP_DeactivateSaber( gentity_t *self, qboolean clearLength ); //////////////////////////////////////////////////////////////////////////////////////// void Fighter_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 enemyAlive3 = (NPC->enemy->health>0); float fighterDistance = Distance(NPC->currentOrigin, NPC->enemy->currentOrigin); bool enemyChaffRange = (fighterDistance<FIGHTER_SHOOTRANGEMIN); bool enemyBombRange = (fighterDistance>FIGHTER_SHOOTRANGEMIN && fighterDistance<FIGHTER_SHOOTRANGEMED); bool enemyLaserRange = (fighterDistance>FIGHTER_SHOOTRANGEMED && fighterDistance<FIGHTER_SHOOTRANGEMAX); bool enemySeekRange = (fighterDistance>FIGHTER_SHOOTRANGEMAX && fighterDistance<FIGHTER_SPECIALRANGE); bool enemySpecialRange = (fighterDistance>FIGHTER_SPECIALRANGE); bool enemyRecentlySeen3 = Fighter_CanSeeEnemy(NPC); if (!enemyAlive3) { nextState = FIGHTER_LASER; } else if (enemyChaffRange)// Enemy is pretty near, so use Saber! { if ( HaveWeapon(NPC, WEAPS_CHAFF ))// If Enemy is near, and NPC have a sword in his inventory, using that sword. { nextState = FIGHTER_CHAFF; } else if ( HaveWeapon(NPC, WEAPS_LASER ))// If Enemy is near, and NPC have a sword in his inventory, using that sword. { nextState = FIGHTER_LASER; } } else if (enemyBombRange && !enemyChaffRange )// Enemy is distance enought to bombardment. on alternative, you can use lasers. { if ( HaveWeapon(NPC, WEAPS_BOMBS ))// Enemy is distance, you are a wizard? shoot with magic { nextState = FIGHTER_BOMBER; } else if ( HaveWeapon(NPC, WEAPS_LASER ))// Enemy is distance? You are an Hunter? use glyphic weapons { nextState = FIGHTER_LASER; } } else if (!enemyBombRange && !enemyChaffRange && enemyLaserRange)// Enemy is distance so use shoot atk { if ( HaveWeapon(NPC, WEAPS_LASER ))// Enemy is distance, you are a wizard? shoot with magic { nextState = FIGHTER_LASER; } else if ( HaveWeapon(NPC, WEAPS_SEEKER ))// Enemy is distance? You are an Hunter? use glyphic weapons { nextState = FIGHTER_SEEKER; } } else if (!enemyBombRange && !enemyChaffRange && !enemyLaserRange && enemySeekRange)// Enemy is distance so use shoot atk { if ( HaveWeapon(NPC, WEAPS_LASER ))// Enemy is distance, you are a wizard? shoot with magic { nextState = FIGHTER_LASER; } else if ( HaveWeapon(NPC, WEAPS_SEEKER ))// Enemy is distance? You are an Hunter? use glyphic weapons { nextState = FIGHTER_SEEKER; } } else if (!enemyBombRange && !enemyChaffRange && !enemyLaserRange && !enemySeekRange && enemySpecialRange) // 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, WEAPS_BLASTER ))// Enemy is distance, you are a wizard? shoot with magic { nextState = FIGHTER_LASER; } else if ( HaveWeapon(NPC, WEAPS_SPECIAL ))// Enemy is distance? You are an Hunter? use glyphic weapons { nextState = FIGHTER_SPECIAL; } else if ( HaveWeapon(NPC, WEAPS_SEEKER ))// You are an archer? use arrows! { nextState = FIGHTER_SEEKER; } } // Recently Saw The Enemy, Time For Some Good Ole Fighten! //--------------------------------------------------------- /*else if (enemyRecentlySeen3) { // 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 if (!enemyChaffRange && NPC->client->ps.weapon != WP_FLECHETTE ) { nextState = FIGHTER_LASER; } nextState = (!enemyChaffRange || Q_irand(0, NPC->count)<1)?(FIGHTER_BOMBER):(FIGHTER_LASER); //nextState = (!enemyInShootRange || Q_irand(0, NPC->count)<1)?(NPC_MAGIC):(NPC_FENCER); }*/ NPCInfo->localState = nextState; int weapon = 0; switch (NPCInfo->localState) { case FIGHTER_LASER: weapon = ChooseWeaponRandom(NPC, WEAPS_LASER); if (weapon) { //NPC_Printf("NEW TACTIC: Rifle"); NPC_ChangeWeapon(WEAPS_LASER); G_RemoveWeaponModels( NPC ); break; } case FIGHTER_CHAFF: weapon = ChooseWeaponRandom(NPC, WEAPS_CHAFF); if (weapon) { //NPC_Printf("NEW TACTIC: Rocket Launcher"); NPC_ChangeWeapon(WEAPS_CHAFF); G_RemoveWeaponModels( NPC ); break; } case FIGHTER_BOMBER: //kinda stuck at this point if doesn't have flamethrower //NPC_Printf("NEW TACTIC: Flame Thrower"); weapon = ChooseWeaponRandom(NPC, WEAPS_BOMBS); if (weapon) { //NPC_Printf("NEW TACTIC: Rocket Launcher"); NPC_ChangeWeapon(WEAPS_BOMBS); G_RemoveWeaponModels( NPC ); break; } case FIGHTER_SPECIAL: //kinda stuck at this point if doesn't have flamethrower //NPC_Printf("NEW TACTIC: Flame Thrower"); weapon = ChooseWeaponRandom(NPC, WEAPS_SPECIAL); if (weapon) { //NPC_Printf("NEW TACTIC: Rocket Launcher"); NPC_ChangeWeapon(WEAPS_SPECIAL); G_RemoveWeaponModels( NPC ); break; } case FIGHTER_SEEKER: //kinda stuck at this point if doesn't have flamethrower //NPC_Printf("NEW TACTIC: Flame Thrower"); weapon = ChooseWeaponRandom(NPC, WEAPS_SEEKER); if (weapon) { //NPC_Printf("NEW TACTIC: Rocket Launcher"); NPC_ChangeWeapon(WEAPS_SEEKER); G_RemoveWeaponModels( NPC ); break; } case FIGHTER_AMBUSHWAIT: //NPC_Printf("NEW TACTIC: Ambush"); weapon = ChooseWeaponRandom(NPC, WEAPS_ALL); if (weapon) { //NPC_Printf("NEW TACTIC: Rocket Launcher"); NPC_ChangeWeapon(weapon); G_RemoveWeaponModels( NPC ); break; } } } //////////////////////////////////////////////////////////////////////////////////////// // Tactics // // This function is called right after Update() // If returns true, Jedi and Seeker AI not used for movement // //////////////////////////////////////////////////////////////////////////////////////// bool Fighter_Tactics() { if (!NPC->enemy) { return false; } // Think About Changing Tactics //------------------------------ if (TIMER_Done(NPC, "NPC_TacticsSelect")) { Fighter_TacticsSelect(); } // These Tactics Require Seeker & Jedi Movement //---------------------------------------------- if (!NPCInfo->localState || NPCInfo->localState==FIGHTER_LASER || NPCInfo->localState==FIGHTER_CHAFF || NPCInfo->localState==FIGHTER_BOMBER|| NPCInfo->localState==FIGHTER_SEEKER || NPCInfo->localState==FIGHTER_SPECIAL ) { return false; } // Flame Thrower - Locked In Place //--------------------------------- if (NPCInfo->localState==FIGHTER_BOMBER || NPCInfo->localState==FIGHTER_CHAFF || NPCInfo->localState==FIGHTER_LASER || NPCInfo->localState==FIGHTER_SEEKER || NPCInfo->localState==FIGHTER_SPECIAL ) { Fighter_TacticsSelect(); } // Ambush Wait //------------ else if (NPCInfo->localState==FIGHTER_AMBUSHWAIT) { Fighter_DoAmbushWait( NPC ); } NPC_FacePosition( NPC->enemy->currentOrigin, qtrue); // chase enemy NPC_UpdateAngles(qtrue, qtrue); return true; // Do Not Use Normal Jedi Or Seeker Movement } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Fighter_Update() { // Hey, That Tests The Trace All The Time //---------------------------------------------------- if (NPC->enemy) { // Never Forget The Player... Never. NEVER!!! NPC->svFlags |= SVF_LOCKEDENEMY; // Don't forget about the enemy once you've found him if (!(NPC->svFlags&SVF_NOCLIENT)) { trace_t testTrace; vec3_t eyes; CalcEntitySpot( NPC, SPOT_HEAD_LEAN, eyes ); gi.trace (&testTrace, eyes, NULL, NULL, NPC->enemy->currentOrigin, NPC->s.number, MASK_SHOT, (EG2_Collision)0, 0); bool wasSeen = Fighter_CanSeeEnemy(NPC); if (!testTrace.startsolid && !testTrace.allsolid && testTrace.entityNum == NPC->enemy->s.number) { NPCInfo->enemyLastSeenTime = level.time; NPCInfo->enemyLastHeardTime = level.time; VectorCopy(NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation); VectorCopy(NPC->enemy->currentOrigin, NPCInfo->enemyLastHeardLocation); } else if (gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin)) { NPCInfo->enemyLastHeardTime = level.time; VectorCopy(NPC->enemy->currentOrigin, NPCInfo->enemyLastHeardLocation); } } } // Make Sure He Always Appears In The Last Area With Full Health When His Death Script Is Turned On //-------------------------------------------------------------------------------------------------- if (!FighterHadDeathScript && NPC->behaviorSet[BSET_DEATH]!=0) { if (!gi.inPVS(NPC->enemy->currentOrigin, NPC->currentOrigin)) { //NPC_Printf("Attempting Final Battle Spawn..."); /*if (Fighter_Respawn()) { FighterHadDeathScript = true; } else { //NPC_Printf("Failed"); }*/ } } // Occasionally A Jump Turns Into A Rocket Fly //--------------------------------------------- if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE && NPC->client->ps.forceJumpZStart && NPC->client->NPC_class == CLASS_FIGHTER && !Q_irand( 0, 10 )) {//take off Fighter_FlyStart( NPC ); } // EDIT THIS WITH A FUNCTION FOR TAKE EVER A GOOD DISTANCE BY GROUND // CALL FIGHTER MAINTAINE HEIGHT // ADD // If Hurting, Try To Run Away //----------------------------- if (!NPCInfo->surrenderTime && (NPC->health<NPC->max_health/10)) { // Find The Closest Flee Point That I Can Get To //----------------------------------------------- int cp = NPC_FindCombatPoint(NPC->currentOrigin, 0, NPC->currentOrigin, CP_FLEE|CP_HAS_ROUTE|CP_TRYFAR|CP_HORZ_DIST_COLL, 0, -1); if (cp!=-1) { NPC_SetCombatPoint( cp ); NPC_SetMoveGoal( NPC, level.combatPoints[cp].origin, 8, qtrue, cp ); if (NPC->count<6) { NPCInfo->surrenderTime = level.time + Q_irand(5000, 10000) + 1000*(6-NPC->count); } else { NPCInfo->surrenderTime = level.time + Q_irand(5000, 10000); } } } } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// bool Fighter_Flee() { bool EnemyRecentlySeen = ((level.time - NPCInfo->enemyLastSeenTime)<10000); bool ReachedEscapePoint = (Distance(level.combatPoints[NPCInfo->combatPoint].origin, NPC->currentOrigin)<50.0f); bool HasBeenGoneEnough = (level.time>NPCInfo->surrenderTime || (level.time - NPCInfo->enemyLastSeenTime)>400000); // Is It Time To Come Back For Some More? //---------------------------------------- if (!EnemyRecentlySeen || ReachedEscapePoint) { NPC->svFlags |= SVF_NOCLIENT; if (HasBeenGoneEnough) { if ((level.time - NPCInfo->enemyLastSeenTime)>400000) { //NPC_Printf(" Gone Too Long, Attempting Respawn"); } } else if (ReachedEscapePoint && (NPCInfo->surrenderTime - level.time)>3000) { if (TIMER_Done(NPC, "SpookPlayerTimer")) { vec3_t testDirection; TIMER_Set(NPC, "SpookPlayerTimer", Q_irand(2000, 10000)); switch(Q_irand(0, 1)) { case 0: //NPC_Printf("SPOOK: Dust"); Fighter_DustFallNear(NPC->enemy->currentOrigin, Q_irand(1,2)); break; case 1: //NPC_Printf("SPOOK: Footsteps"); testDirection[0] = (random() * 0.5f) - 1.0f; testDirection[0] += (testDirection[0]>0.0f)?(0.5f)-0.5f); testDirection[1] = (random() * 0.5f) - 1.0f; testDirection[1] += (testDirection[1]>0.0f)?(0.5f)-0.5f); testDirection[2] = 1.0f; break; } } if (TIMER_Done(NPC, "ResampleEnemyDirection") && NPC->enemy->resultspeed>10.0f) { TIMER_Set(NPC, "ResampleEnemyDirection", Q_irand(500, 1000)); AverageEnemyDirectionSamples3 ++; vec3_t moveDir; VectorCopy(NPC->enemy->client->ps.velocity, moveDir); VectorNormalize(moveDir); VectorAdd(AverageEnemyDirection3, moveDir, AverageEnemyDirection3); } } } else { NPCInfo->surrenderTime += 100; } // Finish The Flame Thrower First... // FLAMETHROWER //----------------------------------- /*if (NPCInfo->aiFlags&NPCAI_FLAMETHROW) { Fighter_TacticsSelect(); NPC_FacePosition( NPC->enemy->currentOrigin, qtrue); NPC_UpdateAngles(qtrue, qtrue); return true; }*/ bool IsOnAPath = !!NPC_MoveToGoal(qtrue); if (!ReachedEscapePoint && NPCInfo->aiFlags&NPCAI_BLOCKED && NPC->client->moveType!=MT_FLYSWIM && ((level.time - NPCInfo->blockedDebounceTime)>1000) ) { if (!Fighter_CanSeeEnemy(NPC) && Distance(NPC->currentOrigin, level.combatPoints[NPCInfo->combatPoint].origin)<200) { //NPC_Printf("BLOCKED: Just Teleporting There"); G_SetOrigin(NPC, level.combatPoints[NPCInfo->combatPoint].origin); } else { //NPC_Printf("BLOCKED: Attempting Jump"); if (IsOnAPath) { if (NPC_TryJump(NPCInfo->blockedTargetPosition)) { } else { //NPC_Printf(" Failed"); } } else if (EnemyRecentlySeen) { if (NPC_TryJump(NPCInfo->enemyLastSeenLocation)) { } else { //NPC_Printf(" Failed"); } } } } NPC_UpdateAngles( qtrue, qtrue ); return true; }
Asgarath83 Posted July 26, 2017 Author Posted July 26, 2017 flight code ///////////////////////// BY SENTRY CODE FLY FUNCTIONS////////////////////////// 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 ); } /* ------------------------- Fighter_Idle ------------------------- */ void Fighter_Idle( void ) { /*float distance, speed; vec3_t forward; Fighter_MaintainHeight(); VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, forward ); distance = VectorNormalize( forward ); speed = 0;*/ // 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_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); NPC->flags |= FL_SHIELDED; NPC_BSIdle(); } } /* ------------------------- 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_DIS * dir, right, NPC->client->ps.velocity ); // Add a slight 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; } } /* ------------------------- Fighter_Hunt ------------------------- */ #define FIGHTER_ATTACK_FWD 0.95f #define FIGHTER_ATTACK_SIDE 0.20f #define FIGHTER_AIM_SIDE 0.60f #define FIGHTER_FUTURE_PRED_DIST 20.0f #define FIGHTER_FUTURE_SIDE_DIST 60.0f #define FIGHTER_ATTACK_FLANK_SLOWING 1000.0f #define FIGHTER_RAM_DIST 150.0f #define FIGHTER_MIN_STAY_VIEWABLE_TIME 20000 extern bool VEH_StartStrafeRam(Vehicle_t *pVeh, bool Right); void Fighter_Steer() { if (!NPC->enemy || !NPC->enemy->client) { return; } // SETUP //======= // Setup Actor Data //------------------ CVec3 ActorPos(NPC->currentOrigin); CVec3 ActorAngles(NPC->currentAngles); ActorAngles[2] = 0; Vehicle_t* ActorVeh = NPCInfo->greetEnt->m_pVehicle; bool ActorInTurbo = (ActorVeh->m_iTurboTime>level.time); float ActorSpeed = (ActorVeh)?(VectorLength(ActorVeh->m_pParentEntity->client->ps.velocity)):(NPC->client->ps.speed); // If my vehicle is spinning out of control, just hold on, we're going to die!!!!! //--------------------------------------------------------------------------------- if (ActorVeh && (ActorVeh->m_ulFlags & VEH_OUTOFCONTROL)) { if (NPC->client->ps.weapon!=WP_NONE) { NPC_ChangeWeapon(WP_NONE); } ucmd.buttons &=~BUTTON_ATTACK; ucmd.buttons &=~BUTTON_ALT_ATTACK; return; } CVec3 ActorDirection; AngleVectors(ActorAngles.v, ActorDirection.v, 0, 0); CVec3 ActorFuturePos(ActorPos); ActorFuturePos.ScaleAdd(ActorDirection, FIGHTER_FUTURE_PRED_DIST); bool ActorDoTurbo = false; bool ActorAccelerate = false; bool ActorAimAtTarget= true; float ActorYawOffset = 0.0f; // Setup Enemy Data //------------------ CVec3 EnemyPos(NPC->enemy->currentOrigin); CVec3 EnemyAngles(NPC->enemy->currentAngles); EnemyAngles[2] = 0; Vehicle_t* EnemyVeh = (NPC->enemy->s.m_iVehicleNum)?(g_entities[NPC->enemy->s.m_iVehicleNum].m_pVehicle):(0); bool EnemyInTurbo = (EnemyVeh && EnemyVeh->m_iTurboTime>level.time); float EnemySpeed = (EnemyVeh)?(EnemyVeh->m_pParentEntity->client->ps.speed):(NPC->enemy->resultspeed); bool EnemySlideBreak = (EnemyVeh && (EnemyVeh->m_ulFlags&VEH_SLIDEBREAKING || EnemyVeh->m_ulFlags&VEH_STRAFERAM)); bool EnemyDead = (NPC->enemy->health<=0); bool ActorFlank = (NPCInfo->lastAvoidSteerSideDebouncer>level.time && EnemyVeh && EnemySpeed>10.0f); CVec3 EnemyDirection; CVec3 EnemyRight; AngleVectors(EnemyAngles.v, EnemyDirection.v, EnemyRight.v, 0); CVec3 EnemyFuturePos(EnemyPos); EnemyFuturePos.ScaleAdd(EnemyDirection, FIGHTER_FUTURE_PRED_DIST); ESide EnemySide = ActorPos.LRTest(EnemyPos, EnemyFuturePos); CVec3 EnemyFlankPos(EnemyFuturePos); EnemyFlankPos.ScaleAdd(EnemyRight, (EnemySide==Side_Right)?(FIGHTER_FUTURE_SIDE_DIST)-FIGHTER_FUTURE_SIDE_DIST)); // Debug Draw Enemy Data //----------------------- if (false) { CG_DrawEdge(EnemyPos.v, EnemyFuturePos.v, EDGE_IMPACT_SAFE); CG_DrawEdge(EnemyFuturePos.v, EnemyFlankPos.v, EDGE_IMPACT_SAFE); } // Setup Move And Aim Directions //------------------------------- CVec3 MoveDirection((ActorFlank)?(EnemyFlankPos):(EnemyFuturePos)); MoveDirection -= ActorPos; float MoveDistance = MoveDirection.SafeNorm(); float MoveAccuracy = MoveDirection.Dot(ActorDirection); CVec3 AimDirection(EnemyPos); AimDirection -= ActorPos; float AimDistance = AimDirection.SafeNorm(); float AimAccuracy = AimDirection.Dot(ActorDirection); if (!ActorFlank && TIMER_Done(NPC, "FlankAttackCheck")) { TIMER_Set(NPC, "FlankAttackCheck", Q_irand(1000, 3000)); if (MoveDistance<4000 && Q_irand(0, 1)==0) { NPCInfo->lastAvoidSteerSideDebouncer = level.time + Q_irand(8000, 14000); } } // Fly By Sounds //--------------- if ((ActorVeh->m_pVehicleInfo->soundFlyBy || ActorVeh->m_pVehicleInfo->soundFlyBy2) && EnemyVeh && MoveDistance<800 && ActorSpeed>500.0f && TIMER_Done(NPC, "FlybySoundDebouncer") ) { if (EnemySpeed<100.0f || (ActorDirection.Dot(EnemyDirection)*(MoveDistance/800.0f))<-0.5f) { TIMER_Set(NPC, "FlybySoundDebouncer", 2000); int soundFlyBy = ActorVeh->m_pVehicleInfo->soundFlyBy; if (ActorVeh->m_pVehicleInfo->soundFlyBy2 && (!soundFlyBy || !Q_irand(0,1))) { soundFlyBy = ActorVeh->m_pVehicleInfo->soundFlyBy2; } G_Sound(ActorVeh->m_pParentEntity, soundFlyBy); } } // FLY PAST BEHAVIOR //=================== if (EnemySlideBreak || !TIMER_Done(NPC, "MinHoldDirectionTime")) { if (TIMER_Done(NPC, "MinHoldDirectionTime")) { TIMER_Set(NPC, "MinHoldDirectionTime", 500); // Hold For At Least 500 ms } ActorAccelerate = true; // Go ActorAimAtTarget = false; // Don't Alter Our Aim Direction ucmd.buttons &=~BUTTON_VEH_SPEED; // Let Normal Vehicle Controls Go } // FLANKING BEHAVIOR //=================== else if (ActorFlank) { ActorAccelerate = true; ActorDoTurbo = (MoveDistance>2500 || EnemyInTurbo); ucmd.buttons |= BUTTON_VEH_SPEED; // Tells PMove to use the ps.speed we calculate here, not the one from g_vehicles.c // For Flanking, We Calculate The Speed By Hand, Rather Than Using Pure Accelerate / No Accelerate Functionality //--------------------------------------------------------------------------------------------------------------- NPC->client->ps.speed = ActorVeh->m_pVehicleInfo->speedMax * ((ActorInTurbo)?(1.35f):(1.15f)); // If In Slowing Distance, Scale Down The Speed As We Approach Our Move Target //----------------------------------------------------------------------------- if (MoveDistance<FIGHTER_ATTACK_FLANK_SLOWING) { NPC->client->ps.speed *= (MoveDistance/FIGHTER_ATTACK_FLANK_SLOWING); NPC->client->ps.speed += EnemySpeed; // Match Enemy Speed //------------------- if (NPC->client->ps.speed<5.0f && EnemySpeed<5.0f) { NPC->client->ps.speed = EnemySpeed; } // Extra Slow Down When Out In Front //----------------------------------- if (MoveAccuracy<0.0f) { NPC->client->ps.speed *= (MoveAccuracy + 1.0f); } MoveDirection *= (MoveDistance/FIGHTER_ATTACK_FLANK_SLOWING); EnemyDirection *= 1.0f - (MoveDistance/FIGHTER_ATTACK_FLANK_SLOWING); MoveDirection += EnemyDirection; if (TIMER_Done(NPC, "RamCheck")) { TIMER_Set(NPC, "RamCheck", Q_irand(1000, 3000)); if (MoveDistance<FIGHTER_RAM_DIST && Q_irand(0, 2)==0) { VEH_StartStrafeRam(ActorVeh, (EnemySide==Side_Left)); } } } } // NORMAL CHASE BEHAVIOR //======================= else { if (!EnemyVeh && AimAccuracy>0.99f && MoveDistance<500 && !EnemyDead) { ActorAccelerate = true; ActorDoTurbo = false; } else { ActorAccelerate = ((MoveDistance>500 && EnemySpeed>20.0f) || MoveDistance>1000); ActorDoTurbo = (MoveDistance>3000 && EnemySpeed>20.0f); } ucmd.buttons &=~BUTTON_VEH_SPEED; } // APPLY RESULTS //======================= // Decide Turbo //-------------- if (ActorDoTurbo || ActorInTurbo) { ucmd.buttons |= BUTTON_ALT_ATTACK; } else { ucmd.buttons &=~BUTTON_ALT_ATTACK; } // Decide Acceleration //--------------------- ucmd.forwardmove = (ActorAccelerate)?(127):(0); // Decide To Shoot //----------------- ucmd.buttons &=~BUTTON_ATTACK; ucmd.rightmove = 0; if (AimDistance<2000 && !EnemyDead) { // If Doing A Ram Attack //----------------------- if (ActorYawOffset!=0) { if (NPC->client->ps.weapon!=WP_NONE) { NPC_ChangeWeapon(WP_NONE); } ucmd.buttons &=~BUTTON_ATTACK; } else if (AimAccuracy>FIGHTER_ATTACK_FWD) { if (NPC->client->ps.weapon!=WP_NONE) { NPC_ChangeWeapon(WP_NONE); } ucmd.buttons |= BUTTON_ATTACK; } else if (AimAccuracy<FIGHTER_AIM_SIDE && AimAccuracy>-FIGHTER_AIM_SIDE) { if (NPC->client->ps.weapon!=WP_BLASTER) { NPC_ChangeWeapon(WP_BLASTER); } if (AimAccuracy<FIGHTER_ATTACK_SIDE && AimAccuracy>-FIGHTER_ATTACK_SIDE) { //if (!TIMER_Done(NPC, "RiderAltAttack")) //{ // ucmd.buttons |= BUTTON_ALT_ATTACK; //} //else //{ ucmd.buttons |= BUTTON_ATTACK; /* if (TIMER_Done(NPC, "RiderAltAttackCheck")) { TIMER_Set(NPC, "RiderAltAttackCheck", Q_irand(1000, 3000)); if (Q_irand(0, 2)==0) { TIMER_Set(NPC, "RiderAltAttack", 300); } }*/ //} WeaponThink(true); } ucmd.rightmove = (EnemySide==Side_Left)?( 127)-127); } else { if (NPC->client->ps.weapon!=WP_NONE) { NPC_ChangeWeapon(WP_NONE); } } } else { if (NPC->client->ps.weapon!=WP_NONE) { NPC_ChangeWeapon(WP_NONE); } } // Aim At Target //--------------- if (ActorAimAtTarget) { MoveDirection.VecToAng(); NPCInfo->desiredPitch = AngleNormalize360(MoveDirection[PITCH]); NPCInfo->desiredYaw = AngleNormalize360(MoveDirection[YAW] + ActorYawOffset); } NPC_UpdateAngles(qtrue, qtrue); } 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 = 12; NPC_MoveToGoal(qtrue); return; } else { VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, forward ); distance = VectorNormalize( forward ); // only for fighter classes not for cruisers // Acceleration! this allow a fighter to flight like a swoop. // friction: this allow a fighter to slow speed when go over the player // if a fighter go over the player, it brakes and turn back for purchase. // Fighter_Steer(); CRASHA! } // If you disable that, fighter not fly and you get the bobbing movement! speed = FIGHTER_FORWARD_BASE_SPEED + FIGHTER_FORWARD_MULTIPLIER * g_spskill->integer; VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity ); } /* ------------------------- NPC_Fighter_Patrol ------------------------- */ void NPC_Fighter_Patrol( void ) { Fighter_MaintainHeight(); //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 ); } /* ------------------------- 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 ); } // YOU WANT TO SHIELD ONLY SOME CLASSES OF FIGHTER OR SPECIAL STARSHIP? /*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->flags |= FL_SHIELDED; 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" ); }*/ } else { Fighter_Fire(); } } if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES ) { Fighter_Hunt( visible, advance ); } } /* ------------------------- Fighter_AttackDecision ------------------------- */ void Fighter_AttackDecision( void ) { // Always keep a good height off the ground Fighter_MaintainHeight(); NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/fighter/sentry_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_CheckPlayerTeamStealth( void ); void NPC_BSFighter_Default( void ) { //Fighter_Update(); if ( NPC->targetname ) { //NPC->e_UseFunc = useF_fighter_use; } if (( NPC->enemy ) && (NPCInfo->localState != LSTATE_WAKEUP)) { // Don't attack if waking up or if no enemy Fighter_AttackDecision(); } else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES ) { NPC_Fighter_Patrol(); } else { Fighter_Idle(); } } /* ================ Fighter_use ================ */ void Fighter_use( gentity_t *self, gentity_t *other, gentity_t *activator) { G_ActivateBehavior(self,BSET_USE); self->flags &= ~FL_SHIELDED; NPC_SetAnim( self, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); // self->NPC->localState = LSTATE_WAKEUP; self->NPC->localState = FSTATE_ACTIVE; } /* ------------------------- NPC_Fighter_Pain ------------------------- */ void NPC_Fighter_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc ) { NPC_Pain( self, inflictor, other, point, damage, mod ); if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT ) { self->NPC->burstCount = 0; TIMER_Set( self, "attackDelay", Q_irand( 9000, 12000) ); self->flags |= FL_SHIELDED; NPC_SetAnim( self, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); G_SoundOnEnt( self, CHAN_AUTO, "sound/chars/fighter/misc/fighter_pain" ); self->NPC->localState = FSTATE_ACTIVE; } // You got hit, go after the enemy if (self->NPC->localState == FSTATE_ASLEEP) { G_Sound( self, G_SoundIndex("sound/chars/Fighter/misc/shieldsopen.wav")); //self->flags &= ~FL_SHIELDED; NPC_SetAnim( self, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); self->NPC->localState = FSTATE_WAKEUP; } }
Asgarath83 Posted July 26, 2017 Author Posted July 26, 2017 it's a WIP, so not fully 100% garantuee to works perfect. but for some nice fighter ship boss should be sufficient. Noodle and Lancelot like this
Asgarath83 Posted July 27, 2017 Author Posted July 27, 2017 Oh, ywes, i just missed up...weapons groped into categories for fighter combact tacticts (fighter can switch weapon at secund of circustances and player distance. weapon available are the same that modder get to NPC into ext_data npc file.on g_weapon.cpp // WEAPONS CATEGORIES FOR STARFIGHTERS! qboolean seekerWeap(int wp)//seeker missiles { switch (wp) { case WP_ROCKET_LAUNCHER: case WP_BOWCASTER: return qtrue; } return qfalse; } qboolean bombsWeap(int wp)//elementals { switch (wp) { case WP_REPEATER: case WP_POISON: case WP_DET_PACK: case WP_THERMAL: case WP_TRIP_MINE: return qtrue; } return qfalse; } qboolean laserWeap(int wp)// Arrows { switch (wp) { case WP_BLASTER_PISTOL: // green laser - short case WP_BRYAR_PISTOL: // red laser case WP_POISON: // chemical weapon case WP_BLASTER: // greenlaser case WP_JAWA: // yellow lasers case WP_BLOODGUN: // blue lasers return qtrue; } return qfalse; } qboolean chaffWeap(int wp)// Life&Necro { switch (wp) { case WP_FLECHETTE: case WP_DEMP2: return qtrue; } return qfalse; } qboolean specialWeap(int wp) // Melee fight { switch (wp) { case WP_CONCUSSION: // am rocket case WP_DISRUPTOR: case WP_ATST_MAIN: // blue laser case WP_ATST_SIDE: case WP_EMPLACED_GUN: return qtrue; } return qfalse; } // Weapon Helper Functions float weaponSpeed[WP_NUM_WEAPONS][2] = { weapons.h typedef enum { WEAPS_FIGHTER, WEAPS_LASER, WEAPS_SEEKER,// Glifiche WEAPS_BOMBS,// Arrows WEAPS_CHAFF,// nec Holy WEAPS_SPECIAL, // Explosive WEAPS_OTHER2 } weaponGroup2;//for fighter NPC_combatassign weapon group for fighters to weapons headers. extern qboolean seekerWeap(int wp); extern qboolean laserWeap(int wp); extern qboolean bombsWeap(int wp); extern qboolean chaffWeap(int wp); extern qboolean specialWeap(int wp); qboolean WeaponFighters(int weapon, int wpnGroup, int altFire = 0) {//this and the funcs it calls do the heavy lifting for weapon grouping if ((seekerWeap(weapon) && wpnGroup == WEAPS_SEEKER) // || (laserWeap(weapon) && wpnGroup == WEAPS_LASER) // || (bombsWeap(weapon) && wpnGroup == WEAPS_BOMBS) // || (chaffWeap(weapon) && wpnGroup == WEAPS_CHAFF )// || ( specialWeap(weapon) && wpnGroup == WEAPS_SPECIAL ) // || wpnGroup == WEAPS_FIGHTER ) { return qtrue; } return qfalse; }
Asgarath83 Posted July 27, 2017 Author Posted July 27, 2017 Okay, now i upgraded the fighter_steer function. flight is much better. is not acrobatic. but fighter chase enemy very fast and when they are close brake itself and fly around, strafing and shooting, and ever facing the enemy.like swoop pilots, but with strafing of sentry,. noooot bad.they need just a lot of acceleration of speed (but is facoltative: if player drive a fighter and is ever running forward, also if fighter reach target, they cannot completely round enemy because enemy is away pretty fast so they are forced to chase it again!and so, for flight i think this AI is okay. they are static only against static objectives, so i think is okay. just a lot of acceleration for avoid stupid swoopfights in case there are enemy fighter against teammate npc fighters. two things to fix:- weapons: there is some interference between this function and weapon tactive... fighters shoots rarely when they chase enemy and shoot nice and with a good rate of fire only when they are pretty close. i want more aggression!- ground distance (they fly too near to ground is player is walking or running or ground -.- ) sometime i see the fighter landing and ... walking??? a tie fighter walking in the grass??? totally madness. need to tell to have more distance by ground and NEVER touch the ground or level geometry. for other things, AI is completed so after i take a looong break... and after i will see if is possible to make something like a drivable fighter like a drivable atst... but honestly i not have much hope in that sense. is pretty complex like code and require multiple file working also for HUD and interface.
Lancelot Posted July 27, 2017 Posted July 27, 2017 @@Asgarath83Can you make a video of your what you've done so far? It's not just for curiosity, but it could be also helpful for other modders, so they can help you if you need support. Asgarath83 and Jeff like this
Asgarath83 Posted July 27, 2017 Author Posted July 27, 2017 mmm a video with fraps? it's long time i not update a video on youtube, but,... okay.really i need an hand with this fucked code for end the stuff. also, if is possible to contact who does the client fly code for jk2... maybe there is something useful that i use for fix AI and for client fly.( not worry if in the video not listen all sound correctly because weapon system of fighter is WIP and also special effects of weapons are just placeholders. ) .
Asgarath83 Posted July 27, 2017 Author Posted July 27, 2017 i take some snapshot and cutscene but is very laggy.windows movie maker crash every 2 second so i need to found some other program for mount the clips, convert and host on youtube.>.<
Noodle Posted July 28, 2017 Posted July 28, 2017 i take some snapshot and cutscene but is very laggy.windows movie maker crash every 2 second so i need to found some other program for mount the clips, convert and host on youtube.>.< I use Open Broadcaster Software, it's much better than fraps and I can upload the clip directly to youtube.
Asgarath83 Posted July 28, 2017 Author Posted July 28, 2017 I use Open Broadcaster Software, it's much better than fraps and I can upload the clip directly to youtube. eh, my fraps is shareware too. i not know how to find a full version.it's free your program?can run on an old xp sp3? tryed,... not run on xp, but on vista with direct x 10. >.<i will search some other. i need just to mount 3 clipscenes.
Asgarath83 Posted July 28, 2017 Author Posted July 28, 2017 uff, painful... i'll never be a youtuber.disabled the audio for making the video more light as possible .4 minutes of test. you can see fighter in fly hunting approach and strafing, some shooting (effects of shoot are placeholders for moments ) and a fighter destroyed by player shoots. and two fighters fight each others into the sky. for moment, fly and shoot is the best part. dogfight is horrible. making you some laughts:see the video with this music:
Noodle Posted July 28, 2017 Posted July 28, 2017 Not related, but that legacy of kain custom look is looking pretty good! Asgarath83 likes this
Asgarath83 Posted July 28, 2017 Author Posted July 28, 2017 Not related, but that legacy of kain custom look is looking pretty good!thanks. the map is full of all soul reaver map objects on MD3 format. is a test map of md3 that i used for fly test because is great enough for flight zone. Kain use energy bolt and some kind of bleeding fire attack. Honestly however, i hope in some mod feedback yes i know video is too laggy and fighters not seems to shoot good.was just for show the stupid flight behavour.for shooting i have fixed efx only today.
Asgarath83 Posted July 31, 2017 Author Posted July 31, 2017 shoot behavour is pretty close to complete.now on fighter_tactictselect i add the field for flight behavour /////// Fighter fly behavours///////////////////////////////////////////////////////// float fighterflightDistance = Distance(NPC->currentOrigin, NPC->enemy->currentOrigin); bool fighterEvasionRange = (fighterflightDistance<FIGHTER_SHOOTRANGEMIN); // If enemy is Near, try some evasion shooting chaffs bool fighterRoundRange = (fighterDistance>FIGHTER_SHOOTRANGEMIN && fighterDistance<FIGHTER_SHOOTRANGEMED); // if enemy is close, fly round him shoot him with laser bool fighterBrakeRange = (fighterDistance>FIGHTER_SHOOTRANGEMED && fighterDistance<FIGHTER_SHOOTRANGEMAX);// if you are a bomber nd you are sufficiently far from target. stay on target nnd bombarding. // Evasion: (only for fighter, not for cruisers or big ships) if enemy is shooted by player flee with evasion manouvre (rolling, strafing) so we have 2 evasion behavour: one with fighter equiped with chaff weapons, it shoot chaff and making evasion by a close enemy.the other for fighter generically shooted. they rolled and strafe... if health of fighter is low, they will try to escape.attack fly manouvre, instead is basically: for bombers tht carry bombs, they stay in front or upon target bombarding it. for fighter with lsers, they fly round target like an wp_rocket altfire homing missile, shooting him...nd now is the hard task: how can i archive all that stuff????? o.ony help suggest? in JKA there are not much coding example about behavours like thats...rolling is the more easy i think becuse the probe droid tilts they head and interrogator model tilt on itself entire model if you use a humanoid model with interrogator NPC default...but the others... damn. :S (if i have success AI of fighter is finished! )
Asgarath83 Posted July 31, 2017 Author Posted July 31, 2017 mmm i noticed that the seeker and remote_sp fly round the player... maybe i can use this behavour for round dogfight...
Asgarath83 Posted August 1, 2017 Author Posted August 1, 2017 Added an alpha test version of SEEKER AI code parameter for dogfight combat... i admit fighter are much better know. i will do the necessary edit at the end of works. i think now is time to pass to client and make a playable fighter...Oh, my >.< Jeff likes this
Asgarath83 Posted August 2, 2017 Author Posted August 2, 2017 Today work: :- try to make a custom HUD drawing like atst but again HUD is not displayed and changed when i do "playermodel tiefighter" so it's again something missed up. but the function for drawing is wrote.- worked on bg_pmove about movement. i have forced CLASS_FIGHTER to use the FLY_VEHICLE mode modality of fighter flying vehicle and this get some progress.a playermodeled fighter cannot again leave by ground and fly (i need again to found how to set the command for do that i guess).weapon switch work properly 50% (there is a glitch when a fighter get as weapon the lightsaber if i use playermodel before switch to a shoot weapon)- NPC Fighter: much better with FLY_VEHICLE move that with default NPC fly move: they are slow as snails now so i think i need to set better the velocity paramater but they now float and fly properly without no more stupid walking in the ground (yes... fighter walks into the grounds until now if they touch ground XDD ) So what is missing:NPC:- properly velocity fix- weapon bug fix (some time shoot 23942309423492342 repeater alt concussion together )- evasion manouvre when hitted \ low health (rolling, flee? )- better aggressive manouvre (fly round an enemy, strafing? ) playable fighter:- correct hud draw display- camera fix (insanely attacked to the ass of the fighter )- correct "atst drivable" modality enabled for the class if is on playermodel- correct fly movements.- fix toggle weapons after that... we have our space battle game! i am at 50% of code work. Noodle and Lancelot like this
Asgarath83 Posted August 4, 2017 Author Posted August 4, 2017 great progress with client playable fighter!!! i create a specific class for players called OLON and i added on npc_spawn.cpp that a team player olon class get the drivable atst attributes... results:https://postimg.org/gallery/3g5jqqfg6/ now i need just a workaround to fix all bug and glitchs and change the moving by walking to flying. else if ( ent->client->NPC_class == CLASS_OLON ) {// Drivable fighter vehicle ent->NPC->defaultBehavior = BS_CINEMATIC; // don't attack! damn it! ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); extern void NPC_ATST_Precache(void); extern void NPC_PrecacheAnimationCFG( const char *NPC_type ); ent->s.modelindex = G_ModelIndex( "models/players/atst/model.glm" ); ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, "models/players/atst/model.glm", ent->s.modelindex, NULL_HANDLE, NULL_HANDLE, 0, 0 ); ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "model_root", qtrue ); ent->craniumBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cranium", qtrue ); //FIXME: need to somehow set the anim/frame to the equivalent of BOTH_STAND1... use to be that BOTH_STAND1 was the first frame of the glm, but not anymore ent->s.radius = 320; VectorSet( ent->s.modelScale, 1.0f, 1.0f, 1.0f ); //register my weapons, sounds and model RegisterItem( FindItemForWeapon( WP_ATST_MAIN )); //precache the weapon RegisterItem( FindItemForWeapon( WP_ATST_SIDE )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN )); //precache the weapon // RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon // RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? G_SoundIndex( "sound/chars/atst/atst_hatch_open" ); G_SoundIndex( "sound/chars/atst/atst_hatch_close" ); NPC_ATST_Precache(); ent->NPC_type = (char *)"atst"; NPC_PrecacheAnimationCFG( ent->NPC_type ); //open the hatch //misc_atst_setanim( ent, ent->rootBone, BOTH_STAND2 ); gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "head_hatchcover", 0 ); VectorSet( ent->mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 ); VectorSet( ent->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 ); ent->contents = CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; ent->flags |= FL_SHIELDED; ent->takedamage = qtrue; if ( !ent->health ) { ent->health = 800; } ent->s.radius = 320; ent->max_health = ent->health; // cg_draw needs this G_SetOrigin( ent, ent->s.origin ); G_SetAngles( ent, ent->s.angles ); VectorCopy( ent->currentAngles, ent->s.angles2 ); gi.linkentity ( ent ); //FIXME: test the origin to make sure I'm clear? ent->e_UseFunc = useF_misc_atst_use; ent->svFlags |= SVF_PLAYER_USABLE; //make it able to take damage and die when you're not in it... //do an explosion and play the death anim, remove use func. ent->e_DieFunc = dieF_misc_atst_die; } just a copy paste of SP_misc_atst_drivable function by g_misc.cpp , but it works!https://s2.postimg.org/weuxlyont/LOL1.jpghttps://s2.postimg.org/e0kehzcd5/LOL2.jpghttps://s2.postimg.org/sxsvizpll/LOL3.jpghttps://s2.postimg.org/gkg1c2zx5/LOL4.jpg Noodle likes this
Asgarath83 Posted August 4, 2017 Author Posted August 4, 2017 great progress with client playable fighter!!! i create a specific class for players called OLON and i added on npc_spawn.cpp that a team player olon class get the drivable atst attributes... results:https://postimg.org/gallery/3g5jqqfg6/ now i need just a workaround to fix all bug and glitchs and change the moving by walking to flying. else if ( ent->client->NPC_class == CLASS_OLON ) {// Drivable fighter vehicle ent->NPC->defaultBehavior = BS_CINEMATIC; // don't attack! damn it! ent->client->ps.gravity = 0; ent->svFlags |= SVF_CUSTOM_GRAVITY; ent->client->moveType = MT_FLYSWIM; ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" ); extern void NPC_ATST_Precache(void); extern void NPC_PrecacheAnimationCFG( const char *NPC_type ); ent->s.modelindex = G_ModelIndex( "models/players/atst/model.glm" ); ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, "models/players/atst/model.glm", ent->s.modelindex, NULL_HANDLE, NULL_HANDLE, 0, 0 ); ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "model_root", qtrue ); ent->craniumBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cranium", qtrue ); //FIXME: need to somehow set the anim/frame to the equivalent of BOTH_STAND1... use to be that BOTH_STAND1 was the first frame of the glm, but not anymore ent->s.radius = 320; VectorSet( ent->s.modelScale, 1.0f, 1.0f, 1.0f ); //register my weapons, sounds and model RegisterItem( FindItemForWeapon( WP_ATST_MAIN )); //precache the weapon RegisterItem( FindItemForWeapon( WP_ATST_SIDE )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN )); //precache the weapon // RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon // RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? G_SoundIndex( "sound/chars/atst/atst_hatch_open" ); G_SoundIndex( "sound/chars/atst/atst_hatch_close" ); NPC_ATST_Precache(); ent->NPC_type = (char *)"atst"; NPC_PrecacheAnimationCFG( ent->NPC_type ); //open the hatch //misc_atst_setanim( ent, ent->rootBone, BOTH_STAND2 ); gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "head_hatchcover", 0 ); VectorSet( ent->mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 ); VectorSet( ent->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 ); ent->contents = CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP; ent->flags |= FL_SHIELDED; ent->takedamage = qtrue; if ( !ent->health ) { ent->health = 800; } ent->s.radius = 320; ent->max_health = ent->health; // cg_draw needs this G_SetOrigin( ent, ent->s.origin ); G_SetAngles( ent, ent->s.angles ); VectorCopy( ent->currentAngles, ent->s.angles2 ); gi.linkentity ( ent ); //FIXME: test the origin to make sure I'm clear? ent->e_UseFunc = useF_misc_atst_use; ent->svFlags |= SVF_PLAYER_USABLE; //make it able to take damage and die when you're not in it... //do an explosion and play the death anim, remove use func. ent->e_DieFunc = dieF_misc_atst_die; } just a copy paste of SP_misc_atst_drivable function by g_misc.cpp , but it works!https://s2.postimg.org/weuxlyont/LOL1.jpghttps://s2.postimg.org/e0kehzcd5/LOL2.jpghttps://s2.postimg.org/sxsvizpll/LOL3.jpghttps://s2.postimg.org/gkg1c2zx5/LOL4.jpgShould be hard for first person view enabled \ disenable a cockpit but i will think to that when AI and client playable are alls okay! :3 otherwise, i found also a way for make that fighters and olons fly around to player... this is niceful! (but i need to do that only for enemy fighters they are really silly in move,ment and orientations but it works. they seems like sharks that swim around their lunch.well, at this point i get all features... i need just to recode all for fix 3000 thousand of glitches. Noodle likes this
Asgarath83 Posted August 7, 2017 Author Posted August 7, 2017 @@Noodle i see only now you question about first person of the swoop... mmm again not . i will implement the first person stuff after i understand i work Atst drivable HUD stuff and swoop stuff. is not much easy to do a cockpit displaying... but i think that the way where in force sense you can see the crop aura effect when you active the force power can be a good hint about that draw \ hide this.about cockpit... if someone can do a nice cockpit fighter image tga \ png and a radar icon fighters i can use i will be thankful. i am not much good with paint shop pro\ photoshop stuff. the health bar is okay and is like any other playable vehicle now.should be wonderful maybre a cockpit like X wing Alliance game? they was pretty cool! Noodle likes this
Noodle Posted August 7, 2017 Posted August 7, 2017 about cockpit... if someone can do a nice cockpit fighter image tga \ png and a radar icon fighters i can use i will be thankful. i am not much good with paint shop pro\ photoshop stuff. the health bar is okay and is like any other playable vehicle now.should be wonderful maybre a cockpit like X wing Alliance game? they was pretty cool! I'm hoping someone can do a nice interior HUD!
Lancelot Posted August 7, 2017 Posted August 7, 2017 I'm hoping someone can do a nice interior HUD!Maybe something like Star Wars Starfighter has? It's simple and similar to the HUD from Jedi Academy.
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