codemp/game/g_ICARUScb.c

Go to the documentation of this file.
00001 //====================================================================================
00002 //
00003 //rww - ICARUS callback file, all that can be handled within vm's is handled in here.
00004 //
00005 //====================================================================================
00006 
00007 #include "q_shared.h"
00008 #include "bg_public.h"
00009 #include "b_local.h"
00010 #include "../icarus/Q3_Interface.h"
00011 #include "../icarus/Q3_Registers.h"
00012 #include "g_nav.h"
00013 
00014 #include "../namespace_begin.h"
00015 qboolean BG_SabersOff( playerState_t *ps );
00016 extern stringID_table_t WPTable[];
00017 extern stringID_table_t BSTable[];
00018 #include "../namespace_end.h"
00019 
00020 
00021 //This is a hack I guess. It's because we can't include the file this enum is in
00022 //unless we're using cpp. But we need it for the interpreter stuff.
00023 //In any case, DO NOT modify this enum.
00024 
00025 // Hack++
00026 // This code is compiled as C++ on Xbox. We could try and rig something above
00027 // so that we only get the C version of the includes (no full Icarus) in that
00028 // scenario, but I think we'll just try to leave this out instead.
00029 #ifndef _XBOX
00030 #ifndef __linux__
00031 enum
00032 {
00033         TK_EOF = -1,
00034         TK_UNDEFINED,
00035         TK_COMMENT,
00036         TK_EOL,
00037         TK_CHAR,
00038         TK_STRING,
00039         TK_INT,
00040         TK_INTEGER = TK_INT,
00041         TK_FLOAT,
00042         TK_IDENTIFIER,
00043         TK_USERDEF,
00044 };
00045 #endif
00046 #endif
00047 
00048 #include "../icarus/interpreter.h"
00049 
00050 extern stringID_table_t animTable [MAX_ANIMATIONS+1];
00051 
00052 stringID_table_t setTable[] =
00053 {
00054         ENUM2STRING(SET_SPAWNSCRIPT),//0
00055         ENUM2STRING(SET_USESCRIPT),
00056         ENUM2STRING(SET_AWAKESCRIPT),
00057         ENUM2STRING(SET_ANGERSCRIPT),
00058         ENUM2STRING(SET_ATTACKSCRIPT),
00059         ENUM2STRING(SET_VICTORYSCRIPT),
00060         ENUM2STRING(SET_PAINSCRIPT),
00061         ENUM2STRING(SET_FLEESCRIPT),
00062         ENUM2STRING(SET_DEATHSCRIPT),
00063         ENUM2STRING(SET_DELAYEDSCRIPT),
00064         ENUM2STRING(SET_BLOCKEDSCRIPT),
00065         ENUM2STRING(SET_FFIRESCRIPT),
00066         ENUM2STRING(SET_FFDEATHSCRIPT),
00067         ENUM2STRING(SET_MINDTRICKSCRIPT),
00068         ENUM2STRING(SET_NO_MINDTRICK),
00069         ENUM2STRING(SET_ORIGIN),
00070         ENUM2STRING(SET_TELEPORT_DEST),
00071         ENUM2STRING(SET_ANGLES),
00072         ENUM2STRING(SET_XVELOCITY),
00073         ENUM2STRING(SET_YVELOCITY),
00074         ENUM2STRING(SET_ZVELOCITY),
00075         ENUM2STRING(SET_Z_OFFSET),
00076         ENUM2STRING(SET_ENEMY),
00077         ENUM2STRING(SET_LEADER),
00078         ENUM2STRING(SET_NAVGOAL),
00079         ENUM2STRING(SET_ANIM_UPPER),
00080         ENUM2STRING(SET_ANIM_LOWER),
00081         ENUM2STRING(SET_ANIM_BOTH),
00082         ENUM2STRING(SET_ANIM_HOLDTIME_LOWER),
00083         ENUM2STRING(SET_ANIM_HOLDTIME_UPPER),
00084         ENUM2STRING(SET_ANIM_HOLDTIME_BOTH),
00085         ENUM2STRING(SET_PLAYER_TEAM),
00086         ENUM2STRING(SET_ENEMY_TEAM),
00087         ENUM2STRING(SET_BEHAVIOR_STATE),
00088         ENUM2STRING(SET_BEHAVIOR_STATE),
00089         ENUM2STRING(SET_HEALTH),
00090         ENUM2STRING(SET_ARMOR),
00091         ENUM2STRING(SET_DEFAULT_BSTATE),
00092         ENUM2STRING(SET_CAPTURE),
00093         ENUM2STRING(SET_DPITCH),
00094         ENUM2STRING(SET_DYAW),
00095         ENUM2STRING(SET_EVENT),
00096         ENUM2STRING(SET_TEMP_BSTATE),
00097         ENUM2STRING(SET_COPY_ORIGIN),
00098         ENUM2STRING(SET_VIEWTARGET),
00099         ENUM2STRING(SET_WEAPON),
00100         ENUM2STRING(SET_ITEM),
00101         ENUM2STRING(SET_WALKSPEED),
00102         ENUM2STRING(SET_RUNSPEED),
00103         ENUM2STRING(SET_YAWSPEED),
00104         ENUM2STRING(SET_AGGRESSION),
00105         ENUM2STRING(SET_AIM),
00106         ENUM2STRING(SET_FRICTION),
00107         ENUM2STRING(SET_GRAVITY),
00108         ENUM2STRING(SET_IGNOREPAIN),
00109         ENUM2STRING(SET_IGNOREENEMIES),
00110         ENUM2STRING(SET_IGNOREALERTS),
00111         ENUM2STRING(SET_DONTSHOOT),
00112         ENUM2STRING(SET_DONTFIRE),
00113         ENUM2STRING(SET_LOCKED_ENEMY),
00114         ENUM2STRING(SET_NOTARGET),
00115         ENUM2STRING(SET_LEAN),
00116         ENUM2STRING(SET_CROUCHED),
00117         ENUM2STRING(SET_WALKING),
00118         ENUM2STRING(SET_RUNNING),
00119         ENUM2STRING(SET_CHASE_ENEMIES),
00120         ENUM2STRING(SET_LOOK_FOR_ENEMIES),
00121         ENUM2STRING(SET_FACE_MOVE_DIR),
00122         ENUM2STRING(SET_ALT_FIRE),
00123         ENUM2STRING(SET_DONT_FLEE),
00124         ENUM2STRING(SET_FORCED_MARCH),
00125         ENUM2STRING(SET_NO_RESPONSE),
00126         ENUM2STRING(SET_NO_COMBAT_TALK),
00127         ENUM2STRING(SET_NO_ALERT_TALK),
00128         ENUM2STRING(SET_UNDYING),
00129         ENUM2STRING(SET_TREASONED),
00130         ENUM2STRING(SET_DISABLE_SHADER_ANIM),
00131         ENUM2STRING(SET_SHADER_ANIM),
00132         ENUM2STRING(SET_INVINCIBLE),
00133         ENUM2STRING(SET_NOAVOID),
00134         ENUM2STRING(SET_SHOOTDIST),
00135         ENUM2STRING(SET_TARGETNAME),
00136         ENUM2STRING(SET_TARGET),
00137         ENUM2STRING(SET_TARGET2),
00138         ENUM2STRING(SET_LOCATION),
00139         ENUM2STRING(SET_PAINTARGET),
00140         ENUM2STRING(SET_TIMESCALE),
00141         ENUM2STRING(SET_VISRANGE),
00142         ENUM2STRING(SET_EARSHOT),
00143         ENUM2STRING(SET_VIGILANCE),
00144         ENUM2STRING(SET_HFOV),
00145         ENUM2STRING(SET_VFOV),
00146         ENUM2STRING(SET_DELAYSCRIPTTIME),
00147         ENUM2STRING(SET_FORWARDMOVE),
00148         ENUM2STRING(SET_RIGHTMOVE),
00149         ENUM2STRING(SET_LOCKYAW),
00150         ENUM2STRING(SET_SOLID),
00151         ENUM2STRING(SET_CAMERA_GROUP),
00152         ENUM2STRING(SET_CAMERA_GROUP_Z_OFS),
00153         ENUM2STRING(SET_CAMERA_GROUP_TAG),
00154         ENUM2STRING(SET_LOOK_TARGET),
00155         ENUM2STRING(SET_ADDRHANDBOLT_MODEL),
00156         ENUM2STRING(SET_REMOVERHANDBOLT_MODEL),
00157         ENUM2STRING(SET_ADDLHANDBOLT_MODEL),
00158         ENUM2STRING(SET_REMOVELHANDBOLT_MODEL),
00159         ENUM2STRING(SET_FACEAUX),
00160         ENUM2STRING(SET_FACEBLINK),
00161         ENUM2STRING(SET_FACEBLINKFROWN),
00162         ENUM2STRING(SET_FACEFROWN),
00163         ENUM2STRING(SET_FACENORMAL),
00164         ENUM2STRING(SET_FACEEYESCLOSED),
00165         ENUM2STRING(SET_FACEEYESOPENED),
00166         ENUM2STRING(SET_SCROLLTEXT),
00167         ENUM2STRING(SET_LCARSTEXT),
00168         ENUM2STRING(SET_SCROLLTEXTCOLOR),
00169         ENUM2STRING(SET_CAPTIONTEXTCOLOR),
00170         ENUM2STRING(SET_CENTERTEXTCOLOR),
00171         ENUM2STRING(SET_PLAYER_USABLE),
00172         ENUM2STRING(SET_STARTFRAME),
00173         ENUM2STRING(SET_ENDFRAME),
00174         ENUM2STRING(SET_ANIMFRAME),
00175         ENUM2STRING(SET_LOOP_ANIM),
00176         ENUM2STRING(SET_INTERFACE),
00177         ENUM2STRING(SET_SHIELDS),
00178         ENUM2STRING(SET_NO_KNOCKBACK),
00179         ENUM2STRING(SET_INVISIBLE),
00180         ENUM2STRING(SET_VAMPIRE),
00181         ENUM2STRING(SET_FORCE_INVINCIBLE),
00182         ENUM2STRING(SET_GREET_ALLIES),
00183         ENUM2STRING(SET_PLAYER_LOCKED),
00184         ENUM2STRING(SET_LOCK_PLAYER_WEAPONS),
00185         ENUM2STRING(SET_NO_IMPACT_DAMAGE),
00186         ENUM2STRING(SET_PARM1),
00187         ENUM2STRING(SET_PARM2),
00188         ENUM2STRING(SET_PARM3),
00189         ENUM2STRING(SET_PARM4),
00190         ENUM2STRING(SET_PARM5),
00191         ENUM2STRING(SET_PARM6),
00192         ENUM2STRING(SET_PARM7),
00193         ENUM2STRING(SET_PARM8),
00194         ENUM2STRING(SET_PARM9),
00195         ENUM2STRING(SET_PARM10),
00196         ENUM2STRING(SET_PARM11),
00197         ENUM2STRING(SET_PARM12),
00198         ENUM2STRING(SET_PARM13),
00199         ENUM2STRING(SET_PARM14),
00200         ENUM2STRING(SET_PARM15),
00201         ENUM2STRING(SET_PARM16),
00202         ENUM2STRING(SET_DEFEND_TARGET),
00203         ENUM2STRING(SET_WAIT),
00204         ENUM2STRING(SET_COUNT),
00205         ENUM2STRING(SET_SHOT_SPACING),
00206         ENUM2STRING(SET_VIDEO_PLAY),
00207         ENUM2STRING(SET_VIDEO_FADE_IN),
00208         ENUM2STRING(SET_VIDEO_FADE_OUT),
00209         ENUM2STRING(SET_REMOVE_TARGET),
00210         ENUM2STRING(SET_LOADGAME),
00211         ENUM2STRING(SET_MENU_SCREEN),
00212         ENUM2STRING(SET_OBJECTIVE_SHOW),
00213         ENUM2STRING(SET_OBJECTIVE_HIDE),
00214         ENUM2STRING(SET_OBJECTIVE_SUCCEEDED),
00215         ENUM2STRING(SET_OBJECTIVE_FAILED),
00216         ENUM2STRING(SET_MISSIONFAILED),
00217         ENUM2STRING(SET_TACTICAL_SHOW),
00218         ENUM2STRING(SET_TACTICAL_HIDE),
00219         ENUM2STRING(SET_FOLLOWDIST),
00220         ENUM2STRING(SET_SCALE),
00221         ENUM2STRING(SET_OBJECTIVE_CLEARALL),
00222         ENUM2STRING(SET_MISSIONSTATUSTEXT),
00223         ENUM2STRING(SET_WIDTH),
00224         ENUM2STRING(SET_CLOSINGCREDITS),
00225         ENUM2STRING(SET_SKILL),
00226         ENUM2STRING(SET_MISSIONSTATUSTIME),
00227         ENUM2STRING(SET_FULLNAME),
00228         ENUM2STRING(SET_FORCE_HEAL_LEVEL),
00229         ENUM2STRING(SET_FORCE_JUMP_LEVEL),
00230         ENUM2STRING(SET_FORCE_SPEED_LEVEL),
00231         ENUM2STRING(SET_FORCE_PUSH_LEVEL),
00232         ENUM2STRING(SET_FORCE_PULL_LEVEL),
00233         ENUM2STRING(SET_FORCE_MINDTRICK_LEVEL),
00234         ENUM2STRING(SET_FORCE_GRIP_LEVEL),
00235         ENUM2STRING(SET_FORCE_LIGHTNING_LEVEL),
00236         ENUM2STRING(SET_SABER_THROW),
00237         ENUM2STRING(SET_SABER_DEFENSE),
00238         ENUM2STRING(SET_SABER_OFFENSE),
00239         ENUM2STRING(SET_VIEWENTITY),
00240         ENUM2STRING(SET_WATCHTARGET),
00241         ENUM2STRING(SET_SABERACTIVE),
00242         ENUM2STRING(SET_ADJUST_AREA_PORTALS),
00243         ENUM2STRING(SET_DMG_BY_HEAVY_WEAP_ONLY),
00244         ENUM2STRING(SET_SHIELDED),
00245         ENUM2STRING(SET_NO_GROUPS),
00246         ENUM2STRING(SET_FIRE_WEAPON),
00247         ENUM2STRING(SET_INACTIVE),
00248         ENUM2STRING(SET_FUNC_USABLE_VISIBLE),
00249         ENUM2STRING(SET_MISSION_STATUS_SCREEN),
00250         ENUM2STRING(SET_END_SCREENDISSOLVE),
00251         ENUM2STRING(SET_LOOPSOUND),
00252         ENUM2STRING(SET_ICARUS_FREEZE),
00253         ENUM2STRING(SET_ICARUS_UNFREEZE),
00254         ENUM2STRING(SET_USE_CP_NEAREST),
00255         ENUM2STRING(SET_MORELIGHT),
00256         ENUM2STRING(SET_CINEMATIC_SKIPSCRIPT),
00257         ENUM2STRING(SET_NO_FORCE),
00258         ENUM2STRING(SET_NO_FALLTODEATH),
00259         ENUM2STRING(SET_DISMEMBERABLE),
00260         ENUM2STRING(SET_NO_ACROBATICS),
00261         ENUM2STRING(SET_MUSIC_STATE),
00262         ENUM2STRING(SET_USE_SUBTITLES),
00263         ENUM2STRING(SET_CLEAN_DAMAGING_ENTS),
00264         ENUM2STRING(SET_HUD),
00265 
00266 //FIXME: add BOTH_ attributes here too
00267         "",     SET_,
00268 };
00269 
00270 void Q3_TaskIDClear( int *taskID )
00271 {
00272         *taskID = -1;
00273 }
00274 
00275 void G_DebugPrint( int level, const char *format, ... )
00276 {
00277         va_list         argptr;
00278         char            text[1024];
00279 
00280         //Don't print messages they don't want to see
00281         //if ( g_ICARUSDebug->integer < level )
00282         if (g_developer.integer != 2)
00283                 return;
00284 
00285         va_start (argptr, format);
00286         vsprintf (text, format, argptr);
00287         va_end (argptr);
00288 
00289         //Add the color formatting
00290         switch ( level )
00291         {
00292                 case WL_ERROR:
00293                         Com_Printf ( S_COLOR_RED"ERROR: %s", text );
00294                         break;
00295                 
00296                 case WL_WARNING:
00297                         Com_Printf ( S_COLOR_YELLOW"WARNING: %s", text );
00298                         break;
00299                 
00300                 case WL_DEBUG:
00301                         {
00302                                 int             entNum;
00303                                 char    *buffer;
00304 
00305                                 sscanf( text, "%d", &entNum );
00306 
00307                                 //if ( ( ICARUS_entFilter >= 0 ) && ( ICARUS_entFilter != entNum ) )
00308                                 //      return;
00309 
00310                                 buffer = (char *) text;
00311                                 buffer += 5;
00312 
00313                                 if ( ( entNum < 0 ) || ( entNum > MAX_GENTITIES ) )
00314                                         entNum = 0;
00315 
00316                                 Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", g_entities[entNum].script_targetname, entNum, buffer );
00317                                 break;
00318                         }
00319                 default:
00320                 case WL_VERBOSE:
00321                         Com_Printf ( S_COLOR_GREEN"INFO: %s", text );
00322                         break;
00323         }
00324 }
00325 
00326 /*
00327 -------------------------
00328 Q3_GetAnimLower
00329 -------------------------
00330 */
00331 static char *Q3_GetAnimLower( gentity_t *ent )
00332 {
00333         int anim = 0;
00334 
00335         if ( ent->client == NULL )
00336         {
00337                 G_DebugPrint( WL_WARNING, "Q3_GetAnimLower: attempted to read animation state off non-client!\n" );
00338                 return NULL;
00339         }
00340 
00341         anim = ent->client->ps.legsAnim;
00342 
00343         return (char *)animTable[anim].name;
00344 }
00345 
00346 /*
00347 -------------------------
00348 Q3_GetAnimUpper
00349 -------------------------
00350 */
00351 static char *Q3_GetAnimUpper( gentity_t *ent )
00352 {
00353         int anim = 0;
00354 
00355         if ( ent->client == NULL )
00356         {
00357                 G_DebugPrint( WL_WARNING, "Q3_GetAnimUpper: attempted to read animation state off non-client!\n" );
00358                 return NULL;
00359         }
00360 
00361         anim = ent->client->ps.torsoAnim;
00362 
00363         return (char *)animTable[anim].name;
00364 }
00365 
00366 /*
00367 -------------------------
00368 Q3_GetAnimBoth
00369 -------------------------
00370 */
00371 static char *Q3_GetAnimBoth( gentity_t *ent )
00372 {
00373         char    *lowerName, *upperName;
00374 
00375         lowerName = Q3_GetAnimLower( ent );
00376         upperName = Q3_GetAnimUpper( ent );
00377 
00378         if ( !lowerName || !lowerName[0] )
00379         {
00380                 G_DebugPrint( WL_WARNING, "Q3_GetAnimBoth: NULL legs animation string found!\n" );
00381                 return NULL;
00382         }
00383 
00384         if ( !upperName || !upperName[0] )
00385         {
00386                 G_DebugPrint( WL_WARNING, "Q3_GetAnimBoth: NULL torso animation string found!\n" );
00387                 return NULL;
00388         }
00389 
00390         if ( Q_stricmp( lowerName, upperName ) )
00391         {
00392 #ifdef _DEBUG   // sigh, cut down on tester reports that aren't important
00393                 G_DebugPrint( WL_WARNING, "Q3_GetAnimBoth: legs and torso animations did not match : returning legs\n" );
00394 #endif
00395         }
00396 
00397         return lowerName;
00398 }
00399 
00400 int Q3_PlaySound( int taskID, int entID, const char *name, const char *channel )
00401 {
00402         gentity_t               *ent = &g_entities[entID];
00403         char                    finalName[MAX_QPATH];
00404         soundChannel_t  voice_chan = CHAN_VOICE; // set a default so the compiler doesn't bitch
00405         qboolean                type_voice = qfalse;
00406         int                             soundHandle;
00407         qboolean                bBroadcast;
00408 
00409         Q_strncpyz( finalName, name, MAX_QPATH );
00410         Q_strupr(finalName);
00411         //G_AddSexToMunroString( finalName, qtrue );
00412 
00413         COM_StripExtension( (const char *)finalName, finalName );
00414 
00415         soundHandle = G_SoundIndex( (char *) finalName );
00416         bBroadcast = qfalse;
00417 
00418         if ( ( Q_stricmp( channel, "CHAN_ANNOUNCER" ) == 0 ) || (ent->classname && Q_stricmp("target_scriptrunner", ent->classname ) == 0) ) {
00419                 bBroadcast = qtrue;
00420         }
00421 
00422 
00423         // moved here from further down so I can easily check channel-type without code dup...
00424         //
00425         if ( Q_stricmp( channel, "CHAN_VOICE" ) == 0 )
00426         {
00427                 voice_chan = CHAN_VOICE;
00428                 type_voice = qtrue;
00429         }
00430         else if ( Q_stricmp( channel, "CHAN_VOICE_ATTEN" ) == 0 )
00431         {
00432                 voice_chan = CHAN_AUTO;//CHAN_VOICE_ATTEN;
00433                 type_voice = qtrue;
00434         }
00435         else if ( Q_stricmp( channel, "CHAN_VOICE_GLOBAL" ) == 0 ) // this should broadcast to everyone, put only casue animation on G_SoundOnEnt...
00436         {
00437                 voice_chan = CHAN_AUTO;//CHAN_VOICE_GLOBAL;
00438                 type_voice = qtrue;
00439                 bBroadcast = qtrue;
00440         }
00441 
00442         // if we're in-camera, check for skipping cinematic and ifso, no subtitle print (since screen is not being
00443         //      updated anyway during skipping). This stops leftover subtitles being left onscreen after unskipping.
00444         //
00445         /*
00446         if (!in_camera ||
00447                 (!g_skippingcin || !g_skippingcin->integer)
00448                 )       // paranoia towards project end <g>
00449         {
00450                 // Text on
00451                 // certain NPC's we always want to use subtitles regardless of subtitle setting
00452                 if (g_subtitles->integer == 1 || (ent->NPC && (ent->NPC->scriptFlags & SCF_USE_SUBTITLES) ) ) // Show all text
00453                 {
00454                         if ( in_camera) // Cinematic
00455                         {                                       
00456                                 trap_SendServerCommand( -1, va("ct \"%s\" %i", finalName, soundHandle) );
00457                         }
00458                         else //if (precacheWav[i].speaker==SP_NONE)     //  lower screen text
00459                         {
00460                                 sharedEntity_t          *ent2 = SV_GentityNum(0);
00461                                 // the numbers in here were either the original ones Bob entered (350), or one arrived at from checking the distance Chell stands at in stasis2 by the computer core that was submitted as a bug report...
00462                                 //
00463                                 if (bBroadcast || (DistanceSquared(ent->currentOrigin, ent2->currentOrigin) < ((voice_chan == CHAN_VOICE_ATTEN)?(350 * 350):(1200 * 1200)) ) )
00464                                 {
00465                                         trap_SendServerCommand( -1, va("ct \"%s\" %i", finalName, soundHandle) );
00466                                 }
00467                         }
00468                 }
00469                 // Cinematic only
00470                 else if (g_subtitles->integer == 2) // Show only talking head text and CINEMATIC
00471                 {
00472                         if ( in_camera) // Cinematic text
00473                         {                                                       
00474                                 trap_SendServerCommand( -1, va("ct \"%s\" %i", finalName, soundHandle));
00475                         }
00476                 }
00477 
00478         }
00479         */
00480 
00481         if ( type_voice )
00482         {
00483                 char buf[128];
00484                 float tFVal = 0;
00485 
00486                 trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf));
00487 
00488                 tFVal = atof(buf);
00489 
00490 
00491                 if ( tFVal > 1.0f )
00492                 {//Skip the damn sound!
00493                         return qtrue;
00494                 }
00495                 else
00496                 {
00497                         //This the voice channel
00498                         G_Sound( ent, voice_chan, G_SoundIndex((char *) finalName) );
00499                 }
00500                 //Remember we're waiting for this
00501                 trap_ICARUS_TaskIDSet( ent, TID_CHAN_VOICE, taskID );
00502 
00503                 return qfalse;
00504         }
00505 
00506         if ( bBroadcast )
00507         {//Broadcast the sound
00508                 gentity_t       *te;
00509 
00510                 te = G_TempEntity( ent->r.currentOrigin, EV_GLOBAL_SOUND );
00511                 te->s.eventParm = soundHandle;
00512                 te->r.svFlags |= SVF_BROADCAST;
00513         }
00514         else
00515         {
00516                 G_Sound( ent, CHAN_AUTO, soundHandle );
00517         }
00518 
00519         return qtrue;
00520 }
00521 
00522 /*
00523 -------------------------
00524 Q3_Play
00525 -------------------------
00526 */
00527 void Q3_Play( int taskID, int entID, const char *type, const char *name )
00528 {
00529         gentity_t *ent = &g_entities[entID];
00530 
00531         if ( !Q_stricmp( type, "PLAY_ROFF" ) )
00532         {
00533                 // Try to load the requested ROFF
00534                 ent->roffid = trap_ROFF_Cache((char*)name);
00535                 if ( ent->roffid )
00536                 {
00537                         ent->roffname = G_NewString( name );
00538 
00539                         // Start the roff from the beginning
00540                         //ent->roff_ctr = 0;
00541 
00542                         //Save this off for later
00543                         trap_ICARUS_TaskIDSet( ent, TID_MOVE_NAV, taskID );
00544 
00545                         // Let the ROFF playing start.
00546                         //ent->next_roff_time = level.time;
00547 
00548                         //rww - Maybe use pos1 and pos2? I don't think we need to care if these values are sent across the net.
00549                         // These need to be initialised up front...
00550                         //VectorCopy( ent->r.currentOrigin, ent->pos1 );
00551                         //VectorCopy( ent->r.currentAngles, ent->pos2 );
00552                         VectorCopy( ent->r.currentOrigin, ent->s.origin2 );
00553                         VectorCopy( ent->r.currentAngles, ent->s.angles2 );
00554                         
00555                         trap_LinkEntity( ent );
00556 
00557                         trap_ROFF_Play(ent->s.number, ent->roffid, qtrue);
00558                 }
00559         }
00560 }
00561 
00562 /*
00563 =============
00564 anglerCallback
00565 
00566 Utility function
00567 =============
00568 */
00569 void anglerCallback( gentity_t *ent )
00570 {
00571         //Complete the task
00572         trap_ICARUS_TaskIDComplete( ent, TID_ANGLE_FACE );
00573 
00574         //Set the currentAngles, clear all movement
00575         VectorMA( ent->s.apos.trBase, (ent->s.apos.trDuration*0.001f), ent->s.apos.trDelta, ent->r.currentAngles );
00576         VectorCopy( ent->r.currentAngles, ent->s.apos.trBase );
00577         VectorClear( ent->s.apos.trDelta );
00578         ent->s.apos.trDuration = 1;
00579         ent->s.apos.trType = TR_STATIONARY;
00580         ent->s.apos.trTime = level.time;
00581 
00582         //Stop thinking
00583         ent->reached = 0;
00584         if ( ent->think == anglerCallback )
00585         {
00586                 ent->think = 0;
00587         }
00588 
00589         //link
00590         trap_LinkEntity( ent );
00591 }
00592 
00593 void MatchTeam( gentity_t *teamLeader, int moverState, int time );
00594 void Blocked_Mover( gentity_t *ent, gentity_t *other );
00595 
00596 /*
00597 =============
00598 moverCallback
00599 
00600 Utility function
00601 =============
00602 */
00603 void moverCallback( gentity_t *ent )
00604 {       //complete the task
00605         trap_ICARUS_TaskIDComplete( ent, TID_MOVE_NAV );
00606         
00607         // play sound
00608         ent->s.loopSound = 0;//stop looping sound
00609         ent->s.loopIsSoundset = qfalse;
00610         G_PlayDoorSound( ent, BMS_END );//play end sound
00611 
00612         if ( ent->moverState == MOVER_1TO2 ) 
00613         {//reached open
00614                 // reached pos2
00615                 MatchTeam( ent, MOVER_POS2, level.time );
00616                 //SetMoverState( ent, MOVER_POS2, level.time );
00617         } 
00618         else if ( ent->moverState == MOVER_2TO1 ) 
00619         {//reached closed
00620                 MatchTeam( ent, MOVER_POS1, level.time );
00621                 //SetMoverState( ent, MOVER_POS1, level.time );
00622         }
00623 
00624         if ( ent->blocked == Blocked_Mover )
00625         {
00626                 ent->blocked = 0;
00627         }
00628 
00629 //      if ( !Q_stricmp( "misc_model_breakable", ent->classname ) && ent->physicsBounce )
00630 //      {//a gravity-affected model
00631 //              misc_model_breakable_gravity_init( ent, qfalse );
00632 //      }
00633 }
00634 
00635 void Blocked_Mover( gentity_t *ent, gentity_t *other )
00636 {
00637         // remove anything other than a client -- no longer the case
00638 
00639         // don't remove security keys or goodie keys
00640         if ( (other->s.eType == ET_ITEM) )
00641         {
00642                 // should we be doing anything special if a key blocks it... move it somehow..?
00643         }
00644         // if your not a client, or your a dead client remove yourself...
00645         else if ( other->s.number && (!other->client || (other->client && other->health <= 0 && other->r.contents == CONTENTS_CORPSE && !other->message)) )
00646         {
00647                 //if ( !other->taskManager || !other->taskManager->IsRunning() )
00648                 {
00649                         // if an item or weapon can we do a little explosion..?
00650                         G_FreeEntity( other );
00651                         return;
00652                 }
00653         }
00654 
00655         if ( ent->damage ) {
00656                 G_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH );
00657         }
00658 }
00659 
00660 /*
00661 =============
00662 moveAndRotateCallback
00663 
00664 Utility function
00665 =============
00666 */
00667 void moveAndRotateCallback( gentity_t *ent )
00668 {
00669         //stop turning
00670         anglerCallback( ent );
00671         //stop moving
00672         moverCallback( ent );
00673 }
00674 
00675 /*
00676 =============
00677 Q3_Lerp2Start
00678 
00679 Lerps the origin of an entity to its starting position
00680 =============
00681 */
00682 void Q3_Lerp2Start( int entID, int taskID, float duration )
00683 {
00684         gentity_t       *ent = &g_entities[entID];
00685 
00686         if(!ent)
00687         {       
00688                 G_DebugPrint( WL_WARNING, "Q3_Lerp2Start: invalid entID %d\n", entID);
00689                 return;
00690         }
00691         
00692         if ( ent->client || Q_stricmp(ent->classname, "target_scriptrunner") == 0 )
00693         {
00694                 G_DebugPrint( WL_ERROR, "Q3_Lerp2Start: ent %d is NOT a mover!\n", entID);
00695                 return;
00696         }
00697 
00698         if ( ent->s.eType != ET_MOVER )
00699         {
00700                 ent->s.eType = ET_MOVER;
00701         }
00702 
00703         //FIXME: set up correctly!!!
00704         ent->moverState = MOVER_2TO1;
00705         ent->s.eType = ET_MOVER;
00706         ent->reached = moverCallback;           //Callsback the the completion of the move
00707         if ( ent->damage )
00708         {
00709                 ent->blocked = Blocked_Mover;
00710         }
00711 
00712         ent->s.pos.trDuration = duration * 10;  //In seconds
00713         ent->s.pos.trTime = level.time;
00714         
00715         trap_ICARUS_TaskIDSet( ent, TID_MOVE_NAV, taskID );
00716         // starting sound
00717         G_PlayDoorLoopSound( ent );
00718         G_PlayDoorSound( ent, BMS_START );      //??
00719 
00720         trap_LinkEntity( ent );
00721 }
00722 
00723 /*
00724 =============
00725 Q3_Lerp2End
00726 
00727 Lerps the origin of an entity to its ending position
00728 =============
00729 */
00730 void Q3_Lerp2End( int entID, int taskID, float duration )
00731 {
00732         gentity_t       *ent = &g_entities[entID];
00733 
00734         if(!ent)
00735         {
00736                 G_DebugPrint( WL_WARNING, "Q3_Lerp2End: invalid entID %d\n", entID);
00737                 return;
00738         }
00739         
00740         if ( ent->client || Q_stricmp(ent->classname, "target_scriptrunner") == 0 )
00741         {
00742                 G_DebugPrint( WL_ERROR, "Q3_Lerp2End: ent %d is NOT a mover!\n", entID);
00743                 return;
00744         }
00745 
00746         if ( ent->s.eType != ET_MOVER )
00747         {
00748                 ent->s.eType = ET_MOVER;
00749         }
00750 
00751         //FIXME: set up correctly!!!
00752         ent->moverState = MOVER_1TO2;
00753         ent->s.eType = ET_MOVER;
00754         ent->reached = moverCallback;           //Callsback the the completion of the move
00755         if ( ent->damage )
00756         {
00757                 ent->blocked = Blocked_Mover;
00758         }
00759 
00760         ent->s.pos.trDuration = duration * 10;  //In seconds
00761         ent->s.time = level.time;
00762         
00763         trap_ICARUS_TaskIDSet( ent, TID_MOVE_NAV, taskID );
00764         // starting sound
00765         G_PlayDoorLoopSound( ent );
00766         G_PlayDoorSound( ent, BMS_START );      //??
00767 
00768         trap_LinkEntity( ent );
00769 }
00770 
00771 void InitMoverTrData( gentity_t *ent );
00772 
00773 /*
00774 =============
00775 Q3_Lerp2Pos
00776 
00777 Lerps the origin and angles of an entity to the destination values
00778 
00779 =============
00780 */
00781 void Q3_Lerp2Pos( int taskID, int entID, vec3_t origin, vec3_t angles, float duration )
00782 {
00783         gentity_t       *ent = &g_entities[entID];
00784         vec3_t          ang;
00785         int                     i;
00786         moverState_t moverState;
00787 
00788         if(!ent)
00789         {
00790                 G_DebugPrint( WL_WARNING, "Q3_Lerp2Pos: invalid entID %d\n", entID);
00791                 return;
00792         }
00793         
00794         if ( ent->client || Q_stricmp(ent->classname, "target_scriptrunner") == 0 )
00795         {
00796                 G_DebugPrint( WL_ERROR, "Q3_Lerp2Pos: ent %d is NOT a mover!\n", entID);
00797                 return;
00798         }
00799 
00800         if ( ent->s.eType != ET_MOVER )
00801         {
00802                 ent->s.eType = ET_MOVER;
00803         }
00804 
00805         //Don't allow a zero duration
00806         if ( duration == 0 )
00807                 duration = 1;
00808 
00809         //
00810         // Movement
00811 
00812         moverState = ent->moverState;
00813 
00814         if ( moverState == MOVER_POS1 || moverState == MOVER_2TO1 )
00815         {
00816                 VectorCopy( ent->r.currentOrigin, ent->pos1 );
00817                 VectorCopy( origin, ent->pos2 );
00818 
00819                 moverState = MOVER_1TO2;
00820         }
00821         else
00822         {
00823                 VectorCopy( ent->r.currentOrigin, ent->pos2 );
00824                 VectorCopy( origin, ent->pos1 );
00825 
00826                 moverState = MOVER_2TO1;
00827         }
00828 
00829         InitMoverTrData( ent );
00830 
00831         ent->s.pos.trDuration = duration;
00832 
00833         // start it going
00834         MatchTeam( ent, moverState, level.time );
00835         //SetMoverState( ent, moverState, level.time );
00836 
00837         //Only do the angles if specified
00838         if ( angles != NULL )
00839         {
00840                 //
00841                 // Rotation
00842 
00843                 for ( i = 0; i < 3; i++ )
00844                 {
00845                         ang[i] = AngleDelta( angles[i], ent->r.currentAngles[i] );
00846                         ent->s.apos.trDelta[i] = ( ang[i] / ( duration * 0.001f ) );
00847                 }
00848 
00849                 VectorCopy( ent->r.currentAngles, ent->s.apos.trBase );
00850 
00851                 if ( ent->alt_fire )
00852                 {
00853                         ent->s.apos.trType = TR_LINEAR_STOP;
00854                 }
00855                 else
00856                 {
00857                         ent->s.apos.trType = TR_NONLINEAR_STOP;
00858                 }
00859                 ent->s.apos.trDuration = duration;
00860 
00861                 ent->s.apos.trTime = level.time;
00862 
00863                 ent->reached = moveAndRotateCallback;
00864                 trap_ICARUS_TaskIDSet( ent, TID_ANGLE_FACE, taskID );
00865         }
00866         else
00867         {
00868                 //Setup the last bits of information
00869                 ent->reached = moverCallback;
00870         }
00871 
00872         if ( ent->damage )
00873         {
00874                 ent->blocked = Blocked_Mover;
00875         }
00876 
00877         trap_ICARUS_TaskIDSet( ent, TID_MOVE_NAV, taskID );
00878         // starting sound
00879         G_PlayDoorLoopSound( ent );
00880         G_PlayDoorSound( ent, BMS_START );      //??
00881 
00882         trap_LinkEntity( ent );
00883 }
00884 
00885 /*
00886 =============
00887 Q3_LerpAngles
00888 
00889 Lerps the angles to the destination value
00890 =============
00891 */
00892 void Q3_Lerp2Angles( int taskID, int entID, vec3_t angles, float duration )
00893 {
00894         gentity_t       *ent = &g_entities[entID];
00895         vec3_t          ang;
00896         int                     i;
00897 
00898         if(!ent)
00899         {
00900                 G_DebugPrint( WL_WARNING, "Q3_Lerp2Angles: invalid entID %d\n", entID);
00901                 return;
00902         }
00903         
00904         if ( ent->client || Q_stricmp(ent->classname, "target_scriptrunner") == 0 )
00905         {
00906                 G_DebugPrint( WL_ERROR, "Q3_Lerp2Angles: ent %d is NOT a mover!\n", entID);
00907                 return;
00908         }
00909 
00910         //If we want an instant move, don't send 0...
00911         ent->s.apos.trDuration = (duration>0) ? duration : 1;
00912 
00913         for ( i = 0; i < 3; i++ )
00914         {
00915                 ang [i] = AngleSubtract( angles[i], ent->r.currentAngles[i]);
00916                 ent->s.apos.trDelta[i] = ( ang[i] / ( ent->s.apos.trDuration * 0.001f ) );
00917         }
00918 
00919         VectorCopy( ent->r.currentAngles, ent->s.apos.trBase );
00920 
00921         if ( ent->alt_fire )
00922         {
00923                 ent->s.apos.trType = TR_LINEAR_STOP;
00924         }
00925         else
00926         {
00927                 ent->s.apos.trType = TR_NONLINEAR_STOP;
00928         }
00929 
00930         ent->s.apos.trTime = level.time;
00931         
00932         trap_ICARUS_TaskIDSet( ent, TID_ANGLE_FACE, taskID );
00933 
00934         //ent->e_ReachedFunc = reachedF_NULL;
00935         ent->think = anglerCallback;
00936         ent->nextthink = level.time + duration;
00937 
00938         trap_LinkEntity( ent );
00939 }
00940 
00941 /*
00942 =============
00943 Q3_GetTag
00944 
00945 Gets the value of a tag by the give name
00946 =============
00947 */
00948 int     Q3_GetTag( int entID, const char *name, int lookup, vec3_t info )
00949 {
00950         gentity_t       *ent = &g_entities[entID];
00951 
00952         if (!ent->inuse)
00953         {
00954                 assert(0);
00955                 return 0;
00956         }
00957 
00958         switch ( lookup )
00959         {
00960         case TYPE_ORIGIN:
00961                 return TAG_GetOrigin( ent->ownername, name, info );
00962                 break;
00963 
00964         case TYPE_ANGLES:
00965                 return TAG_GetAngles( ent->ownername, name, info );
00966                 break;  
00967         }
00968 
00969         return 0;
00970 }
00971 
00972 //-----------------------------------------------
00973 
00974 /*
00975 ============
00976 Q3_Use
00977 
00978 Uses an entity
00979 ============
00980 */
00981 void Q3_Use( int entID, const char *target )
00982 {
00983         gentity_t       *ent  = &g_entities[entID];
00984         
00985         if ( !ent )
00986         {
00987                 G_DebugPrint( WL_WARNING, "Q3_Use: invalid entID %d\n", entID);
00988                 return;
00989         }
00990 
00991         if( !target || !target[0] )
00992         {
00993                 G_DebugPrint( WL_WARNING, "Q3_Use: string is NULL!\n" );
00994                 return;
00995         }
00996 
00997         G_UseTargets2(ent, ent, target);
00998 }
00999 
01000 /*
01001 ============
01002 Q3_Kill
01003   Description   : 
01004   Return type   : void 
01005   Argument              :  int entID
01006   Argument              : const char *name
01007 ============
01008 */
01009 void Q3_Kill( int entID, const char *name )
01010 {
01011         gentity_t       *ent = &g_entities[entID];
01012         gentity_t       *victim = NULL;
01013         int                     o_health;
01014 
01015         if( !Q_stricmp( name, "self") )
01016         {
01017                 victim = ent;
01018         }
01019         else if( !Q_stricmp( name, "enemy" ) )
01020         {
01021                 victim = ent->enemy;
01022         }
01023         else
01024         {
01025                 victim = G_Find (NULL, FOFS(targetname), (char *) name );
01026         }
01027 
01028         if ( !victim )
01029         {
01030                 G_DebugPrint( WL_WARNING, "Q3_Kill: can't find %s\n", name);
01031                 return;
01032         }
01033 
01034         //rww - I guess this would only apply to NPCs anyway. I'm not going to bother.
01035         //if ( victim == ent )
01036         //{//don't ICARUS_FreeEnt me, I'm in the middle of a script!  (FIXME: shouldn't ICARUS handle this internally?)
01037         //      victim->svFlags |= SVF_KILLED_SELF;
01038         //}
01039 
01040         o_health = victim->health;
01041         victim->health = 0;
01042         if ( victim->client )
01043         {
01044                 victim->flags |= FL_NO_KNOCKBACK;
01045         }
01046         //G_SetEnemy(victim, ent);
01047         if( victim->die != NULL )       // check can be omitted
01048         {
01049                 //GEntity_DieFunc( victim, NULL, NULL, o_health, MOD_UNKNOWN );
01050                 victim->die(victim, victim, victim, o_health, MOD_UNKNOWN);
01051         }
01052 }
01053 
01054 /*
01055 ============
01056 Q3_RemoveEnt
01057   Description   : 
01058   Return type   : void 
01059   Argument              : sharedEntity_t *victim
01060 ============
01061 */
01062 void Q3_RemoveEnt( gentity_t *victim )
01063 {
01064         if( victim->client )
01065         {
01066                 if ( victim->s.eType != ET_NPC )
01067                 {
01068                         G_DebugPrint( WL_WARNING, "Q3_RemoveEnt: You can't remove clients in MP!\n" );
01069                         assert(0); //can't remove clients in MP
01070                 }
01071                 else
01072                 {//remove the NPC
01073                         if ( victim->client->NPC_class == CLASS_VEHICLE )
01074                         {//eject everyone out of a vehicle that's about to remove itself
01075                                 Vehicle_t *pVeh = victim->m_pVehicle;
01076                                 if ( pVeh && pVeh->m_pVehicleInfo )
01077                                 {
01078                                         pVeh->m_pVehicleInfo->EjectAll( pVeh );
01079                                 }
01080                         }
01081                         victim->think = G_FreeEntity;
01082                         victim->nextthink = level.time + 100;
01083                 }
01084                 /*
01085                 //ClientDisconnect(ent);
01086                 victim->s.eFlags |= EF_NODRAW;
01087                 victim->s.eType = ET_INVISIBLE;
01088                 victim->contents = 0;
01089                 victim->health = 0;
01090                 victim->targetname = NULL;
01091 
01092                 if ( victim->NPC && victim->NPC->tempGoal != NULL )
01093                 {
01094                         G_FreeEntity( victim->NPC->tempGoal );
01095                         victim->NPC->tempGoal = NULL;
01096                 }
01097                 if ( victim->client->ps.saberEntityNum != ENTITYNUM_NONE && victim->client->ps.saberEntityNum > 0 )
01098                 {
01099                         if ( g_entities[victim->client->ps.saberEntityNum].inuse )
01100                         {
01101                                 G_FreeEntity( &g_entities[victim->client->ps.saberEntityNum] );
01102                         }
01103                         victim->client->ps.saberEntityNum = ENTITYNUM_NONE;
01104                 }
01105                 //Disappear in half a second
01106                 victim->e_ThinkFunc = thinkF_G_FreeEntity;
01107                 victim->nextthink = level.time + 500;
01108                 return;
01109                 */
01110         }
01111         else
01112         {
01113                 victim->think = G_FreeEntity;
01114                 victim->nextthink = level.time + 100;
01115         }
01116 }
01117 
01118 
01119 /*
01120 ============
01121 Q3_Remove
01122   Description   : 
01123   Return type   : void 
01124   Argument              :  int entID
01125   Argument              : const char *name
01126 ============
01127 */
01128 void Q3_Remove( int entID, const char *name )
01129 {
01130         gentity_t *ent = &g_entities[entID];
01131         gentity_t       *victim = NULL;
01132 
01133         if( !Q_stricmp( "self", name ) )
01134         {
01135                 victim = ent;
01136                 if ( !victim )
01137                 {
01138                         G_DebugPrint( WL_WARNING, "Q3_Remove: can't find %s\n", name );
01139                         return;
01140                 }
01141                 Q3_RemoveEnt( victim );
01142         }
01143         else if( !Q_stricmp( "enemy", name ) )
01144         {
01145                 victim = ent->enemy;
01146                 if ( !victim )
01147                 {
01148                         G_DebugPrint( WL_WARNING, "Q3_Remove: can't find %s\n", name );
01149                         return;
01150                 }
01151                 Q3_RemoveEnt( victim );
01152         }
01153         else
01154         {
01155                 victim = G_Find( NULL, FOFS(targetname), (char *) name );
01156                 if ( !victim )
01157                 {
01158                         G_DebugPrint( WL_WARNING, "Q3_Remove: can't find %s\n", name );
01159                         return;
01160                 }
01161 
01162                 while ( victim )
01163                 {
01164                         Q3_RemoveEnt( victim );
01165                         victim = G_Find( victim, FOFS(targetname), (char *) name );
01166                 }
01167         }
01168 }
01169 
01170 /*
01171 =================================================
01172 
01173   Get / Set Functions
01174 
01175 =================================================
01176 */
01177 
01178 /*
01179 ============
01180 Q3_GetFloat
01181   Description   : 
01182   Return type   : int 
01183   Argument              :  int entID
01184   Argument              : int type
01185   Argument              : const char *name
01186   Argument              : float *value
01187 ============
01188 */
01189 int Q3_GetFloat( int entID, int type, const char *name, float *value )
01190 {
01191         gentity_t       *ent = &g_entities[entID];
01192         int toGet = 0;
01193 
01194         if ( !ent )
01195         {
01196                 return 0;
01197         }
01198 
01199         toGet = GetIDForString( setTable, name );       //FIXME: May want to make a "getTable" as well
01200         //FIXME: I'm getting really sick of these huge switch statements!
01201 
01202         //NOTENOTE: return true if the value was correctly obtained
01203         switch ( toGet )
01204         {
01205         case SET_PARM1:
01206         case SET_PARM2:
01207         case SET_PARM3:
01208         case SET_PARM4:
01209         case SET_PARM5:
01210         case SET_PARM6:
01211         case SET_PARM7:
01212         case SET_PARM8:
01213         case SET_PARM9:
01214         case SET_PARM10:
01215         case SET_PARM11:
01216         case SET_PARM12:
01217         case SET_PARM13:
01218         case SET_PARM14:
01219         case SET_PARM15:
01220         case SET_PARM16:
01221                 if (ent->parms == NULL)
01222                 {
01223                         G_DebugPrint( WL_ERROR, "GET_PARM: %s %s did not have any parms set!\n", ent->classname, ent->targetname );
01224                         return 0;       // would prefer qfalse, but I'm fitting in with what's here <sigh>
01225                 }
01226                 *value = atof( ent->parms->parm[toGet - SET_PARM1] );
01227                 break;
01228         
01229         case SET_COUNT:
01230                 *value = ent->count;
01231                 break;
01232 
01233         case SET_HEALTH:
01234                 *value = ent->health;
01235                 break;
01236 
01237         case SET_SKILL:
01238                 return 0;
01239                 break;
01240 
01241         case SET_XVELOCITY://## %f="0.0" # Velocity along X axis
01242                 if ( ent->client == NULL )
01243                 {
01244                         G_DebugPrint( WL_WARNING, "Q3_GetFloat: SET_XVELOCITY, %s not a client\n", ent->targetname );
01245                         return 0;
01246                 }
01247                 *value = ent->client->ps.velocity[0];
01248                 break;
01249 
01250         case SET_YVELOCITY://## %f="0.0" # Velocity along Y axis
01251                 if ( ent->client == NULL )
01252                 {
01253                         G_DebugPrint( WL_WARNING, "Q3_GetFloat: SET_YVELOCITY, %s not a client\n", ent->targetname );
01254                         return 0;
01255                 }
01256                 *value = ent->client->ps.velocity[1];
01257                 break;
01258 
01259         case SET_ZVELOCITY://## %f="0.0" # Velocity along Z axis
01260                 if ( ent->client == NULL )
01261                 {
01262                         G_DebugPrint( WL_WARNING, "Q3_GetFloat: SET_ZVELOCITY, %s not a client\n", ent->targetname );
01263                         return 0;
01264                 }
01265                 *value = ent->client->ps.velocity[2];
01266                 break;
01267 
01268         case SET_Z_OFFSET:
01269                 *value = ent->r.currentOrigin[2] - ent->s.origin[2];
01270                 break;
01271 
01272         case SET_DPITCH://## %f="0.0" # Pitch for NPC to turn to
01273                 return 0;
01274                 break;
01275 
01276         case SET_DYAW://## %f="0.0" # Yaw for NPC to turn to
01277                 return 0;
01278                 break;
01279 
01280         case SET_WIDTH://## %f="0.0" # Width of NPC bounding box
01281                 *value = ent->r.mins[0];
01282                 break;
01283         case SET_TIMESCALE://## %f="0.0" # Speed-up slow down game (0 - 1.0)
01284                 return 0;
01285                 break;
01286         case SET_CAMERA_GROUP_Z_OFS://## %s="NULL" # all ents with this cameraGroup will be focused on
01287                 return 0;
01288                 break;
01289 
01290         case SET_VISRANGE://## %f="0.0" # How far away NPC can see
01291                 return 0;
01292                 break;
01293 
01294         case SET_EARSHOT://## %f="0.0" # How far an NPC can hear
01295                 return 0;
01296                 break;
01297 
01298         case SET_VIGILANCE://## %f="0.0" # How often to look for enemies (0 - 1.0)
01299                 return 0;
01300                 break;
01301 
01302         case SET_GRAVITY://## %f="0.0" # Change this ent's gravity - 800 default
01303                 *value = g_gravity.value;
01304                 break;
01305 
01306         case SET_FACEEYESCLOSED:
01307         case SET_FACEEYESOPENED:
01308         case