-
Posts
2,023 -
Joined
-
Last visited
Content Type
Profiles
News Articles
Tutorials
Forums
Downloads
Everything posted by Asgarath83
-
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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. -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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: -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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. -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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. >.< -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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. ) . -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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. -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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_combat assign 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; } -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
it's a WIP, so not fully 100% garantuee to works perfect. but for some nice fighter ship boss should be sufficient. -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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; } } -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
AI: AI_SENTRY at 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; } -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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 ); } -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
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. -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
I see that my fighters do something like that when i use "notarget" cheat when they use WP_THERMAL as weapon and stop to bombard me... i suppose that you can use with drivable team neutral now with icarus scripting SET ANIMATION and cinematic spawning. BOTH_SWIM_IDLE1 animation in loop allow to see the fighter float in place (i not know really how damn fix the fly movement of player and enemy teams ffighters so i think now i pass to drivable code so after i need just to debugging the work. -
The Trick For People Who Want Diffrent Guns For Npcs.
Asgarath83 replied to Langerd's topic in Mod Requests & Suggestions
The only problem is that the new weapon JAWA clone cannomt have custom effects of projectiles, wall impact and flesh impact. i know about the unfinishede jawa weapon. also bryar pistol of kyle katarn. these 3 weapons use in common the same effects for shoots of blaster pistol. i ever thinked that is a little shame because they are too rendundant into original game. so in my mod i coded the weapons for have 3 different effects arrays, so they are completely separated and stand alone weapons. WP_JAWA is a sonic weapon ... pity is not possible to customize weapons efx and sfx without code hacking. also, the code edit for assign cutom efx to weapon at second opf NPC or user's classes is not compatible with EF_BOUNCE function and so for changing with code effect of WP_FLECHETTE i removed the bouncing of projectiles ._. (same on bowcaster alt fire weapons :\ ) should be really wonderful a little code edit of ext_data weapons.dat file with new field that allow to modder to add custom effects on the weapons and models at second of class users. so is possible to doing that without code hacking. maybe also changing damage that npc do with weapons when shoots into the same customizable ways. in that mode, also with with 64 AI classes x 32 weapons, with something like that available, also without adding new weapons in the code every modder with no c++ knowledge can recycle physic and weapon slots and get all weapon they desires! (i know how to customize that on code, but i cannot again customize weapon icons, weapon descs and weapon models with code editing ._. ) so my suggest is: why not do that on some coded mode version of openjk? weapons fully editable with weapons.dat, without any code hacking needed... should be a wonderfuil dreams that become true! @@Langerd you are a totally genius! great idea about the WP_JAWA. pity that this require scripting for fully working ... but for mod developer is a great suggest -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
Not really in the AI of stormtroopers default called by human merc (they are stormtroopers, basically). if you do a map and place a swoop near to every kind of humanoid enemy, trandoshan, weequay, stormies, mercs, rodians, etc. they automatically when player is near go to nearest vehicle and jump on it and become npc + vehicle that flank, chase and shoot the player. in escape from yavin 4 the lost map the four and fifth level you can see trandoshan and also zabrak iridonian sith assassin that use swoop for chase players, so is not a behavour setted only for human merc. ALL humanoid npcs with a swoop near do that! so is a common function for all AI. tpday i see this behavour is setted on AI_vehicle.cpp this is the code of AI of pilots on a swoops that use swoop for chase players. //////////////////////////////////////////////////////////////////////////////////////// // Pilot_MasterUpdate() - Master think function for Pilot NPCs // // Will return true if the character is either driving a vehicle or on his way to get // onto one. //////////////////////////////////////////////////////////////////////////////////////// bool Pilot_MasterUpdate() { if (!NPC->enemy) { // If Still On A Vehicle, Jump Off //--------------------------------- if (NPCInfo->greetEnt) { ucmd.upmove = 127; if (NPCInfo->greetEnt && NPCInfo->greetEnt->m_pVehicle && (level.time<NPCInfo->confusionTime||level.time<NPCInfo->insanityTime)) { Vehicle_t* pVeh = NPCInfo->greetEnt->m_pVehicle; if (!(pVeh->m_ulFlags&VEH_OUTOFCONTROL)) { gentity_t* parent = pVeh->m_pParentEntity; float CurSpeed = VectorLength(parent->client->ps.velocity); pVeh->m_pVehicleInfo->StartDeathDelay(pVeh, 10000); pVeh->m_ulFlags |= (VEH_OUTOFCONTROL); VectorScale(parent->client->ps.velocity, 1.25f, parent->pos3); if (CurSpeed<pVeh->m_pVehicleInfo->speedMax) { VectorNormalize(parent->pos3); if (fabsf(parent->pos3[2])<0.25f) { VectorScale(parent->pos3, (pVeh->m_pVehicleInfo->speedMax * 1.25f), parent->pos3); } else { VectorScale(parent->client->ps.velocity, 1.25f, parent->pos3); } } } } if (NPCInfo->greetEnt->owner==NPC) { return true; } NPCInfo->greetEnt = 0; } // Otherwise Nothing To See Here //------------------------------- return false; } // If We Already Have A Target Vehicle, Make Sure It Is Still Valid //------------------------------------------------------------------ if (NPCInfo->greetEnt) { if (!NPCInfo->greetEnt->inuse || !NPCInfo->greetEnt->m_pVehicle || !NPCInfo->greetEnt->m_pVehicle->m_pVehicleInfo) { NPCInfo->greetEnt = Vehicle_Find(NPC); } else { if (NPCInfo->greetEnt->owner && NPCInfo->greetEnt->owner!=NPC) { NPCInfo->greetEnt = Vehicle_Find(NPC); } } } // If We Have An Enemy, Try To Find A Vehicle Nearby //--------------------------------------------------- else { NPCInfo->greetEnt = Vehicle_Find(NPC); } // If No Vehicle Available, Continue As Usual //-------------------------------------------- if (!NPCInfo->greetEnt) { return false; } if (NPCInfo->greetEnt->owner==NPC) { Pilot_Steer_Vehicle(); } else { Pilot_Goto_Vehicle(); } Pilot_Update_Enemy(); return true; } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Pilot_Update_Enemy() { if (!TIMER_Exists(NPC, "PilotRemoveTime")) { TIMER_Set(NPC, "PilotRemoveTime", MIN_STAY_VIEWABLE_TIME); } if (TIMER_Done(NPC, "NextPilotCheckEnemyTime")) { TIMER_Set(NPC, "NextPilotCheckEnemyTime", Q_irand(1000,2000)); if (NPC->enemy && Distance(NPC->currentOrigin, NPC->enemy->currentOrigin)>1000.0f) { mPilotViewTraceCount ++; gi.trace(&mPilotViewTrace, NPC->currentOrigin, 0, 0, NPC->enemy->currentOrigin, NPC->s.number, MASK_SHOT, (EG2_Collision)0, 0); if ((mPilotViewTrace.allsolid==qfalse) && (mPilotViewTrace.startsolid==qfalse ) && ((mPilotViewTrace.entityNum==NPC->enemy->s.number)||(mPilotViewTrace.entityNum==NPC->enemy->s.m_iVehicleNum))) { TIMER_Set(NPC, "PilotRemoveTime", MIN_STAY_VIEWABLE_TIME); } } else { TIMER_Set(NPC, "PilotRemoveTime", MIN_STAY_VIEWABLE_TIME); } } if (TIMER_Done(NPC, "PilotRemoveTime")) { if (NPCInfo->greetEnt->owner==NPC) { NPCInfo->greetEnt->e_ThinkFunc = thinkF_G_FreeEntity; NPCInfo->greetEnt->nextthink = level.time; } NPC->e_ThinkFunc = thinkF_G_FreeEntity; NPC->nextthink = level.time; } } //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Pilot_Goto_Vehicle() { STEER::Activate(NPC); { if (STEER::Reached(NPC, NPCInfo->greetEnt, 80.0f)) { NPC_Use(NPCInfo->greetEnt, NPC, NPC); } else if (NAV::OnNeighboringPoints(NPC, NPCInfo->greetEnt)) { STEER::Persue(NPC, NPCInfo->greetEnt, 50.0f, 0.0f, 30.0f, 0.0f, true); } else { if (!NAV::GoTo(NPC, NPCInfo->greetEnt)) { STEER::Stop(NPC); } } } STEER::AvoidCollisions(NPC); STEER::DeActivate(NPC, &ucmd); NPC_UpdateAngles(qtrue, qtrue); } extern bool VEH_StartStrafeRam(Vehicle_t *pVeh, bool Right); //////////////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////////////// void Pilot_Steer_Vehicle() { 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, 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, FUTURE_PRED_DIST); ESide EnemySide = ActorPos.LRTest(EnemyPos, EnemyFuturePos); CVec3 EnemyFlankPos(EnemyFuturePos); EnemyFlankPos.ScaleAdd(EnemyRight, (EnemySide==Side_Right)?(FUTURE_SIDE_DIST)-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<ATTACK_FLANK_SLOWING) { NPC->client->ps.speed *= (MoveDistance/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/ATTACK_FLANK_SLOWING); EnemyDirection *= 1.0f - (MoveDistance/ATTACK_FLANK_SLOWING); MoveDirection += EnemyDirection; if (TIMER_Done(NPC, "RamCheck")) { TIMER_Set(NPC, "RamCheck", Q_irand(1000, 3000)); if (MoveDistance<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>ATTACK_FWD) { if (NPC->client->ps.weapon!=WP_NONE) { NPC_ChangeWeapon(WP_NONE); } ucmd.buttons |= BUTTON_ATTACK; } else if (AimAccuracy<AIM_SIDE && AimAccuracy>-AIM_SIDE) { if (NPC->client->ps.weapon!=WP_BLASTER) { NPC_ChangeWeapon(WP_BLASTER); } if (AimAccuracy<ATTACK_SIDE && AimAccuracy>-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); } another interessing AI is NPCfighter.cpp but really i am hard to understand that or how to use that. there are 1700 line of code and many parts are unchucked and note used by the game. seems the AI of drivable tie fighter vehicle or something like that. -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
Oh, okay, crash is caused by concussion weapon. this is a good news. a little fix to weapon system and combat ai is pretty near to close. i checked the dogfight with a tiefighter enemy against a friendly tie... ,mmm they fight one against other like two rockettroopers of different teams... not exactly much good to see for fighters... should be good maybe for cruisers or big starships... but for fighters... it need really some big improvement about movement. the unique think i have in mind is to give to fighter AI the boost movement forward of a swoop driven by a foe. /if fighters attacks like swoop merc on t2_trip shold be good i guess. ) -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
eh, i dreamed about rogue squadron and XWA but really this need a TRUELY expert coder with vectors and AIs. i cannot attempt nothing to these levels. the unique way for do something like that in "easy way" is to get the fighter movement like the alt fire rocket projectile weapon when they are in some evasion modality and they are near to objective to destroy. but the code of a weapon is not muchn compatible with a code of an AI. so for moment i not know how to do that. now i search a video about what you talking. oh, impressive, i played the first battlefront but this is amazing! D: however my tie fighter AI attacks like the shadows of the empire tie fighters of asteroid belt level (but with more strafing) however yes, the goal is to get something more possible similar to: on JKA. i failed to apply a seeker movement to fighter when they purchase a enemy for moment. .-. massive crash when they start to do that. about spawn bobbing: i am thinking to give the fighters idles the BOTH_SWIM1 animation... should be funny floating "we wait order" mode the AI should work for ENEMY and PLAYER team fighter (so can do also a NPC teammates squadron) the drivable fighter i think will be usable hardcoded TEAM_NEUTRAL that switch to TEAM_PLAYER when you use it. the goal is to allow it to works like Atst drivable, but you can play like a tie fighter the best goal i reached for now is that figher change weapons at second of circustamces (they prefear to use rocket launcher at distance and blaster and repeater alt fire bombs in close combat) and the death explosion. this is pretty funny because fighters when explode assume some silly position for a little moment. XD -
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
I do a lot of progress @@Ramikad and @@Noodle - removed ghouls2 models when fighter change weapons, now they shoot by their cannon the projectiles of weapons. the weapons are the same of default game but have coded custom efx and sounds. - fighter shoot by their cannons... i need a little work for allow him to alternative shoots by left and right cannon. - Enemy fighter fly like a sentry now, and not a rocketrooper. a lot of strafing and evasion movement. they strafe when they fly to player but also when their are close and attack. BUG: there is a crash with a weapon and i need again which cause it when multiple fighter shoot me at same time after i fix AI enemy fighter is near to be closed and i can check the drivable code -
well this require a lot code work also. because you need to set droid like cultistcommando npc (so dual shoot weapon enabled ). you can shoot weapons and spawn weapon models and force power by EVERY body parts you desire, not necessary the hands. you just need to move into the model project the bolt_l_hand and bolt_r_hand tag of the skeleton. this work on some monster of my mod that have bolt_l_hand in mouth and so can shoot force power by mouth and bite (because the left hand saber is... an invisibkle bite saber XD lol ) also working on my fighter AI i see is possible if you build a custom AI of a droid to set other tag for shoot projectile. on CLASS_FIGHTER fighters use the weapons, but i changed efx and snd weapons by code and in the code when fighter change weapon remove also the glm model of weapon so weapon is invisible. also the muzzle and hands tag i placed into the cannons of the tie fighter... so it works.
-
funny and strange stuff. i like it. is for morin mod? however... try to use hex editor for change gla path into glm file into models/players/_humanoid/_humanoid_cloudysent.gla i fear the troblem is that. maybe assassin droid gla is hardocoded. for what i have seen the assassin droid bubble shield is deep coded into source. all droid class of JKA are deeply coded into the AI files >.< AI_assassin_droid, AI_sentry, AI_interrogator Etc etc. class behavour is called on NPC_spawn.cpp and NPC.cpp . i see that same model have hardcoded stuff for tags and body parts. like atst drivable, for example or tie fighter vehicle.
-
i have bad feeling that the correct using of weapon models by a ghouls 2 model depend by 2 factor: - rigged with humanoid skeleton (but assassin droids use the rifle without humanoid so i not think) - correct body separation. i see that model without the separation into the 9 base meshes (head, torso, hips, l_leg, r_leg, r_arm, l_arm, l_hand, r_hand) cannot use the lightsaber. maybe is the same with this droid. also CLASS can have some weapon restriction. what is class of npc file? if it has custom animation, custom model detaching and custom skeleton the prolem lies in thats think, i guess.
-
SP new game styles (RPG - Space \ air dogfight battles)
Asgarath83 replied to Asgarath83's topic in Coding and Scripts
Thanks ^^ sick for heat pumps -.- i hate these devices. why i cannot escape on hoth on summer? : \