#include "b_local.h"#include "g_nav.h"#include "anims.h"#include "w_saber.h"#include "../namespace_begin.h"#include "../namespace_end.h"Go to the source code of this file.
Defines | |
| #define | MELEE_DIST_SQUARED 6400 |
| #define | MIN_LOB_DIST_SQUARED 65536 |
| #define | MAX_LOB_DIST_SQUARED 200704 |
| #define | REPEATER_ALT_SIZE 3 |
| #define | GENERATOR_HEALTH 25 |
| #define | TURN_ON 0x00000000 |
| #define | TURN_OFF 0x00000100 |
| #define | GALAK_SHIELD_HEALTH 500 |
Functions | |
| void | G_AddVoiceEvent (gentity_t *self, int event, int speakDebounceTime) |
| void | NPC_AimAdjust (int change) |
| qboolean | WP_LobFire (gentity_t *self, vec3_t start, vec3_t target, vec3_t mins, vec3_t maxs, int clipmask, vec3_t velocity, qboolean tracePath, int ignoreEntNum, int enemyNum, float minSpeed, float maxSpeed, float idealSpeed, qboolean mustHit) |
| void | G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath) |
| qboolean | BG_CrouchAnim (int anim) |
| qboolean | NPC_CheckPlayerTeamStealth (void) |
| void | NPC_GalakMech_Precache (void) |
| void | NPC_GalakMech_Init (gentity_t *ent) |
| void | GM_Dying (gentity_t *self) |
| void | NPC_SetPainEvent (gentity_t *self) |
| void | NPC_GM_Pain (gentity_t *self, gentity_t *attacker, int damage) |
| void | NPC_BSGM_Patrol (void) |
| void | NPC_GM_StartLaser (void) |
| void | GM_StartGloat (void) |
| void | NPC_BSGM_Attack (void) |
| void | NPC_BSGM_Default (void) |
|
|
Definition at line 26 of file NPC_AI_GalakMech.c. Referenced by NPC_BSGM_Default(), and NPC_GalakMech_Init(). |
|
|
Definition at line 23 of file NPC_AI_GalakMech.c. Referenced by NPC_BSGM_Attack(), and NPC_BSGM_Default(). |
|
|
Definition at line 21 of file NPC_AI_GalakMech.c. Referenced by NPC_BSGM_Attack(). |
|
|
Definition at line 19 of file NPC_AI_GalakMech.c. Referenced by NPC_BSGM_Attack(). |
|
|
Definition at line 20 of file NPC_AI_GalakMech.c. Referenced by NPC_BSGM_Attack(). |
|
|
Definition at line 22 of file NPC_AI_GalakMech.c. |
|
|
Definition at line 25 of file NPC_AI_GalakMech.c. |
|
|
Definition at line 24 of file NPC_AI_GalakMech.c. |
|
|
Definition at line 49 of file bg_panimate.c.
00050 {
00051 switch ( anim )
00052 {
00053 case BOTH_SIT1: //# Normal chair sit.
00054 case BOTH_SIT2: //# Lotus position.
00055 case BOTH_SIT3: //# Sitting in tired position: elbows on knees
00056 case BOTH_CROUCH1: //# Transition from standing to crouch
00057 case BOTH_CROUCH1IDLE: //# Crouching idle
00058 case BOTH_CROUCH1WALK: //# Walking while crouched
00059 case BOTH_CROUCH1WALKBACK: //# Walking while crouched
00060 case BOTH_CROUCH2TOSTAND1: //# going from crouch2 to stand1
00061 case BOTH_CROUCH3: //# Desann crouching down to Kyle (cin 9)
00062 case BOTH_KNEES1: //# Tavion on her knees
00063 case BOTH_CROUCHATTACKBACK1://FIXME: not if in middle of anim?
00064 case BOTH_ROLL_STAB:
00065 return qtrue;
00066 break;
00067 }
00068 return qfalse;
00069 }
|
|
||||||||||||||||
|
Definition at line 23 of file NPC_sounds.c.
00024 {
00025 if ( !self->NPC )
00026 {
00027 return;
00028 }
00029
00030 if ( !self->client || self->client->ps.pm_type >= PM_DEAD )
00031 {
00032 return;
00033 }
00034
00035 if ( self->NPC->blockedSpeechDebounceTime > level.time )
00036 {
00037 return;
00038 }
00039
00040 if ( trap_ICARUS_TaskIDPending( self, TID_CHAN_VOICE ) )
00041 {
00042 return;
00043 }
00044
00045
00046 if ( (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK) && ( (event >= EV_ANGER1 && event <= EV_VICTORY3) || (event >= EV_CHASE1 && event <= EV_SUSPICIOUS5) ) )//(event < EV_FF_1A || event > EV_FF_3C) && (event < EV_RESPOND1 || event > EV_MISSION3) )
00047 {
00048 return;
00049 }
00050
00051 if ( (self->NPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) )
00052 {
00053 return;
00054 }
00055 //FIXME: Also needs to check for teammates. Don't want
00056 // everyone babbling at once
00057
00058 //NOTE: was losing too many speech events, so we do it directly now, screw networking!
00059 //G_AddEvent( self, event, 0 );
00060 G_SpeechEvent( self, event );
00061
00062 //won't speak again for 5 seconds (unless otherwise specified)
00063 self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime);
00064 }
|
|
||||||||||||||||
|
|
|
|
Definition at line 133 of file NPC_AI_GalakMech.c. References gentity_s::client, entityShared_t::currentOrigin, playerState_s::electrifyTime, FRAMETIME, G_EffectIndex(), G_FreeEntity(), G_PlayEffectID(), gentity_t, gentity_s::ghoul2, renderInfo_s::headBolt, level, gentity_s::nextthink, NPC_SetSurfaceOnOff(), gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, gentity_s::s, gentity_s::think, entityState_s::time, level_locals_t::time, TIMER_Done(), TIMER_Set(), trap_G2API_AddBolt(), trap_G2API_GetSurfaceRenderStatus(), TURN_OFF, and vec3_origin. Referenced by CorpsePhysics().
00134 {
00135 if ( level.time - self->s.time < 4000 )
00136 {//FIXME: need a real effect
00137 //self->s.powerups |= ( 1 << PW_SHOCKED );
00138 //self->client->ps.powerups[PW_SHOCKED] = level.time + 1000;
00139 self->client->ps.electrifyTime = level.time + 1000;
00140 if ( TIMER_Done( self, "dyingExplosion" ) )
00141 {
00142 int newBolt;
00143 switch ( Q_irand( 1, 14 ) )
00144 {
00145 // Find place to generate explosion
00146 case 1:
00147 if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "r_hand" ))
00148 {//r_hand still there
00149 GM_CreateExplosion( self, trap_G2API_AddBolt(self->ghoul2, 0, "*flasha"), qtrue );
00150 NPC_SetSurfaceOnOff( self, "r_hand", TURN_OFF );
00151 }
00152 else if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "r_arm_middle" ))
00153 {//r_arm_middle still there
00154 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*r_arm_elbow" );
00155 NPC_SetSurfaceOnOff( self, "r_arm_middle", TURN_OFF );
00156 }
00157 break;
00158 case 2:
00159 //FIXME: do only once?
00160 if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_hand" ))
00161 {//l_hand still there
00162 GM_CreateExplosion( self, trap_G2API_AddBolt(self->ghoul2, 0, "*flashc"), qfalse );
00163 NPC_SetSurfaceOnOff( self, "l_hand", TURN_OFF );
00164 }
00165 else if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm_wrist" ))
00166 {//l_arm_wrist still there
00167 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_arm_cap_l_hand" );
00168 NPC_SetSurfaceOnOff( self, "l_arm_wrist", TURN_OFF );
00169 }
00170 else if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm_middle" ))
00171 {//l_arm_middle still there
00172 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_arm_cap_l_hand" );
00173 NPC_SetSurfaceOnOff( self, "l_arm_middle", TURN_OFF );
00174 }
00175 else if (!trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "l_arm_augment" ))
00176 {//l_arm_augment still there
00177 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_arm_elbow" );
00178 NPC_SetSurfaceOnOff( self, "l_arm_augment", TURN_OFF );
00179 }
00180 break;
00181 case 3:
00182 case 4:
00183 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*hip_fr" );
00184 GM_CreateExplosion( self, newBolt, qfalse );
00185 break;
00186 case 5:
00187 case 6:
00188 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*shldr_l" );
00189 GM_CreateExplosion( self, newBolt, qfalse );
00190 break;
00191 case 7:
00192 case 8:
00193 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*uchest_r" );
00194 GM_CreateExplosion( self, newBolt, qfalse );
00195 break;
00196 case 9:
00197 case 10:
00198 GM_CreateExplosion( self, self->client->renderInfo.headBolt, qfalse );
00199 break;
00200 case 11:
00201 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_leg_knee" );
00202 GM_CreateExplosion( self, newBolt, qtrue );
00203 break;
00204 case 12:
00205 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*r_leg_knee" );
00206 GM_CreateExplosion( self, newBolt, qtrue );
00207 break;
00208 case 13:
00209 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_leg_foot" );
00210 GM_CreateExplosion( self, newBolt, qtrue );
00211 break;
00212 case 14:
00213 newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*r_leg_foot" );
00214 GM_CreateExplosion( self, newBolt, qtrue );
00215 break;
00216 }
00217
00218 TIMER_Set( self, "dyingExplosion", Q_irand( 300, 1100 ) );
00219 }
00220 }
00221 else
00222 {//one final, huge explosion
00223 G_PlayEffectID( G_EffectIndex("galak/explode"), self->r.currentOrigin, vec3_origin );
00224 // G_PlayEffect( "small_chunks", self->r.currentOrigin );
00225 // G_PlayEffect( "env/exp_trail_comp", self->r.currentOrigin, self->currentAngles );
00226 self->nextthink = level.time + FRAMETIME;
00227 self->think = G_FreeEntity;
00228 }
00229 }
|
|
|
Definition at line 575 of file NPC_AI_GalakMech.c. References BOTH_STAND2TO1, gentity_s::client, playerState_s::legsTimer, NPC, NPC_SetAnim(), NPC_SetSurfaceOnOff(), gclient_s::ps, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, playerState_s::torsoTimer, TURN_ON, and gentity_s::wait. Referenced by NPC_BSGM_Attack().
00576 {
00577 NPC->wait = 0;
00578 NPC_SetSurfaceOnOff( NPC, "torso_galakface", TURN_ON );
00579 NPC_SetSurfaceOnOff( NPC, "torso_galakhead", TURN_ON );
00580 NPC_SetSurfaceOnOff( NPC, "torso_eyes_mouth", TURN_ON );
00581 NPC_SetSurfaceOnOff( NPC, "torso_collar", TURN_ON );
00582 NPC_SetSurfaceOnOff( NPC, "torso_galaktorso", TURN_ON );
00583
00584 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND2TO1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00585 NPC->client->ps.legsTimer += 500;
00586 NPC->client->ps.torsoTimer += 500;
00587 }
|
|
|
Definition at line 3098 of file NPC_combat.c.
03099 {
03100 if ( !TIMER_Exists( NPC, "aimDebounce" ) )
03101 {
03102 int debounce = 500+(3-g_spskill.integer)*100;
03103 TIMER_Set( NPC, "aimDebounce", Q_irand( debounce,debounce+1000 ) );
03104 //int debounce = 1000+(3-g_spskill.integer)*500;
03105 //TIMER_Set( NPC, "aimDebounce", Q_irand( debounce, debounce+2000 ) );
03106 return;
03107 }
03108 if ( TIMER_Done( NPC, "aimDebounce" ) )
03109 {
03110 int debounce;
03111
03112 NPCInfo->currentAim += change;
03113 if ( NPCInfo->currentAim > NPCInfo->stats.aim )
03114 {//can never be better than max aim
03115 NPCInfo->currentAim = NPCInfo->stats.aim;
03116 }
03117 else if ( NPCInfo->currentAim < -30 )
03118 {//can never be worse than this
03119 NPCInfo->currentAim = -30;
03120 }
03121
03122 //Com_Printf( "%s new aim = %d\n", NPC->NPC_type, NPCInfo->currentAim );
03123
03124 debounce = 500+(3-g_spskill.integer)*100;
03125 TIMER_Set( NPC, "aimDebounce", Q_irand( debounce,debounce+1000 ) );
03126 //int debounce = 1000+(3-g_spskill.integer)*500;
03127 //TIMER_Set( NPC, "aimDebounce", Q_irand( debounce, debounce+2000 ) );
03128 }
03129 }
|
|
|
Definition at line 594 of file NPC_AI_GalakMech.c. References entityShared_t::absmax, entityShared_t::absmin, trace_t::allsolid, gentity_s::alt_fire, AngleNormalize360(), ARMOR_EFFECT_TIME, BG_CrouchAnim(), gNPC_t::blockedDebounceTime, gNPC_t::blockedSpeechDebounceTime, BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK4, BOTH_ATTACK5, BOTH_ATTACK6, BOTH_KNOCKDOWN1, BOTH_KNOCKDOWN4, BOTH_KNOCKDOWN5, BOTH_STAND1, BOTH_STAND2TO1, usercmd_s::buttons, CalcEntitySpot(), CHAN_AUTO, gentity_s::classname, gentity_s::client, CONTENTS_LIGHTSABER, gNPC_t::coverTarg, crandom, gNPC_t::currentAim, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, gNPC_t::desiredPitch, gNPC_t::desiredYaw, DistanceHorizontalSquared(), playerState_s::electrifyTime, trace_t::endpos, gentity_s::enemy, gNPC_t::enemyCheckDebounceTime, gNPC_t::enemyLastSeenLocation, gNPC_t::enemyLastSeenTime, gclient_s::enemyTeam, trace_t::entityNum, EV_ANGER1, EV_ANGER2, EV_ANGER3, EV_CHASE1, EV_COVER1, EV_ESCAPING1, EV_VICTORY1, EV_VICTORY3, renderInfo_s::eyePoint, flrand(), trace_t::fraction, G_AddVoiceEvent(), G_BoundsOverlap(), G_Damage(), G_EffectIndex(), g_entities, G_FreeEntity(), G_PlayEffectID(), G_SetOrigin(), G_Sound(), G_SoundAtLoc(), G_SoundIndex(), G_Spawn(), g_spskill, G_Throw(), GENERATOR_HEALTH, gentity_t, GM_StartGloat(), gNPC_t::goalEntity, gentity_s::health, gclient_s::hiddenDir, gclient_s::hiddenDist, HL_GENERIC1, InFront(), vmCvar_t::integer, gNPC_t::lastPathAngles, playerState_s::legsAnim, playerState_s::legsTimer, level, gentity_s::localAnimIndex, gentity_s::locationDamage, gentity_s::lockCount, entityState_s::loopSound, MASK_SHOT, MAX_LOB_DIST_SQUARED, MELEE_DIST_SQUARED, MIN_LOB_DIST_SQUARED, MOD_CRUSH, MOD_UNKNOWN, gNPC_t::movementSpeech, renderInfo_s::muzzleDir, renderInfo_s::muzzlePoint, NPC, NPC_AimAdjust(), NPC_BSGM_Patrol(), NPC_ChangeWeapon(), NPC_CheckEnemyExt(), NPC_ClearLOS4(), NPC_FaceEnemy(), NPC_GM_StartLaser(), NPC_SetAnim(), NPC_ShotEntity(), NPC_UpdateAngles(), NPCInfo, NULL, entityState_s::number, gentity_s::painDebounceTime, PITCH, gclient_s::playerTeam, playerState_s::powerups, gclient_s::ps, PW_BATTLESUIT, Q_irand(), Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, REPEATER_ALT_SIZE, gentity_s::s, SCF_ALT_FIRE, SCF_CHASE_ENEMIES, SCF_DONT_FIRE, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, SPOT_WEAPON, trace_t::startsolid, SVF_BROADCAST, entityShared_t::svFlags, gentity_s::takedamage, level_locals_t::time, TIMER_Done(), TIMER_Set(), playerState_s::torsoAnim, playerState_s::torsoTimer, gNPC_t::touchedByPlayer, trap_InPVS(), trap_Trace(), ucmd, vec3_origin, vec3_t, vectoangles(), VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, playerState_s::viewangles, gentity_s::wait, playerState_s::weapon, entityState_s::weapon, WeaponThink(), WP_LobFire(), WP_NONE, WP_REPEATER, WP_SABER, WP_TURRET, and YAW. Referenced by NPC_BSGM_Default().
00595 {
00596 //Don't do anything if we're hurt
00597 if ( NPC->painDebounceTime > level.time )
00598 {
00599 NPC_UpdateAngles( qtrue, qtrue );
00600 return;
00601 }
00602
00603 #if 0
00604 //FIXME: if killed enemy, use victory anim
00605 if ( NPC->enemy && NPC->enemy->health <= 0
00606 && !NPC->enemy->s.number )
00607 {//my enemy is dead
00608 if ( NPC->client->ps.torsoAnim == BOTH_STAND2TO1 )
00609 {
00610 if ( NPC->client->ps.torsoTimer <= 500 )
00611 {
00612 G_AddVoiceEvent( NPC, Q_irand( EV_VICTORY1, EV_VICTORY3 ), 3000 );
00613 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00614 NPC->client->ps.legsTimer += 500;
00615 NPC->client->ps.torsoTimer += 500;
00616 }
00617 }
00618 else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1START )
00619 {
00620 if ( NPC->client->ps.torsoTimer <= 500 )
00621 {
00622 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STARTGESTURE, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00623 NPC->client->ps.legsTimer += 500;
00624 NPC->client->ps.torsoTimer += 500;
00625 }
00626 }
00627 else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STARTGESTURE )
00628 {
00629 if ( NPC->client->ps.torsoTimer <= 500 )
00630 {
00631 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00632 NPC->client->ps.legsTimer += 500;
00633 NPC->client->ps.torsoTimer += 500;
00634 }
00635 }
00636 else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STOP )
00637 {
00638 if ( NPC->client->ps.torsoTimer <= 500 )
00639 {
00640 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00641 NPC->client->ps.legsTimer = -1;
00642 NPC->client->ps.torsoTimer = -1;
00643 }
00644 }
00645 else if ( NPC->wait )
00646 {
00647 if ( TIMER_Done( NPC, "gloatTime" ) )
00648 {
00649 GM_StartGloat();
00650 }
00651 else if ( DistanceHorizontalSquared( NPC->client->renderInfo.eyePoint, NPC->enemy->r.currentOrigin ) > 4096 && (NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//64 squared
00652 {
00653 NPCInfo->goalEntity = NPC->enemy;
00654 GM_Move();
00655 }
00656 else
00657 {//got there
00658 GM_StartGloat();
00659 }
00660 }
00661 NPC_FaceEnemy( qtrue );
00662 NPC_UpdateAngles( qtrue, qtrue );
00663 return;
00664 }
00665 #endif
00666
00667 //If we don't have an enemy, just idle
00668 if ( NPC_CheckEnemyExt(qfalse) == qfalse || !NPC->enemy )
00669 {
00670 NPC->enemy = NULL;
00671 NPC_BSGM_Patrol();
00672 return;
00673 }
00674
00675 enemyLOS4 = enemyCS4 = qfalse;
00676 move4 = qtrue;
00677 faceEnemy4 = qfalse;
00678 shoot4 = qfalse;
00679 hitAlly4 = qfalse;
00680 VectorClear( impactPos4 );
00681 enemyDist4 = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00682
00683 //if ( NPC->client->ps.torsoAnim == BOTH_ATTACK4 ||
00684 // NPC->client->ps.torsoAnim == BOTH_ATTACK5 )
00685 if (0)
00686 {
00687 shoot4 = qfalse;
00688 if ( TIMER_Done( NPC, "smackTime" ) && !NPCInfo->blockedDebounceTime )
00689 {//time to smack
00690 //recheck enemyDist4 and InFront
00691 if ( enemyDist4 < MELEE_DIST_SQUARED && InFront( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 0.3f ) )
00692 {
00693 vec3_t smackDir;
00694 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, smackDir );
00695 smackDir[2] += 30;
00696 VectorNormalize( smackDir );
00697 //hurt them
00698 G_Sound( NPC->enemy, CHAN_AUTO, G_SoundIndex( "sound/weapons/galak/skewerhit.wav" ) );
00699 G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->r.currentOrigin, (g_spskill.integer+1)*Q_irand( 5, 10), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_CRUSH );
00700 if ( NPC->client->ps.torsoAnim == BOTH_ATTACK4 )
00701 {//smackdown
00702 int knockAnim = BOTH_KNOCKDOWN1;
00703 if ( BG_CrouchAnim( NPC->enemy->client->ps.legsAnim ) )
00704 {//knockdown from crouch
00705 knockAnim = BOTH_KNOCKDOWN4;
00706 }
00707 //throw them
00708 smackDir[2] = 1;
00709 VectorNormalize( smackDir );
00710 G_Throw( NPC->enemy, smackDir, 50 );
00711 NPC_SetAnim( NPC->enemy, SETANIM_BOTH, knockAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00712 }
00713 else
00714 {//uppercut
00715 //throw them
00716 G_Throw( NPC->enemy, smackDir, 100 );
00717 //make them backflip
00718 NPC_SetAnim( NPC->enemy, SETANIM_BOTH, BOTH_KNOCKDOWN5, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00719 }
00720 //done with the damage
00721 NPCInfo->blockedDebounceTime = 1;
00722 }
00723 }
00724 }
00725 else if ( NPC->lockCount ) //already shooting laser
00726 {//sometimes use the laser beam attack, but only after he's taken down our generator
00727 shoot4 = qfalse;
00728 if ( NPC->lockCount == 1 )
00729 {//charging up
00730 if ( TIMER_Done( NPC, "beamDelay" ) )
00731 {//time to start the beam
00732 int laserAnim;
00733 //if ( Q_irand( 0, 1 ) )
00734 if (1)
00735 {
00736 laserAnim = BOTH_ATTACK2;
00737 }
00738 /*
00739 else
00740 {
00741 laserAnim = BOTH_ATTACK7;
00742 }
00743 */
00744 NPC_SetAnim( NPC, SETANIM_BOTH, laserAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00745 TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoTimer + Q_irand( 1000, 3000 ) );
00746 //turn on beam effect
00747 NPC->lockCount = 2;
00748 G_PlayEffectID( G_EffectIndex("galak/trace_beam"), NPC->r.currentOrigin, vec3_origin );
00749 NPC->s.loopSound = G_SoundIndex( "sound/weapons/galak/lasercutting.wav" );
00750 if ( !NPCInfo->coverTarg )
00751 {//for moving looping sound at end of trace
00752 NPCInfo->coverTarg = G_Spawn();
00753 if ( NPCInfo->coverTarg )
00754 {
00755 G_SetOrigin( NPCInfo->coverTarg, NPC->client->renderInfo.muzzlePoint );
00756 NPCInfo->coverTarg->r.svFlags |= SVF_BROADCAST;
00757 NPCInfo->coverTarg->s.loopSound = G_SoundIndex( "sound/weapons/galak/lasercutting.wav" );
00758 }
00759 }
00760 }
00761 }
00762 else
00763 {//in the actual attack now
00764 if ( NPC->client->ps.torsoTimer <= 0 )
00765 {//attack done!
00766 NPC->lockCount = 0;
00767 G_FreeEntity( NPCInfo->coverTarg );
00768 NPC->s.loopSound = 0;
00769 #if 0
00770 NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_DROPWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00771 #endif
00772 TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoTimer );
00773 }
00774 else
00775 {//attack still going
00776 //do the trace and damage
00777 trace_t trace;
00778 vec3_t end, mins={-3,-3,-3}, maxs={3,3,3};
00779 VectorMA( NPC->client->renderInfo.muzzlePoint, 1024, NPC->client->renderInfo.muzzleDir, end );
00780 trap_Trace( &trace, NPC->client->renderInfo.muzzlePoint, mins, maxs, end, NPC->s.number, MASK_SHOT );
00781 if ( trace.allsolid || trace.startsolid )
00782 {//oops, in a wall
00783 if ( NPCInfo->coverTarg )
00784 {
00785 G_SetOrigin( NPCInfo->coverTarg, NPC->client->renderInfo.muzzlePoint );
00786 }
00787 }
00788 else
00789 {//clear
00790 if ( trace.fraction < 1.0f )
00791 {//hit something
00792 gentity_t *traceEnt = &g_entities[trace.entityNum];
00793 if ( traceEnt && traceEnt->takedamage )
00794 {//damage it
00795 G_SoundAtLoc( trace.endpos, CHAN_AUTO, G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ) );
00796 G_Damage( traceEnt, NPC, NPC, NPC->client->renderInfo.muzzleDir, trace.endpos, 10, 0, MOD_UNKNOWN );
00797 }
00798 }
00799 if ( NPCInfo->coverTarg )
00800 {
00801 G_SetOrigin( NPCInfo->coverTarg, trace.endpos );
00802 }
00803 if ( !Q_irand( 0, 5 ) )
00804 {
00805 G_SoundAtLoc( trace.endpos, CHAN_AUTO, G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ) );
00806 }
00807 }
00808 }
00809 }
00810 }
00811 else
00812 {//Okay, we're not in a special attack, see if we should switch weapons or start a special attack
00813 /*
00814 if ( NPC->s.weapon == WP_REPEATER
00815 && !(NPCInfo->scriptFlags & SCF_ALT_FIRE)//using rapid-fire
00816 && NPC->enemy->s.weapon == WP_SABER //enemy using saber
00817 && NPC->client && (NPC->client->ps.saberEventFlags&SEF_DEFLECTED)
00818 && !Q_irand( 0, 50 ) )
00819 {//he's deflecting my shots, switch to the laser or the lob fire for a while
00820 TIMER_Set( NPC, "noRapid", Q_irand( 2000, 6000 ) );
00821 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00822 NPC->alt_fire = qtrue;
00823 if ( NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH && (Q_irand( 0, 1 )||enemyDist4 < MAX_LOB_DIST_SQUARED) )
00824 {//shield down, use laser
00825 NPC_GM_StartLaser();
00826 }
00827 }
00828 else*/
00829 if (// !NPC->client->ps.powerups[PW_GALAK_SHIELD]
00830 1 //rwwFIXMEFIXME: just act like the shield is down til the effects and stuff are done
00831 && enemyDist4 < MELEE_DIST_SQUARED
00832 && InFront( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 0.3f )
00833 && NPC->enemy->localAnimIndex <= 1 )//within 80 and in front
00834 {//our shield is down, and enemy within 80, if very close, use melee attack to slap away
00835 if ( TIMER_Done( NPC, "attackDelay" ) )
00836 {
00837 //animate me
00838 int swingAnim = BOTH_ATTACK1;
00839 #if 0
00840 if ( NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH )
00841 {//generator down, use random melee
00842 swingAnim = Q_irand( BOTH_ATTACK4, BOTH_ATTACK5 );//smackdown or uppercut
00843 }
00844 else
00845 {//always knock-away
00846 swingAnim = BOTH_ATTACK5;//uppercut
00847 }
00848 #endif
00849 //FIXME: swing sound
00850 NPC_SetAnim( NPC, SETANIM_BOTH, swingAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00851 TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoTimer + Q_irand( 1000, 3000 ) );
00852 //delay the hurt until the proper point in the anim
00853 TIMER_Set( NPC, "smackTime", 600 );
00854 NPCInfo->blockedDebounceTime = 0;
00855 //FIXME: say something?
00856 }
00857 }
00858 else if ( !NPC->lockCount && NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH
00859 && TIMER_Done( NPC, "attackDelay" )
00860 && InFront( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 0.3f )
00861 && ((!Q_irand( 0, 10*(2-g_spskill.integer))&& enemyDist4 > MIN_LOB_DIST_SQUARED&& enemyDist4 < MAX_LOB_DIST_SQUARED)
00862 ||(!TIMER_Done( NPC, "noLob" )&&!TIMER_Done( NPC, "noRapid" )))
00863 && NPC->enemy->s.weapon != WP_TURRET )
00864 {//sometimes use the laser beam attack, but only after he's taken down our generator
00865 shoot4 = qfalse;
00866 NPC_GM_StartLaser();
00867 }
00868 else if ( enemyDist4 < MIN_LOB_DIST_SQUARED
00869 && (NPC->enemy->s.weapon != WP_TURRET || Q_stricmp( "PAS", NPC->enemy->classname ))
00870 && TIMER_Done( NPC, "noRapid" ) )//256
00871 {//enemy within 256
00872 if ( (NPC->client->ps.weapon == WP_REPEATER) && (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
00873 {//shooting an explosive, but enemy too close, switch to primary fire
00874 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00875 NPC->alt_fire = qfalse;
00876 //FIXME: use weap raise & lower anims
00877 NPC_ChangeWeapon( WP_REPEATER );
00878 }
00879 }
00880 else if ( (enemyDist4 > MAX_LOB_DIST_SQUARED || (NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname )))
00881 && TIMER_Done( NPC, "noLob" ) )//448
00882 {//enemy more than 448 away and we are ready to try lob fire again
00883 if ( (NPC->client->ps.weapon == WP_REPEATER) && !(NPCInfo->scriptFlags & SCF_ALT_FIRE) )
00884 {//enemy far enough away to use lobby explosives
00885 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00886 NPC->alt_fire = qtrue;
00887 //FIXME: use weap raise & lower anims
00888 NPC_ChangeWeapon( WP_REPEATER );
00889 }
00890 }
00891 }
00892
00893 //can we see our target?
00894 if ( NPC_ClearLOS4( NPC->enemy ) )
00895 {
00896 NPCInfo->enemyLastSeenTime = level.time;//used here for aim debouncing, not always a clear LOS
00897 enemyLOS4 = qtrue;
00898
00899 if ( NPC->client->ps.weapon == WP_NONE )
00900 {
00901 enemyCS4 = qfalse;//not true, but should stop us from firing
00902 NPC_AimAdjust( -1 );//adjust aim worse longer we have no weapon
00903 }
00904 else
00905 {//can we shoot our target?
00906 if ( ((NPC->client->ps.weapon == WP_REPEATER && (NPCInfo->scriptFlags&SCF_ALT_FIRE))) && enemyDist4 < MIN_LOB_DIST_SQUARED )//256
00907 {
00908 enemyCS4 = qfalse;//not true, but should stop us from firing
00909 hitAlly4 = qtrue;//us!
00910 //FIXME: if too close, run away!
00911 }
00912 else
00913 {
00914 int hit = NPC_ShotEntity( NPC->enemy, impactPos4 );
00915 gentity_t *hitEnt = &g_entities[hit];
00916 if ( hit == NPC->enemy->s.number
00917 || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
00918 || ( hitEnt && hitEnt->takedamage ) )
00919 {//can hit enemy or will hit glass or other breakable, so shoot anyway
00920 enemyCS4 = qtrue;
00921 NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
00922 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
00923 }
00924 else
00925 {//Hmm, have to get around this bastard
00926 NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
00927 if ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->playerTeam )
00928 {//would hit an ally, don't fire!!!
00929 hitAlly4 = qtrue;
00930 }
00931 else
00932 {//Check and see where our shot *would* hit... if it's not close to the enemy (within 256?), then don't fire
00933 }
00934 }
00935 }
00936 }
00937 }
00938 else if ( trap_InPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ) )
00939 {
00940 int hit;
00941 gentity_t *hitEnt;
00942
00943 if ( TIMER_Done( NPC, "talkDebounce" ) && !Q_irand( 0, 10 ) )
00944 {
00945 if ( NPCInfo->enemyCheckDebounceTime < 8 )
00946 {
00947 int speech = -1;
00948 switch( NPCInfo->enemyCheckDebounceTime )
00949 {
00950 case 0:
00951 case 1:
00952 case 2:
00953 speech = EV_CHASE1 + NPCInfo->enemyCheckDebounceTime;
00954 break;
00955 case 3:
00956 case 4:
00957 case 5:
00958 speech = EV_COVER1 + NPCInfo->enemyCheckDebounceTime-3;
00959 break;
00960 case 6:
00961 case 7:
00962 speech = EV_ESCAPING1 + NPCInfo->enemyCheckDebounceTime-6;
00963 break;
00964 }
00965 NPCInfo->enemyCheckDebounceTime++;
00966 if ( speech != -1 )
00967 {
00968 G_AddVoiceEvent( NPC, speech, Q_irand( 3000, 5000 ) );
00969 TIMER_Set( NPC, "talkDebounce", Q_irand( 5000, 7000 ) );
00970 }
00971 }
00972 }
00973
00974 NPCInfo->enemyLastSeenTime = level.time;
00975
00976 hit = NPC_ShotEntity( NPC->enemy, impactPos4 );
00977 hitEnt = &g_entities[hit];
00978 if ( hit == NPC->enemy->s.number
00979 || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
00980 || ( hitEnt && hitEnt->takedamage ) )
00981 {//can hit enemy or will hit glass or other breakable, so shoot anyway
00982 enemyCS4 = qtrue;
00983 }
00984 else
00985 {
00986 faceEnemy4 = qtrue;
00987 NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
00988 }
00989 }
00990
00991 if ( enemyLOS4 )
00992 {
00993 faceEnemy4 = qtrue;
00994 }
00995 else
00996 {
00997 if ( !NPCInfo->goalEntity )
00998 {
00999 NPCInfo->goalEntity = NPC->enemy;
01000 }
01001 if ( NPCInfo->goalEntity == NPC->enemy )
01002 {//for now, always chase the enemy
01003 move4 = qtrue;
01004 }
01005 }
01006 if ( enemyCS4 )
01007 {
01008 shoot4 = qtrue;
01009 //NPCInfo->enemyCheckDebounceTime = level.time;//actually used here as a last actual LOS
01010 }
01011 else
01012 {
01013 if ( !NPCInfo->goalEntity )
01014 {
01015 NPCInfo->goalEntity = NPC->enemy;
01016 }
01017 if ( NPCInfo->goalEntity == NPC->enemy )
01018 {//for now, always chase the enemy
01019 move4 = qtrue;
01020 }
01021 }
01022
01023 //Check for movement to take care of
01024 GM_CheckMoveState();
01025
01026 //See if we should override shooting decision with any special considerations
01027 GM_CheckFireState();
01028
01029 if ( NPC->client->ps.weapon == WP_REPEATER && (NPCInfo->scriptFlags&SCF_ALT_FIRE) && shoot4 && TIMER_Done( NPC, "attackDelay" ) )
01030 {
01031 vec3_t muzzle;
01032 vec3_t angles;
01033 vec3_t target;
01034 vec3_t velocity = {0,0,0};
01035 vec3_t mins = {-REPEATER_ALT_SIZE,-REPEATER_ALT_SIZE,-REPEATER_ALT_SIZE}, maxs = {REPEATER_ALT_SIZE,REPEATER_ALT_SIZE,REPEATER_ALT_SIZE};
01036 qboolean clearshot;
01037
01038 CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
01039
01040 VectorCopy( NPC->enemy->r.currentOrigin, target );
01041
01042 target[0] += flrand( -5, 5 )+(crandom()*(6-NPCInfo->currentAim)*2);
01043 target[1] += flrand( -5, 5 )+(crandom()*(6-NPCInfo->currentAim)*2);
01044 target[2] += flrand( -5, 5 )+(crandom()*(6-NPCInfo->currentAim)*2);
01045
01046 //Find the desired angles
01047 clearshot = WP_LobFire( NPC, muzzle, target, mins, maxs, MASK_SHOT|CONTENTS_LIGHTSABER,
01048 velocity, qtrue, NPC->s.number, NPC->enemy->s.number,
01049 300, 1100, 1500, qtrue );
01050 if ( VectorCompare( vec3_origin, velocity ) || (!clearshot&&enemyLOS4&&enemyCS4) )
01051 {//no clear lob shot and no lob shot that will hit something breakable
01052 if ( enemyLOS4 && enemyCS4 && TIMER_Done( NPC, "noRapid" ) )
01053 {//have a clear straight shot, so switch to primary
01054 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
01055 NPC->alt_fire = qfalse;
01056 NPC_ChangeWeapon( WP_REPEATER );
01057 //keep this weap for a bit
01058 TIMER_Set( NPC, "noLob", Q_irand( 500, 1000 ) );
01059 }
01060 else
01061 {
01062 shoot4 = qfalse;
01063 }
01064 }
01065 else
01066 {
01067 vectoangles( velocity, angles );
01068
01069 NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] );
01070 NPCInfo->desiredPitch = AngleNormalize360( angles[PITCH] );
01071
01072 VectorCopy( velocity, NPC->client->hiddenDir );
01073 NPC->client->hiddenDist = VectorNormalize ( NPC->client->hiddenDir );
01074 }
01075 }
01076 else if ( faceEnemy4 )
01077 {//face the enemy
01078 NPC_FaceEnemy( qtrue );
01079 }
01080
01081 if ( !TIMER_Done( NPC, "standTime" ) )
01082 {
01083 move4 = qfalse;
01084 }
01085 if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )
01086 {//not supposed to chase my enemies
01087 if ( NPCInfo->goalEntity == NPC->enemy )
01088 {//goal is my entity, so don't move
01089 move4 = qfalse;
01090 }
01091 }
01092
01093 if ( move4 && !NPC->lockCount )
01094 {//move toward goal
01095 if ( NPCInfo->goalEntity
01096 /*&& NPC->client->ps.legsAnim != BOTH_ALERT1
01097 && NPC->client->ps.legsAnim != BOTH_ATTACK2
01098 && NPC->client->ps.legsAnim != BOTH_ATTACK4
01099 && NPC->client->ps.legsAnim != BOTH_ATTACK5
01100 && NPC->client->ps.legsAnim != BOTH_ATTACK7*/ )
01101 {
01102 move4 = GM_Move();
01103 }
01104 else
01105 {
01106 move4 = qfalse;
01107 }
01108 }
01109
01110 if ( !TIMER_Done( NPC, "flee" ) )
01111 {//running away
01112 faceEnemy4 = qfalse;
01113 }
01114
01115 //FIXME: check scf_face_move_dir here?
01116
01117 if ( !faceEnemy4 )
01118 {//we want to face in the dir we're running
01119 if ( !move4 )
01120 {//if we haven't moved, we should look in the direction we last looked?
01121 VectorCopy( NPC->client->ps.viewangles, NPCInfo->lastPathAngles );
01122 }
01123 if ( move4 )
01124 {//don't run away and shoot
01125 NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW];
01126 NPCInfo->desiredPitch = 0;
01127 shoot4 = qfalse;
01128 }
01129 }
01130 NPC_UpdateAngles( qtrue, qtrue );
01131
01132 if ( NPCInfo->scriptFlags & SCF_DONT_FIRE )
01133 {
01134 shoot4 = qfalse;
01135 }
01136
01137 if ( NPC->enemy && NPC->enemy->enemy )
01138 {
01139 if ( NPC->enemy->s.weapon == WP_SABER && NPC->enemy->enemy->s.weapon == WP_SABER )
01140 {//don't shoot at an enemy jedi who is fighting another jedi, for fear of injuring one or causing rogue blaster deflections (a la Obi Wan/Vader duel at end of ANH)
01141 shoot4 = qfalse;
01142 }
01143 }
01144 //FIXME: don't shoot right away!
01145 if ( shoot4 )
01146 {//try to shoot if it's time
01147 if ( TIMER_Done( NPC, "attackDelay" ) )
01148 {
01149 if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
01150 {
01151 WeaponThink( qtrue );
01152 }
01153 }
01154 }
01155
01156 //also:
01157 if ( NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname ) )
01158 {//crush turrets
01159 if ( G_BoundsOverlap( NPC->r.absmin, NPC->r.absmax, NPC->enemy->r.absmin, NPC->enemy->r.absmax ) )
01160 {//have to do this test because placed turrets are not solid to NPCs (so they don't obstruct navigation)
01161 //if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 )
01162 if (0)
01163 {
01164 NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME;
01165 G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->r.currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN );
01166 }
01167 else
01168 {
01169 G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->r.currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_CRUSH );
01170 }
01171 }
01172 }
01173 else if ( NPCInfo->touchedByPlayer != NULL && NPCInfo->touchedByPlayer == NPC->enemy )
01174 {//touched enemy
01175 //if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 )
01176 if (0)
01177 {//zap him!
01178 vec3_t smackDir;
01179
01180 //animate me
01181 #if 0
01182 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK6, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01183 #endif
01184 TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoTimer );
01185 TIMER_Set( NPC, "standTime", NPC->client->ps.legsTimer );
01186 //FIXME: debounce this?
01187 NPCInfo->touchedByPlayer = NULL;
01188 //FIXME: some shield effect?
01189 NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME;
01190
01191 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, smackDir );
01192 smackDir[2] += 30;
01193 VectorNormalize( smackDir );
01194 G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->r.currentOrigin, (g_spskill.integer+1)*Q_irand( 5, 10), DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN );
01195 //throw them
01196 G_Throw( NPC->enemy, smackDir, 100 );
01197 //NPC->enemy->s.powerups |= ( 1 << PW_SHOCKED );
01198 if ( NPC->enemy->client )
01199 {
01200 // NPC->enemy->client->ps.powerups[PW_SHOCKED] = level.time + 1000;
01201 NPC->enemy->client->ps.electrifyTime = level.time + 1000;
01202 }
01203 //stop any attacks
01204 ucmd.buttons = 0;
01205 }
01206 }
01207
01208 if ( NPCInfo->movementSpeech < 3 && NPCInfo->blockedSpeechDebounceTime <= level.time )
01209 {
01210 if ( NPC->enemy && NPC->enemy->health > 0 && NPC->enemy->painDebounceTime > level.time )
01211 {
01212 if ( NPC->enemy->health < 50 && NPCInfo->movementSpeech == 2 )
01213 {
01214 G_AddVoiceEvent( NPC, EV_ANGER2, Q_irand( 2000, 4000 ) );
01215 NPCInfo->movementSpeech = 3;
01216 }
01217 else if ( NPC->enemy->health < 75 && NPCInfo->movementSpeech == 1 )
01218 {
01219 G_AddVoiceEvent( NPC, EV_ANGER1, Q_irand( 2000, 4000 ) );
01220 NPCInfo->movementSpeech = 2;
01221 }
01222 else if ( NPC->enemy->health < 100 && NPCInfo->movementSpeech == 0 )
01223 {
01224 G_AddVoiceEvent( NPC, EV_ANGER3, Q_irand( 2000, 4000 ) );
01225 NPCInfo->movementSpeech = 1;
01226 }
01227 }
01228 }
01229 }
|
|
|
Definition at line 1231 of file NPC_AI_GalakMech.c. References gentity_s::client, gentity_s::clipmask, playerState_s::crouchheight, entityShared_t::currentOrigin, gentity_s::enemy, FL_SHIELDED, gentity_s::flags, GALAK_SHIELD_HEALTH, GENERATOR_HEALTH, HL_GENERIC1, gNPC_t::investigateCount, gNPC_t::investigateDebounceTime, level, gentity_s::locationDamage, entityShared_t::maxs, entityShared_t::mins, NPC, NPC_BSGM_Attack(), NPC_BSGM_Patrol(), NPC_SetSurfaceOnOff(), NPCInfo, entityState_s::number, gclient_s::ps, qtrue, gentity_s::r, gentity_s::s, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, playerState_s::standheight, trace_t::startsolid, STAT_ARMOR, playerState_s::stats, level_locals_t::time, trap_Trace(), TURN_OFF, TURN_ON, VectorCopy, VectorSet, and WeaponThink(). Referenced by NPC_RunBehavior().
01232 {
01233 if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
01234 {
01235 WeaponThink( qtrue );
01236 }
01237
01238 if ( NPC->client->ps.stats[STAT_ARMOR] <= 0 )
01239 {//armor gone
01240 // if ( !NPCInfo->investigateDebounceTime )
01241 if (0)
01242 {//start regenerating the armor
01243 NPC_SetSurfaceOnOff( NPC, "torso_shield", TURN_OFF );
01244 NPC->flags &= ~FL_SHIELDED;//no more reflections
01245 VectorSet( NPC->r.mins, -20, -20, -24 );
01246 VectorSet( NPC->r.maxs, 20, 20, 64 );
01247 NPC->client->ps.crouchheight = NPC->client->ps.standheight = 64;
01248 if ( NPC->locationDamage[HL_GENERIC1] < GENERATOR_HEALTH )
01249 {//still have the generator bolt-on
01250 if ( NPCInfo->investigateCount < 12 )
01251 {
01252 NPCInfo->investigateCount++;
01253 }
01254 NPCInfo->investigateDebounceTime = level.time + (NPCInfo->investigateCount * 5000);
01255 }
01256 }
01257 else if ( NPCInfo->investigateDebounceTime < level.time )
01258 {//armor regenerated, turn shield back on
01259 //do a trace and make sure we can turn this back on?
01260 trace_t tr;
01261 trap_Trace( &tr, NPC->r.currentOrigin, shieldMins, shieldMaxs, NPC->r.currentOrigin, NPC->s.number, NPC->clipmask );
01262 if ( !tr.startsolid )
01263 {
01264 VectorCopy( shieldMins, NPC->r.mins );
01265 VectorCopy( shieldMaxs, NPC->r.maxs );
01266 NPC->client->ps.crouchheight = NPC->client->ps.standheight = shieldMaxs[2];
01267 NPC->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH;
01268 NPCInfo->investigateDebounceTime = 0;
01269 NPC->flags |= FL_SHIELDED;//reflect normal shots
01270 // NPC->fx_time = level.time;
01271 NPC_SetSurfaceOnOff( NPC, "torso_shield", TURN_ON );
01272 }
01273 }
01274 }
01275 /*
01276 if ( NPC->client->ps.stats[STAT_ARMOR] > 0 )
01277 {//armor present
01278 NPC->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect
01279 NPC_SetSurfaceOnOff( NPC, "torso_shield", TURN_ON );
01280 }
01281 else
01282 {
01283 NPC_SetSurfaceOnOff( NPC, "torso_shield", TURN_OFF );
01284 }
01285 */
01286 //rwwFIXMEFIXME: Allow this stuff, and again, going to have to let the client know about it.
01287 //Maybe a surface-off bitflag of some sort in the entity state?
01288
01289 if( !NPC->enemy )
01290 {//don't have an enemy, look for one
01291 NPC_BSGM_Patrol();
01292 }
01293 else //if ( NPC->enemy )
01294 {//have an enemy
01295 NPC_BSGM_Attack();
01296 }
01297 }
|
|
|
Definition at line 416 of file NPC_AI_GalakMech.c. References BUTTON_WALKING, usercmd_s::buttons, NPC_CheckPlayerTeamStealth(), NPC_MoveToGoal(), NPC_UpdateAngles(), qtrue, ucmd, and UpdateGoal(). Referenced by NPC_BSGM_Attack(), and NPC_BSGM_Default().
00417 {
00418 if ( NPC_CheckPlayerTeamStealth() )
00419 {
00420 NPC_UpdateAngles( qtrue, qtrue );
00421 return;
00422 }
00423
00424 //If we have somewhere to go, then do that
00425 if ( UpdateGoal() )
00426 {
00427 ucmd.buttons |= BUTTON_WALKING;
00428 NPC_MoveToGoal( qtrue );
00429 }
00430
00431 NPC_UpdateAngles( qtrue, qtrue );
00432 }
|
|
|
|
|
|
Definition at line 59 of file NPC_AI_GalakMech.c. References gNPC_t::behaviorState, BS_CINEMATIC, gentity_s::client, FL_NO_KNOCKBACK, FL_SHIELDED, gentity_s::flags, GALAK_SHIELD_HEALTH, gentity_t, gNPC_t::investigateCount, gNPC_t::investigateDebounceTime, entityShared_t::maxs, entityShared_t::mins, gentity_s::NPC, NPC_SetSurfaceOnOff(), gclient_s::ps, gentity_s::r, STAT_ARMOR, playerState_s::stats, TIMER_Set(), TURN_OFF, TURN_ON, and VectorSet. Referenced by NPC_SetMiscDefaultData().
00060 {
00061 if (ent->NPC->behaviorState != BS_CINEMATIC)
00062 {
00063 ent->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH;
00064 ent->NPC->investigateCount = ent->NPC->investigateDebounceTime = 0;
00065 ent->flags |= FL_SHIELDED;//reflect normal shots
00066 //rwwFIXMEFIXME: Support PW_GALAK_SHIELD
00067 //ent->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect
00068 //ent->fx_time = level.time;
00069 VectorSet( ent->r.mins, -60, -60, -24 );
00070 VectorSet( ent->r.maxs, 60, 60, 80 );
00071 ent->flags |= FL_NO_KNOCKBACK;//don't get pushed
00072 TIMER_Set( ent, "attackDelay", 0 ); //FIXME: Slant for difficulty levels
00073 TIMER_Set( ent, "flee", 0 );
00074 TIMER_Set( ent, "smackTime", 0 );
00075 TIMER_Set( ent, "beamDelay", 0 );
00076 TIMER_Set( ent, "noLob", 0 );
00077 TIMER_Set( ent, "noRapid", 0 );
00078 TIMER_Set( ent, "talkDebounce", 0 );
00079
00080 NPC_SetSurfaceOnOff( ent, "torso_shield", TURN_ON );
00081 NPC_SetSurfaceOnOff( ent, "torso_galakface", TURN_OFF );
00082 NPC_SetSurfaceOnOff( ent, "torso_galakhead", TURN_OFF );
00083 NPC_SetSurfaceOnOff( ent, "torso_eyes_mouth", TURN_OFF );
00084 NPC_SetSurfaceOnOff( ent, "torso_collar", TURN_OFF );
00085 NPC_SetSurfaceOnOff( ent, "torso_galaktorso", TURN_OFF );
00086 }
00087 else
00088 {
00089 // NPC_SetSurfaceOnOff( ent, "helmet", TURN_OFF );
00090 NPC_SetSurfaceOnOff( ent, "torso_shield", TURN_OFF );
00091 NPC_SetSurfaceOnOff( ent, "torso_galakface", TURN_ON );
00092 NPC_SetSurfaceOnOff( ent, "torso_galakhead", TURN_ON );
00093 NPC_SetSurfaceOnOff( ent, "torso_eyes_mouth", TURN_ON );
00094 NPC_SetSurfaceOnOff( ent, "torso_collar", TURN_ON );
00095 NPC_SetSurfaceOnOff( ent, "torso_galaktorso", TURN_ON );
00096 }
00097
00098 }
|
|
|
Definition at line 42 of file NPC_AI_GalakMech.c. References G_EffectIndex(), and G_SoundIndex(). Referenced by NPC_SpawnType(), and SP_NPC_Galak().
00043 {
00044 G_SoundIndex( "sound/weapons/galak/skewerhit.wav" );
00045 G_SoundIndex( "sound/weapons/galak/lasercharge.wav" );
00046 G_SoundIndex( "sound/weapons/galak/lasercutting.wav" );
00047 G_SoundIndex( "sound/weapons/galak/laserdamage.wav" );
00048
00049 G_EffectIndex( "galak/trace_beam" );
00050 G_EffectIndex( "galak/beam_warmup" );
00051 // G_EffectIndex( "small_chunks");
00052 G_EffectIndex( "env/med_explode2");
00053 G_EffectIndex( "env/small_explode2");
00054 G_EffectIndex( "galak/explode");
00055 G_EffectIndex( "blaster/smoke_bolton");
00056 // G_EffectIndex( "env/exp_trail_comp");
00057 }
|
|
||||||||||||||||
|
Definition at line 238 of file NPC_AI_GalakMech.c. References gentity_s::alt_fire, gNPC_t::blockedSpeechDebounceTime, gentity_s::client, gentity_s::count, gentity_s::delay, playerState_s::electrifyTime, EV_DETECTED1, EV_PUSHED1, EV_PUSHED2, EV_PUSHED3, G_AddVoiceEvent(), gentity_t, gPainMOD, gPainPoint, gentity_s::health, HL_GENERIC1, gentity_s::lastEnemy, level, gentity_s::lockCount, MOD_REPEATER, MOD_REPEATER_ALT, gentity_s::NPC, NPC_Pain(), NPC_SetPainEvent(), gclient_s::ps, Q_irand(), qfalse, qtrue, SCF_ALT_FIRE, gNPC_t::scriptFlags, level_locals_t::time, TIMER_Done(), TIMER_Set(), playerState_s::torsoTimer, vec3_t, and VectorCopy. Referenced by NPC_PainFunc().
00239 {
00240 vec3_t point;
00241 gentity_t *inflictor = attacker;
00242 int hitLoc = 1;
00243 int mod = gPainMOD;
00244
00245 VectorCopy(gPainPoint, point);
00246
00247 //if ( self->client->ps.powerups[PW_GALAK_SHIELD] == 0 )
00248 if (0) //rwwFIXMEFIXME: do all of this
00249 {//shield is currently down
00250 //FIXME: allow for radius damage?
00251 /*
00252 if ( (hitLoc==HL_GENERIC1) && (self->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH) )
00253 {
00254 int newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*antenna_base" );
00255 if ( newBolt != -1 )
00256 {
00257 GM_CreateExplosion( self, newBolt, qfalse );
00258 }
00259
00260 NPC_SetSurfaceOnOff( self, "torso_shield", TURN_OFF );
00261 NPC_SetSurfaceOnOff( self, "torso_antenna", TURN_OFF );
00262 NPC_SetSurfaceOnOff( self, "torso_antenna_base_cap", TURN_ON );
00263 self->client->ps.powerups[PW_GALAK_SHIELD] = 0;//temp, for effect
00264 self->client->ps.stats[STAT_ARMOR] = 0;//no more armor
00265 self->NPC->investigateDebounceTime = 0;//stop recharging
00266
00267 NPC_SetAnim( self, SETANIM_BOTH, BOTH_ALERT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00268 TIMER_Set( self, "attackDelay", self->client->ps.torsoTimer );
00269 G_AddEvent( self, Q_irand( EV_DEATH1, EV_DEATH3 ), self->health );
00270 }
00271 */
00272 }
00273 else
00274 {//store the point for shield impact
00275 if ( point )
00276 {
00277 // VectorCopy( point, self->pos4 );
00278 // self->client->poisonTime = level.time;
00279 //rwwFIXMEFIXME: ..do this is as well.
00280 }
00281 }
00282
00283 if ( !self->lockCount && self->client->ps.torsoTimer <= 0 )
00284 {//don't interrupt laser sweep attack or other special attacks/moves
00285 if ( self->count < 4 && self->health > 100 && hitLoc != HL_GENERIC1 )
00286 {
00287 if ( self->delay < level.time )
00288 {
00289 int speech;
00290 switch( self->count )
00291 {
00292 default:
00293 case 0:
00294 speech = EV_PUSHED1;
00295 break;
00296 case 1:
00297 speech = EV_PUSHED2;
00298 break;
00299 case 2:
00300 speech = EV_PUSHED3;
00301 break;
00302 case 3:
00303 speech = EV_DETECTED1;
00304 break;
00305 }
00306 self->count++;
00307 self->NPC->blockedSpeechDebounceTime = 0;
00308 G_AddVoiceEvent( self, speech, Q_irand( 3000, 5000 ) );
00309 self->delay = level.time + Q_irand( 5000, 7000 );
00310 }
00311 }
00312 else
00313 {
00314 NPC_Pain(self, attacker, damage);
00315 }
00316 }
00317 else if ( hitLoc == HL_GENERIC1 )
00318 {
00319 NPC_SetPainEvent( self );
00320 //self->s.powerups |= ( 1 << PW_SHOCKED );
00321 //self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 );
00322 self->client->ps.electrifyTime = level.time + Q_irand(500, 2500);
00323 }
00324
00325 if ( inflictor && inflictor->lastEnemy == self )
00326 {//He force-pushed my own lobfires back at me
00327 if ( mod == MOD_REPEATER_ALT && !Q_irand( 0, 2 ) )
00328 {
00329 if ( TIMER_Done( self, "noRapid" ) )
00330 {
00331 self->NPC->scriptFlags &= ~SCF_ALT_FIRE;
00332 self->alt_fire = qfalse;
00333 TIMER_Set( self, "noLob", Q_irand( 2000, 6000 ) );
00334 }
00335 else
00336 {//hopefully this will make us fire the laser
00337 TIMER_Set( self, "noLob", Q_irand( 1000, 2000 ) );
00338 }
00339 }
00340 else if ( mod == MOD_REPEATER && !Q_irand( 0, 5 ) )
00341 {
00342 if ( TIMER_Done( self, "noLob" ) )
00343 {
00344 self->NPC->scriptFlags |= SCF_ALT_FIRE;
00345 self->alt_fire = qtrue;
00346 TIMER_Set( self, "noRapid", Q_irand( 2000, 6000 ) );
00347 }
00348 else
00349 {//hopefully this will make us fire the laser
00350 TIMER_Set( self, "noRapid", Q_irand( 1000, 2000 ) );
00351 }
00352 }
00353 }
00354 }
|
|
|
Definition at line 558 of file NPC_AI_GalakMech.c. References CHAN_AUTO, gentity_s::client, entityShared_t::currentOrigin, G_EffectIndex(), G_PlayEffectID(), G_SoundOnEnt(), gentity_s::lockCount, NPC, NPC_SetAnim(), gclient_s::ps, gentity_s::r, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, TIMER_Set(), playerState_s::torsoTimer, and vec3_origin. Referenced by NPC_BSGM_Attack().
00559 {
00560 if ( !NPC->lockCount )
00561 {//haven't already started a laser attack
00562 //warm up for the beam attack
00563 #if 0
00564 NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_RAISEWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00565 #endif
00566 TIMER_Set( NPC, "beamDelay", NPC->client->ps.torsoTimer );
00567 TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoTimer+3000 );
00568 NPC->lockCount = 1;
00569 //turn on warmup effect
00570 G_PlayEffectID( G_EffectIndex("galak/beam_warmup"), NPC->r.currentOrigin, vec3_origin );
00571 G_SoundOnEnt( NPC, CHAN_AUTO, "sound/weapons/galak/lasercharge.wav" );
00572 }
00573 }
|
|
|
Definition at line 133 of file NPC_reactions.c. References gNPC_t::aiFlags, gentity_s::client, EV_PAIN, floor(), G_AddEvent(), gentity_t, gentity_s::health, gentity_s::NPC, NPCAI_DIE_ON_IMPACT, gclient_s::ps, STAT_MAX_HEALTH, playerState_s::stats, TID_CHAN_VOICE, and trap_ICARUS_TaskIDPending(). Referenced by NPC_ChoosePainAnimation(), and NPC_GM_Pain().
00134 {
00135 if ( !self->NPC || !(self->NPC->aiFlags&NPCAI_DIE_ON_IMPACT) )
00136 {
00137 // no more borg
00138 // if( self->client->playerTeam != TEAM_BORG )
00139 // {
00140 //if ( !Q3_TaskIDPending( self, TID_CHAN_VOICE ) )
00141 if (!trap_ICARUS_TaskIDPending(self, TID_CHAN_VOICE) && self->client)
00142 {
00143 //G_AddEvent( self, EV_PAIN, floor((float)self->health/self->max_health*100.0f) );
00144 G_AddEvent( self, EV_PAIN, floor((float)self->health/self->client->ps.stats[STAT_MAX_HEALTH]*100.0f) );
00145 //rwwFIXMEFIXME: Do this properly?
00146 }
00147 // }
00148 }
00149 }
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Definition at line 2080 of file g_weapon.c. References trace_t::allsolid, BG_EvaluateTrajectory(), trace_t::endpos, trace_t::entityNum, ENTITYNUM_WORLD, floor(), trace_t::fraction, g_entities, g_gravity, gentity_t, level, cplane_s::normal, OnSameTeam(), trace_t::plane, Q3_INFINITE, qboolean, qfalse, qtrue, trace_t::startsolid, gentity_s::takedamage, level_locals_t::time, TR_GRAVITY, trap_Trace(), trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, vmCvar_t::value, vec3_t, VectorCopy, VectorNormalize(), VectorScale, and VectorSubtract. Referenced by NPC_BSGM_Attack().
02084 { //for the galak mech NPC
02085 float targetDist, shotSpeed, speedInc = 100, travelTime, impactDist, bestImpactDist = Q3_INFINITE;//fireSpeed,
02086 vec3_t targetDir, shotVel, failCase;
02087 trace_t trace;
02088 trajectory_t tr;
02089 qboolean blocked;
02090 int elapsedTime, skipNum, timeStep = 500, hitCount = 0, maxHits = 7;
02091 vec3_t lastPos, testPos;
02092 gentity_t *traceEnt;
02093
02094 if ( !idealSpeed )
02095 {
02096 idealSpeed = 300;
02097 }
02098 else if ( idealSpeed < speedInc )
02099 {
02100 idealSpeed = speedInc;
02101 }
02102 shotSpeed = idealSpeed;
02103 skipNum = (idealSpeed-speedInc)/speedInc;
02104 if ( !minSpeed )
02105 {
02106 minSpeed = 100;
02107 }
02108 if ( !maxSpeed )
02109 {
02110 maxSpeed = 900;
02111 }
02112 while ( hitCount < maxHits )
02113 {
02114 VectorSubtract( target, start, targetDir );
02115 targetDist = VectorNormalize( targetDir );
02116
02117 VectorScale( targetDir, shotSpeed, shotVel );
02118 travelTime = targetDist/shotSpeed;
02119 shotVel[2] += travelTime * 0.5 * g_gravity.value;
02120
02121 if ( !hitCount )
02122 {//save the first (ideal) one as the failCase (fallback value)
02123 if ( !mustHit )
02124 {//default is fine as a return value
02125 VectorCopy( shotVel, failCase );
02126 }
02127 }
02128
02129 if ( tracePath )
02130 {//do a rough trace of the path
02131 blocked = qfalse;
02132
02133 VectorCopy( start, tr.trBase );
02134 VectorCopy( shotVel, tr.trDelta );
02135 tr.trType = TR_GRAVITY;
02136 tr.trTime = level.time;
02137 travelTime *= 1000.0f;
02138 VectorCopy( start, lastPos );
02139
02140 //This may be kind of wasteful, especially on long throws... use larger steps? Divide the travelTime into a certain hard number of slices? Trace just to apex and down?
02141 for ( elapsedTime = timeStep; elapsedTime < floor(travelTime)+timeStep; elapsedTime += timeStep )
02142 {
02143 if ( (float)elapsedTime > travelTime )
02144 {//cap it
02145 elapsedTime = floor( travelTime );
02146 }
02147 BG_EvaluateTrajectory( &tr, level.time + elapsedTime, testPos );
02148 trap_Trace( &trace, lastPos, mins, maxs, testPos, ignoreEntNum, clipmask );
02149
02150 if ( trace.allsolid || trace.startsolid )
02151 {
02152 blocked = qtrue;
02153 break;
02154 }
02155 if ( trace.fraction < 1.0f )
02156 {//hit something
02157 if ( trace.entityNum == enemyNum )
02158 {//hit the enemy, that's perfect!
02159 break;
02160 }
02161 else if ( trace.plane.normal[2] > 0.7 && DistanceSquared( trace.endpos, target ) < 4096 )//hit within 64 of desired location, should be okay
02162 {//close enough!
02163 break;
02164 }
02165 else
02166 {//FIXME: maybe find the extents of this brush and go above or below it on next try somehow?
02167 impactDist = DistanceSquared( trace.endpos, target );
02168 if ( impactDist < bestImpactDist )
02169 {
02170 bestImpactDist = impactDist;
02171 VectorCopy( shotVel, failCase );
02172 }
02173 blocked = qtrue;
02174 //see if we should store this as the failCase
02175 if ( trace.entityNum < ENTITYNUM_WORLD )
02176 {//hit an ent
02177 traceEnt = &g_entities[trace.entityNum];
02178 if ( traceEnt && traceEnt->takedamage && !OnSameTeam( self, traceEnt ) )
02179 {//hit something breakable, so that's okay
02180 //we haven't found a clear shot yet so use this as the failcase
02181 VectorCopy( shotVel, failCase );
02182 }
02183 }
02184 break;
02185 }
02186 }
02187 if ( elapsedTime == floor( travelTime ) )
02188 {//reached end, all clear
02189 break;
02190 }
02191 else
02192 {
02193 //all clear, try next slice
02194 VectorCopy( testPos, lastPos );
02195 }
02196 }
02197 if ( blocked )
02198 {//hit something, adjust speed (which will change arc)
02199 hitCount++;
02200 shotSpeed = idealSpeed + ((hitCount-skipNum) * speedInc);//from min to max (skipping ideal)
02201 if ( hitCount >= skipNum )
02202 {//skip ideal since that was the first value we tested
02203 shotSpeed += speedInc;
02204 }
02205 }
02206 else
02207 {//made it!
02208 break;
02209 }
02210 }
02211 else
02212 {//no need to check the path, go with first calc
02213 break;
02214 }
02215 }
02216
02217 if ( hitCount >= maxHits )
02218 {//NOTE: worst case scenario, use the one that impacted closest to the target (or just use the first try...?)
02219 VectorCopy( failCase, velocity );
02220 return qfalse;
02221 }
02222 VectorCopy( shotVel, velocity );
02223 return qtrue;
02224 }
|