codemp/game/bg_misc.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // bg_misc.c -- both games misc functions, all completely stateless
00004 
00005 #include "q_shared.h"
00006 #include "bg_public.h"
00007 #include "bg_strap.h"
00008 
00009 #ifdef QAGAME
00010 #include "g_local.h"
00011 #endif
00012 
00013 #ifdef UI_EXPORTS
00014 #include "../ui/ui_local.h"
00015 #endif
00016 
00017 #ifndef UI_EXPORTS
00018 #ifndef QAGAME
00019 #include "../cgame/cg_local.h"
00020 #endif
00021 #endif
00022 
00023 #ifdef _XBOX
00024 extern void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit, int iAlign);
00025 extern void Z_Free(void *pvAddress);
00026 #endif
00027 
00028 #ifdef QAGAME
00029 extern void Q3_SetParm (int entID, int parmNum, const char *parmValue);
00030 #endif
00031 
00032 #include "../namespace_begin.h"
00033 
00034 const char *bgToggleableSurfaces[BG_NUM_TOGGLEABLE_SURFACES] = 
00035 {
00036         "l_arm_key",                                    //0
00037         "torso_canister1",
00038         "torso_canister2",
00039         "torso_canister3",
00040         "torso_tube1",
00041         "torso_tube2",                                  //5
00042         "torso_tube3",
00043         "torso_tube4",
00044         "torso_tube5",
00045         "torso_tube6",
00046         "r_arm",                                                //10
00047         "l_arm",
00048         "torso_shield",
00049         "torso_galaktorso",
00050         "torso_collar",
00051 //      "torso_eyes_mouth",                             //15
00052 //      "torso_galakhead",
00053 //      "torso_galakface",
00054 //      "torso_antenna_base_cap",
00055 //      "torso_antenna",
00056 //      "l_arm_augment",                                //20
00057 //      "l_arm_middle",
00058 //      "l_arm_wrist",
00059 //      "r_arm_middle", //yeah.. galak's surf stuff is no longer auto, sorry! need the space for vehicle surfs.
00060         "r_wing1",                                              //15
00061         "r_wing2",
00062         "l_wing1",
00063         "l_wing2",
00064         "r_gear",
00065         "l_gear",                                               //20
00066         "nose",
00067         "blah4",
00068         "blah5",
00069         "l_hand",
00070         "r_hand",                                               //25
00071         "helmet",
00072         "head",
00073         "head_concussion_charger",
00074         "head_light_blaster_cann",              //29
00075         NULL
00076 };
00077 
00078 const int bgToggleableSurfaceDebris[BG_NUM_TOGGLEABLE_SURFACES] =
00079 {
00080         0,                                      //0
00081         0,
00082         0,
00083         0,
00084         0,
00085         0,                                      //5
00086         0,
00087         0,
00088         0,
00089         0,
00090         0,                                      //10
00091         0,
00092         0,
00093         0,
00094         0, //>= 2 means it should create a flame trail when destroyed (for vehicles)
00095         3,                                      //15
00096         5, //rwing2
00097         4,
00098         6, //lwing2
00099         0, //rgear
00100         0, //lgear                      //20
00101         7, //nose
00102         0, //blah
00103         0, //blah
00104         0,
00105         0,                                      //25
00106         0,
00107         0,
00108         0,
00109         0,                                      //29
00110         -1
00111 };
00112 
00113 const char      *bg_customSiegeSoundNames[MAX_CUSTOM_SIEGE_SOUNDS] = 
00114 {
00115         "*att_attack",
00116         "*att_primary",
00117         "*att_second",
00118         "*def_guns",
00119         "*def_position",
00120         "*def_primary",
00121         "*def_second",
00122         "*reply_coming",
00123         "*reply_go",
00124         "*reply_no",
00125         "*reply_stay",
00126         "*reply_yes",
00127         "*req_assist",
00128         "*req_demo",
00129         "*req_hvy",
00130         "*req_medic",
00131         "*req_sup",
00132         "*req_tech",
00133         "*spot_air",
00134         "*spot_defenses",
00135         "*spot_emplaced",
00136         "*spot_sniper",
00137         "*spot_troops",
00138         "*tac_cover",
00139         "*tac_fallback",
00140         "*tac_follow",
00141         "*tac_hold",
00142         "*tac_split",
00143         "*tac_together",
00144         NULL
00145 };
00146 
00147 //rww - not putting @ in front of these because
00148 //we don't need them in a cgame StringEd lookup.
00149 //Let me know if this causes problems, pat.
00150 char *forceMasteryLevels[NUM_FORCE_MASTERY_LEVELS] = 
00151 {
00152         "MASTERY0",     //"Uninitiated",        // FORCE_MASTERY_UNINITIATED,
00153         "MASTERY1",     //"Initiate",           // FORCE_MASTERY_INITIATE,
00154         "MASTERY2",     //"Padawan",            // FORCE_MASTERY_PADAWAN,
00155         "MASTERY3",     //"Jedi",                       // FORCE_MASTERY_JEDI,
00156         "MASTERY4",     //"Jedi Adept",         // FORCE_MASTERY_JEDI_GUARDIAN,
00157         "MASTERY5",     //"Jedi Guardian",      // FORCE_MASTERY_JEDI_ADEPT,
00158         "MASTERY6",     //"Jedi Knight",        // FORCE_MASTERY_JEDI_KNIGHT,
00159         "MASTERY7",     //"Jedi Master"         // FORCE_MASTERY_JEDI_MASTER,
00160 };
00161 
00162 int forceMasteryPoints[NUM_FORCE_MASTERY_LEVELS] =
00163 {
00164         0,              // FORCE_MASTERY_UNINITIATED,
00165         5,              // FORCE_MASTERY_INITIATE,
00166         10,             // FORCE_MASTERY_PADAWAN,
00167         20,             // FORCE_MASTERY_JEDI,
00168         30,             // FORCE_MASTERY_JEDI_GUARDIAN,
00169         50,             // FORCE_MASTERY_JEDI_ADEPT,
00170         75,             // FORCE_MASTERY_JEDI_KNIGHT,
00171         100             // FORCE_MASTERY_JEDI_MASTER,
00172 };
00173 
00174 int bgForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS] = //0 == neutral
00175 {
00176         {       0,      2,      4,      6       },      // Heal                 // FP_HEAL
00177         {       0,      0,      2,      6       },      // Jump                 //FP_LEVITATION,//hold/duration
00178         {       0,      2,      4,      6       },      // Speed                //FP_SPEED,//duration
00179         {       0,      1,      3,      6       },      // Push                 //FP_PUSH,//hold/duration
00180         {       0,      1,      3,      6       },      // Pull                 //FP_PULL,//hold/duration
00181         {       0,      4,      6,      8       },      // Mind Trick   //FP_TELEPATHY,//instant
00182         {       0,      1,      3,      6       },      // Grip                 //FP_GRIP,//hold/duration
00183         {       0,      2,      5,      8       },      // Lightning    //FP_LIGHTNING,//hold/duration
00184         {       0,      4,      6,      8       },      // Dark Rage    //FP_RAGE,//duration
00185         {       0,      2,      5,      8       },      // Protection   //FP_PROTECT,//duration
00186         {       0,      1,      3,      6       },      // Absorb               //FP_ABSORB,//duration
00187         {       0,      1,      3,      6       },      // Team Heal    //FP_TEAM_HEAL,//instant
00188         {       0,      1,      3,      6       },      // Team Force   //FP_TEAM_FORCE,//instant
00189         {       0,      2,      4,      6       },      // Drain                //FP_DRAIN,//hold/duration
00190         {       0,      2,      5,      8       },      // Sight                //FP_SEE,//duration
00191         {       0,      1,      5,      8       },      // Saber Attack //FP_SABER_OFFENSE,
00192         {       0,      1,      5,      8       },      // Saber Defend //FP_SABER_DEFENSE,
00193         {       0,      4,      6,      8       }       // Saber Throw  //FP_SABERTHROW,
00194         //NUM_FORCE_POWERS
00195 };
00196 
00197 int forcePowerSorted[NUM_FORCE_POWERS] = 
00198 { //rww - always use this order when drawing force powers for any reason
00199         FP_TELEPATHY,
00200         FP_HEAL,
00201         FP_ABSORB,
00202         FP_PROTECT,
00203         FP_TEAM_HEAL,
00204         FP_LEVITATION,
00205         FP_SPEED,
00206         FP_PUSH,
00207         FP_PULL,
00208         FP_SEE,
00209         FP_LIGHTNING,
00210         FP_DRAIN,
00211         FP_RAGE,
00212         FP_GRIP,
00213         FP_TEAM_FORCE,
00214         FP_SABER_OFFENSE,
00215         FP_SABER_DEFENSE,
00216         FP_SABERTHROW
00217 };
00218 
00219 int forcePowerDarkLight[NUM_FORCE_POWERS] = //0 == neutral
00220 { //nothing should be usable at rank 0..
00221         FORCE_LIGHTSIDE,//FP_HEAL,//instant
00222         0,//FP_LEVITATION,//hold/duration
00223         0,//FP_SPEED,//duration
00224         0,//FP_PUSH,//hold/duration
00225         0,//FP_PULL,//hold/duration
00226         FORCE_LIGHTSIDE,//FP_TELEPATHY,//instant
00227         FORCE_DARKSIDE,//FP_GRIP,//hold/duration
00228         FORCE_DARKSIDE,//FP_LIGHTNING,//hold/duration
00229         FORCE_DARKSIDE,//FP_RAGE,//duration
00230         FORCE_LIGHTSIDE,//FP_PROTECT,//duration
00231         FORCE_LIGHTSIDE,//FP_ABSORB,//duration
00232         FORCE_LIGHTSIDE,//FP_TEAM_HEAL,//instant
00233         FORCE_DARKSIDE,//FP_TEAM_FORCE,//instant
00234         FORCE_DARKSIDE,//FP_DRAIN,//hold/duration
00235         0,//FP_SEE,//duration
00236         0,//FP_SABER_OFFENSE,
00237         0,//FP_SABER_DEFENSE,
00238         0//FP_SABERTHROW,
00239                 //NUM_FORCE_POWERS
00240 };
00241 
00242 int WeaponReadyAnim[WP_NUM_WEAPONS] =
00243 {
00244         TORSO_DROPWEAP1,//WP_NONE,
00245 
00246         TORSO_WEAPONREADY3,//WP_STUN_BATON,
00247         TORSO_WEAPONREADY3,//WP_MELEE,
00248         BOTH_STAND2,//WP_SABER,
00249         TORSO_WEAPONREADY2,//WP_BRYAR_PISTOL,
00250         TORSO_WEAPONREADY3,//WP_BLASTER,
00251         TORSO_WEAPONREADY3,//TORSO_WEAPONREADY4,//WP_DISRUPTOR,
00252         TORSO_WEAPONREADY3,//TORSO_WEAPONREADY5,//WP_BOWCASTER,
00253         TORSO_WEAPONREADY3,//TORSO_WEAPONREADY6,//WP_REPEATER,
00254         TORSO_WEAPONREADY3,//TORSO_WEAPONREADY7,//WP_DEMP2,
00255         TORSO_WEAPONREADY3,//TORSO_WEAPONREADY8,//WP_FLECHETTE,
00256         TORSO_WEAPONREADY3,//TORSO_WEAPONREADY9,//WP_ROCKET_LAUNCHER,
00257         TORSO_WEAPONREADY10,//WP_THERMAL,
00258         TORSO_WEAPONREADY10,//TORSO_WEAPONREADY11,//WP_TRIP_MINE,
00259         TORSO_WEAPONREADY10,//TORSO_WEAPONREADY12,//WP_DET_PACK,
00260         TORSO_WEAPONREADY3,//WP_CONCUSSION
00261         TORSO_WEAPONREADY2,//WP_BRYAR_OLD,
00262 
00263         //NOT VALID (e.g. should never really be used):
00264         BOTH_STAND1,//WP_EMPLACED_GUN,
00265         TORSO_WEAPONREADY1//WP_TURRET,
00266 };
00267 
00268 int WeaponReadyLegsAnim[WP_NUM_WEAPONS] =
00269 {
00270         BOTH_STAND1,//WP_NONE,
00271 
00272         BOTH_STAND1,//WP_STUN_BATON,
00273         BOTH_STAND1,//WP_MELEE,
00274         BOTH_STAND2,//WP_SABER,
00275         BOTH_STAND1,//WP_BRYAR_PISTOL,
00276         BOTH_STAND1,//WP_BLASTER,
00277         BOTH_STAND1,//TORSO_WEAPONREADY4,//WP_DISRUPTOR,
00278         BOTH_STAND1,//TORSO_WEAPONREADY5,//WP_BOWCASTER,
00279         BOTH_STAND1,//TORSO_WEAPONREADY6,//WP_REPEATER,
00280         BOTH_STAND1,//TORSO_WEAPONREADY7,//WP_DEMP2,
00281         BOTH_STAND1,//TORSO_WEAPONREADY8,//WP_FLECHETTE,
00282         BOTH_STAND1,//TORSO_WEAPONREADY9,//WP_ROCKET_LAUNCHER,
00283         BOTH_STAND1,//WP_THERMAL,
00284         BOTH_STAND1,//TORSO_WEAPONREADY11,//WP_TRIP_MINE,
00285         BOTH_STAND1,//TORSO_WEAPONREADY12,//WP_DET_PACK,
00286         BOTH_STAND1,//WP_CONCUSSION
00287         BOTH_STAND1,//WP_BRYAR_OLD,
00288 
00289         //NOT VALID (e.g. should never really be used):
00290         BOTH_STAND1,//WP_EMPLACED_GUN,
00291         BOTH_STAND1//WP_TURRET,
00292 };
00293 
00294 int WeaponAttackAnim[WP_NUM_WEAPONS] =
00295 {
00296         BOTH_ATTACK1,//WP_NONE, //(shouldn't happen)
00297 
00298         BOTH_ATTACK3,//WP_STUN_BATON,
00299         BOTH_ATTACK3,//WP_MELEE,
00300         BOTH_STAND2,//WP_SABER, //(has its own handling)
00301         BOTH_ATTACK2,//WP_BRYAR_PISTOL,
00302         BOTH_ATTACK3,//WP_BLASTER,
00303         BOTH_ATTACK3,//BOTH_ATTACK4,//WP_DISRUPTOR,
00304         BOTH_ATTACK3,//BOTH_ATTACK5,//WP_BOWCASTER,
00305         BOTH_ATTACK3,//BOTH_ATTACK6,//WP_REPEATER,
00306         BOTH_ATTACK3,//BOTH_ATTACK7,//WP_DEMP2,
00307         BOTH_ATTACK3,//BOTH_ATTACK8,//WP_FLECHETTE,
00308         BOTH_ATTACK3,//BOTH_ATTACK9,//WP_ROCKET_LAUNCHER,
00309         BOTH_THERMAL_THROW,//WP_THERMAL,
00310         BOTH_ATTACK3,//BOTH_ATTACK11,//WP_TRIP_MINE,
00311         BOTH_ATTACK3,//BOTH_ATTACK12,//WP_DET_PACK,
00312         BOTH_ATTACK2,//WP_BRYAR_OLD,
00313 
00314         //NOT VALID (e.g. should never really be used):
00315         BOTH_STAND1,//WP_EMPLACED_GUN,
00316         BOTH_ATTACK1//WP_TURRET,
00317 };
00318 
00319 qboolean BG_FileExists(const char *fileName)
00320 {
00321         if (fileName && fileName[0])
00322         {
00323                 int fh = 0;
00324                 trap_FS_FOpenFile(fileName, &fh, FS_READ);
00325                 if (fh > 0)
00326                 {
00327                         trap_FS_FCloseFile(fh);
00328                         return qtrue;
00329                 }
00330         }
00331 
00332         return qfalse;
00333 }
00334 
00335 #ifndef UI_EXPORTS //don't need this stuff in the ui
00336 
00337 // Following functions don't need to be in namespace, they're already
00338 // different per-module
00339 #include "../namespace_end.h"
00340 
00341 #ifdef QAGAME
00342 char *G_NewString( const char *string );
00343 #else
00344 char *CG_NewString( const char *string );
00345 #endif
00346 
00347 #include "../namespace_begin.h"
00348 
00349 /*
00350 ===============
00351 BG_ParseField
00352 
00353 Takes a key/value pair and sets the binary values
00354 in a gentity/centity/whatever the hell you want
00355 ===============
00356 */
00357 
00358 void BG_ParseField( BG_field_t *l_fields, const char *key, const char *value, byte *ent )
00359 {
00360         BG_field_t      *f;
00361         byte    *b;
00362         float   v;
00363         vec3_t  vec;
00364 
00365         for ( f=l_fields ; f->name ; f++ ) {
00366                 if ( !Q_stricmp(f->name, key) ) {
00367                         // found it
00368                         b = (byte *)ent;
00369 
00370                         switch( f->type ) {
00371                         case F_LSTRING:
00372 #ifdef QAGAME
00373                                 *(char **)(b+f->ofs) = G_NewString (value);
00374 #else
00375                                 *(char **)(b+f->ofs) = CG_NewString (value);
00376 #endif
00377                                 break;
00378                         case F_VECTOR:
00379                                 sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
00380                                 ((float *)(b+f->ofs))[0] = vec[0];
00381                                 ((float *)(b+f->ofs))[1] = vec[1];
00382                                 ((float *)(b+f->ofs))[2] = vec[2];
00383                                 break;
00384                         case F_INT:
00385                                 *(int *)(b+f->ofs) = atoi(value);
00386                                 break;
00387                         case F_FLOAT:
00388                                 *(float *)(b+f->ofs) = atof(value);
00389                                 break;
00390                         case F_ANGLEHACK:
00391                                 v = atof(value);
00392                                 ((float *)(b+f->ofs))[0] = 0;
00393                                 ((float *)(b+f->ofs))[1] = v;
00394                                 ((float *)(b+f->ofs))[2] = 0;
00395                                 break;
00396 #ifdef QAGAME
00397                         case F_PARM1:
00398                         case F_PARM2:
00399                         case F_PARM3:
00400                         case F_PARM4:
00401                         case F_PARM5:
00402                         case F_PARM6:
00403                         case F_PARM7:
00404                         case F_PARM8:
00405                         case F_PARM9:
00406                         case F_PARM10:
00407                         case F_PARM11:
00408                         case F_PARM12:
00409                         case F_PARM13:
00410                         case F_PARM14:
00411                         case F_PARM15:
00412                         case F_PARM16:
00413                                 Q3_SetParm( ((gentity_t *)(ent))->s.number, (f->type - F_PARM1), (char *) value );
00414                                 break;
00415 #endif
00416                         default:
00417                         case F_IGNORE:
00418                                 break;
00419                         }
00420                         return;
00421                 }
00422         }
00423 }
00424 
00425 #endif
00426 
00427 /*
00428 ================
00429 BG_LegalizedForcePowers
00430 
00431 The magical function to end all functions.
00432 This will take the force power string in powerOut and parse through it, then legalize
00433 it based on the supposed rank and spit it into powerOut, returning true if it was legal
00434 to begin with and false if not.
00435 fpDisabled is actually only expected (needed) from the server, because the ui disables
00436 force power selection anyway when force powers are disabled on the server.
00437 ================
00438 */
00439 qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber, int teamForce, int gametype, int fpDisabled)
00440 {
00441         char powerBuf[128];
00442         char readBuf[128];
00443         qboolean maintainsValidity = qtrue;
00444         int powerLen = strlen(powerOut);
00445         int i = 0;
00446         int c = 0;
00447         int allowedPoints = 0;
00448         int usedPoints = 0;
00449         int countDown = 0;
00450         
00451         int final_Side;
00452         int final_Powers[NUM_FORCE_POWERS];
00453 
00454         if (powerLen >= 128)
00455         { //This should not happen. If it does, this is obviously a bogus string.
00456                 //They can have this string. Because I said so.
00457                 strcpy(powerBuf, "7-1-032330000000001333");
00458                 maintainsValidity = qfalse;
00459         }
00460         else
00461         {
00462                 strcpy(powerBuf, powerOut); //copy it as the original
00463         }
00464 
00465         //first of all, print the max rank into the string as the rank
00466         strcpy(powerOut, va("%i-", maxRank));
00467 
00468         while (i < 128 && powerBuf[i] && powerBuf[i] != '-')
00469         {
00470                 i++;
00471         }
00472         i++;
00473         while (i < 128 && powerBuf[i] && powerBuf[i] != '-')
00474         {
00475                 readBuf[c] = powerBuf[i];
00476                 c++;
00477                 i++;
00478         }
00479         readBuf[c] = 0;
00480         i++;
00481         //at this point, readBuf contains the intended side
00482         final_Side = atoi(readBuf);
00483 
00484         if (final_Side != FORCE_LIGHTSIDE &&
00485                 final_Side != FORCE_DARKSIDE)
00486         { //Not a valid side. You will be dark. Because I said so. (this is something that should never actually happen unless you purposely feed in an invalid config)
00487                 final_Side = FORCE_DARKSIDE;
00488                 maintainsValidity = qfalse;
00489         }
00490 
00491         if (teamForce)
00492         { //If we are under force-aligned teams, make sure we're on the right side.
00493                 if (final_Side != teamForce)
00494                 {
00495                         final_Side = teamForce;
00496                         //maintainsValidity = qfalse;
00497                         //Not doing this, for now. Let them join the team with their filtered powers.
00498                 }
00499         }
00500 
00501         //Now we have established a valid rank, and a valid side.
00502         //Read the force powers in, and cut them down based on the various rules supplied.
00503         c = 0;
00504         while (i < 128 && powerBuf[i] && powerBuf[i] != '\n' && c < NUM_FORCE_POWERS)
00505         {
00506                 readBuf[0] = powerBuf[i];
00507                 readBuf[1] = 0;
00508                 final_Powers[c] = atoi(readBuf);
00509                 c++;
00510                 i++;
00511         }
00512 
00513         //final_Powers now contains all the stuff from the string
00514         //Set the maximum allowed points used based on the max rank level, and count the points actually used.
00515         allowedPoints = forceMasteryPoints[maxRank];
00516 
00517         i = 0;
00518         while (i < NUM_FORCE_POWERS)
00519         { //if this power doesn't match the side we're on, then 0 it now.
00520                 if (final_Powers[i] &&
00521                         forcePowerDarkLight[i] &&
00522                         forcePowerDarkLight[i] != final_Side)
00523                 {
00524                         final_Powers[i] = 0;
00525                         //This is only likely to happen with g_forceBasedTeams. Let it slide.
00526                 }
00527 
00528                 if ( final_Powers[i] &&
00529                         (fpDisabled & (1 << i)) )
00530                 { //if this power is disabled on the server via said server option, then we don't get it.
00531                         final_Powers[i] = 0;
00532                 }
00533 
00534                 i++;
00535         }
00536 
00537         if (gametype < GT_TEAM)
00538         { //don't bother with team powers then
00539                 final_Powers[FP_TEAM_HEAL] = 0;
00540                 final_Powers[FP_TEAM_FORCE] = 0;
00541         }
00542 
00543         usedPoints = 0;
00544         i = 0;
00545         while (i < NUM_FORCE_POWERS)
00546         {
00547                 countDown = 0;
00548 
00549                 countDown = final_Powers[i];
00550 
00551                 while (countDown > 0)
00552                 {
00553                         usedPoints += bgForcePowerCost[i][countDown]; //[fp index][fp level]
00554                         //if this is jump, or we have a free saber and it's offense or defense, take the level back down on level 1
00555                         if ( countDown == 1 &&
00556                                 ((i == FP_LEVITATION) ||
00557                                  (i == FP_SABER_OFFENSE && freeSaber) ||
00558                                  (i == FP_SABER_DEFENSE && freeSaber)) )
00559                         {
00560                                 usedPoints -= bgForcePowerCost[i][countDown];
00561                         }
00562                         countDown--;
00563                 }
00564 
00565                 i++;
00566         }
00567 
00568         if (usedPoints > allowedPoints)
00569         { //Time to do the fancy stuff. (meaning, slowly cut parts off while taking a guess at what is most or least important in the config)
00570                 int attemptedCycles = 0;
00571                 int powerCycle = 2;
00572                 int minPow = 0;
00573                 
00574                 if (freeSaber)
00575                 {
00576                         minPow = 1;
00577                 }
00578 
00579                 maintainsValidity = qfalse;
00580 
00581                 while (usedPoints > allowedPoints)
00582                 {
00583                         c = 0;
00584 
00585                         while (c < NUM_FORCE_POWERS && usedPoints > allowedPoints)
00586                         {
00587                                 if (final_Powers[c] && final_Powers[c] < powerCycle)
00588                                 { //kill in order of lowest powers, because the higher powers are probably more important
00589                                         if (c == FP_SABER_OFFENSE &&
00590                                                 (final_Powers[FP_SABER_DEFENSE] > minPow || final_Powers[FP_SABERTHROW] > 0))
00591                                         { //if we're on saber attack, only suck it down if we have no def or throw either
00592                                                 int whichOne = FP_SABERTHROW; //first try throw
00593 
00594                                                 if (!final_Powers[whichOne])
00595                                                 {
00596                                                         whichOne = FP_SABER_DEFENSE; //if no throw, drain defense
00597                                                 }
00598 
00599                                                 while (final_Powers[whichOne] > 0 && usedPoints > allowedPoints)
00600                                                 {
00601                                                         if ( final_Powers[whichOne] > 1 ||
00602                                                                 ( (whichOne != FP_SABER_OFFENSE || !freeSaber) &&
00603                                                                   (whichOne != FP_SABER_DEFENSE || !freeSaber) ) )
00604                                                         { //don't take attack or defend down on level 1 still, if it's free
00605                                                                 usedPoints -= bgForcePowerCost[whichOne][final_Powers[whichOne]];
00606                                                                 final_Powers[whichOne]--;
00607                                                         }
00608                                                         else
00609                                                         {
00610                                                                 break;
00611                                                         }
00612                                                 }
00613                                         }
00614                                         else
00615                                         {
00616                                                 while (final_Powers[c] > 0 && usedPoints > allowedPoints)
00617                                                 {
00618                                                         if ( final_Powers[c] > 1 ||
00619                                                                 ((c != FP_LEVITATION) &&
00620                                                                 (c != FP_SABER_OFFENSE || !freeSaber) &&
00621                                                                 (c != FP_SABER_DEFENSE || !freeSaber)) )
00622                                                         {
00623                                                                 usedPoints -= bgForcePowerCost[c][final_Powers[c]];
00624                                                                 final_Powers[c]--;
00625                                                         }
00626                                                         else
00627                                                         {
00628                                                                 break;
00629                                                         }
00630                                                 }
00631                                         }
00632                                 }
00633 
00634                                 c++;
00635                         }
00636 
00637                         powerCycle++;
00638                         attemptedCycles++;
00639 
00640                         if (attemptedCycles > NUM_FORCE_POWERS)
00641                         { //I think this should be impossible. But just in case.
00642                                 break;
00643                         }
00644                 }
00645 
00646                 if (usedPoints > allowedPoints)
00647                 { //Still? Fine then.. we will kill all of your powers, except the freebies.
00648                         i = 0;
00649 
00650                         while (i < NUM_FORCE_POWERS)
00651                         {
00652                                 final_Powers[i] = 0;
00653                                 if (i == FP_LEVITATION ||
00654                                         (i == FP_SABER_OFFENSE && freeSaber) ||
00655                                         (i == FP_SABER_DEFENSE && freeSaber))
00656                                 {
00657                                         final_Powers[i] = 1;
00658                                 }
00659                                 i++;
00660                         }
00661                         usedPoints = 0;
00662                 }
00663         }
00664 
00665         if (freeSaber)
00666         {
00667                 if (final_Powers[FP_SABER_OFFENSE] < 1)
00668                 {
00669                         final_Powers[FP_SABER_OFFENSE] = 1;
00670                 }
00671                 if (final_Powers[FP_SABER_DEFENSE] < 1)
00672                 {
00673                         final_Powers[FP_SABER_DEFENSE] = 1;
00674                 }
00675         }
00676         if (final_Powers[FP_LEVITATION] < 1)
00677         {
00678                 final_Powers[FP_LEVITATION] = 1;
00679         }
00680 
00681         i = 0;
00682         while (i < NUM_FORCE_POWERS)
00683         {
00684                 if (final_Powers[i] > FORCE_LEVEL_3)
00685                 {
00686                         final_Powers[i] = FORCE_LEVEL_3;
00687                 }
00688                 i++;
00689         }
00690 
00691         if (fpDisabled)
00692         { //If we specifically have attack or def disabled, force them up to level 3. It's the way
00693           //things work for the case of all powers disabled.
00694           //If jump is disabled, down-cap it to level 1. Otherwise don't do a thing.
00695                 if (fpDisabled & (1 << FP_LEVITATION))
00696                 {
00697                         final_Powers[FP_LEVITATION] = 1;
00698                 }
00699                 if (fpDisabled & (1 << FP_SABER_OFFENSE))
00700                 {
00701                         final_Powers[FP_SABER_OFFENSE] = 3;
00702                 }
00703                 if (fpDisabled & (1 << FP_SABER_DEFENSE))
00704                 {
00705                         final_Powers[FP_SABER_DEFENSE] = 3;
00706                 }
00707         }
00708 
00709         if (final_Powers[FP_SABER_OFFENSE] < 1)
00710         {
00711                 final_Powers[FP_SABER_DEFENSE] = 0;
00712                 final_Powers[FP_SABERTHROW] = 0;
00713         }
00714 
00715         //We finally have all the force powers legalized and stored locally.
00716         //Put them all into the string and return the result. We already have
00717         //the rank there, so print the side and the powers now.
00718         Q_strcat(powerOut, 128, va("%i-", final_Side));
00719 
00720         i = strlen(powerOut);
00721         c = 0;
00722         while (c < NUM_FORCE_POWERS)
00723         {
00724                 strcpy(readBuf, va("%i", final_Powers[c]));
00725                 powerOut[i] = readBuf[0];
00726                 c++;
00727                 i++;
00728         }
00729         powerOut[i] = 0;
00730 
00731         return maintainsValidity;
00732 }
00733 
00734 #ifdef __LCC__
00735 // given a boltmatrix, return in vec a normalised vector for the axis requested in flags
00736 void BG_GiveMeVectorFromMatrix(mdxaBone_t *boltMatrix, int flags, vec3_t vec)
00737 {
00738         switch (flags)
00739         {
00740         case ORIGIN:
00741                 vec[0] = boltMatrix->matrix[0][3];
00742                 vec[1] = boltMatrix->matrix[1][3];
00743                 vec[2] = boltMatrix->matrix[2][3];
00744                 break;
00745         case POSITIVE_Y:
00746                 vec[0] = boltMatrix->matrix[0][1];
00747                 vec[1] = boltMatrix->matrix[1][1];
00748                 vec[2] = boltMatrix->matrix[2][1];
00749                 break;
00750         case POSITIVE_X:
00751                 vec[0] = boltMatrix->matrix[0][0];
00752                 vec[1] = boltMatrix->matrix[1][0];
00753                 vec[2] = boltMatrix->matrix[2][0];
00754                 break;
00755         case POSITIVE_Z:
00756                 vec[0] = boltMatrix->matrix[0][2];
00757                 vec[1] = boltMatrix->matrix[1][2];
00758                 vec[2] = boltMatrix->matrix[2][2];
00759                 break;
00760         case NEGATIVE_Y:
00761                 vec[0] = -boltMatrix->matrix[0][1];
00762                 vec[1] = -boltMatrix->matrix[1][1];
00763                 vec[2] = -boltMatrix->matrix[2][1];
00764                 break;
00765         case NEGATIVE_X:
00766                 vec[0] = -boltMatrix->matrix[0][0];
00767                 vec[1] = -boltMatrix->matrix[1][0];
00768                 vec[2] = -boltMatrix->matrix[2][0];
00769                 break;
00770         case NEGATIVE_Z:
00771                 vec[0] = -boltMatrix->matrix[0][2];
00772                 vec[1] = -boltMatrix->matrix[1][2];
00773                 vec[2] = -boltMatrix->matrix[2][2];
00774                 break;
00775         }
00776 }
00777 #endif
00778 
00779 /*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended
00780 DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION.
00781 The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface.
00782 
00783 If an item is the target of another entity, it will not spawn in until fired.
00784 
00785 An item fires all of its targets when it is picked up.  If the toucher can't carry it, the targets won't be fired.
00786 
00787 "notfree" if set to 1, don't spawn in free for all games
00788 "notteam" if set to 1, don't spawn in team games
00789 "notsingle" if set to 1, don't spawn in single player games
00790 "wait"  override the default wait before respawning.  -1 = never respawn automatically, which can be used with targeted spawning.
00791 "random" random number of plus or minus seconds varied from the respawn time
00792 "count" override quantity or duration on most items.
00793 */
00794 
00795 gitem_t bg_itemlist[] = 
00796 {
00797         {
00798                 NULL,                           // classname    
00799                 NULL,                           // pickup_sound
00800                 {       NULL,                   // world_model[0]
00801                         NULL,                   // world_model[1]
00802                         0, 0} ,                 // world_model[2],[3]
00803                 NULL,                           // view_model
00804 /* icon */              NULL,           // icon
00805 /* pickup */    //NULL,         // pickup_name
00806                 0,                                      // quantity
00807                 0,                                      // giType (IT_*)
00808                 0,                                      // giTag
00809 /* precache */ "",                      // precaches
00810 /* sounds */ "",                        // sounds
00811                 ""                                      // description
00812         },      // leave index 0 alone
00813 
00814         //
00815         // Pickups
00816         //
00817 
00818 /*QUAKED item_shield_sm_instant (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
00819 Instant shield pickup, restores 25
00820 */
00821         {
00822                 "item_shield_sm_instant", 
00823                 "sound/player/pickupshield.wav",
00824         { "models/map_objects/mp/psd_sm.md3",
00825                 0, 0, 0},
00826 /* view */              NULL,                   
00827 /* icon */              "gfx/mp/small_shield",
00828 /* pickup *///  "Shield Small",
00829                 25,
00830                 IT_ARMOR,
00831                 1, //special for shield - max on pickup is maxhealth*tag, thus small shield goes up to 100 shield
00832 /* precache */ "",
00833 /* sounds */ ""
00834                 ""                                      // description
00835         },
00836 
00837 /*QUAKED item_shield_lrg_instant (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
00838 Instant shield pickup, restores 100
00839 */
00840         {
00841                 "item_shield_lrg_instant", 
00842                 "sound/player/pickupshield.wav",
00843         { "models/map_objects/mp/psd.md3",
00844                 0, 0, 0},
00845 /* view */              NULL,                   
00846 /* icon */              "gfx/mp/large_shield",
00847 /* pickup *///  "Shield Large",
00848                 100,
00849                 IT_ARMOR,
00850                 2, //special for shield - max on pickup is maxhealth*tag, thus large shield goes up to 200 shield
00851 /* precache */ "",
00852 /* sounds */ "",
00853                 ""                                      // description
00854         },
00855 
00856 /*QUAKED item_medpak_instant (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
00857 Instant medpack pickup, heals 25
00858 */
00859         {
00860                 "item_medpak_instant",
00861                 "sound/player/pickuphealth.wav",
00862         { "models/map_objects/mp/medpac.md3", 
00863                 0, 0, 0 },
00864 /* view */              NULL,                   
00865 /* icon */              "gfx/hud/i_icon_medkit",
00866 /* pickup *///  "Medpack",
00867                 25,
00868                 IT_HEALTH,
00869                 0,
00870 /* precache */ "",
00871 /* sounds */ "",
00872                 ""                                      // description
00873         },
00874 
00875 
00876         //
00877         // ITEMS
00878         //
00879 
00880 /*QUAKED item_seeker (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00881 30 seconds of seeker drone
00882 */
00883         {
00884                 "item_seeker", 
00885                 "sound/weapons/w_pkup.wav",
00886                 { "models/items/remote.md3", 
00887                 0, 0, 0} ,
00888 /* view */              NULL,                   
00889 /* icon */              "gfx/hud/i_icon_seeker",
00890 /* pickup *///  "Seeker Drone",
00891                 120,
00892                 IT_HOLDABLE,
00893                 HI_SEEKER,
00894 /* precache */ "",
00895 /* sounds */ "",
00896                 "@MENUS_AN_ATTACK_DRONE_SIMILAR"                                        // description
00897         },
00898 
00899 /*QUAKED item_shield (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00900 Portable shield
00901 */
00902         {
00903                 "item_shield", 
00904                 "sound/weapons/w_pkup.wav",
00905                 { "models/map_objects/mp/shield.md3", 
00906                 0, 0, 0} ,
00907 /* view */              NULL,                   
00908 /* icon */              "gfx/hud/i_icon_shieldwall",
00909 /* pickup *///  "Forcefield",
00910                 120,
00911                 IT_HOLDABLE,
00912                 HI_SHIELD,
00913 /* precache */ "",
00914 /* sounds */ "sound/weapons/detpack/stick.wav sound/movers/doors/forcefield_on.wav sound/movers/doors/forcefield_off.wav sound/movers/doors/forcefield_lp.wav sound/effects/bumpfield.wav",
00915                 "@MENUS_THIS_STATIONARY_ENERGY"                                 // description
00916         },
00917 
00918 /*QUAKED item_medpac (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00919 Bacta canister pickup, heals 25 on use
00920 */
00921         {
00922                 "item_medpac",  //should be item_bacta
00923                 "sound/weapons/w_pkup.wav",
00924                 { "models/map_objects/mp/bacta.md3", 
00925                 0, 0, 0} ,
00926 /* view */              NULL,                   
00927 /* icon */              "gfx/hud/i_icon_bacta",
00928 /* pickup *///  "Bacta Canister",
00929                 25,
00930                 IT_HOLDABLE,
00931                 HI_MEDPAC,
00932 /* precache */ "",
00933 /* sounds */ "",
00934                 "@SP_INGAME_BACTA_DESC"                                 // description
00935         },
00936 
00937 /*QUAKED item_medpac_big (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00938 Big bacta canister pickup, heals 50 on use
00939 */
00940         {
00941                 "item_medpac_big",      //should be item_bacta
00942                 "sound/weapons/w_pkup.wav",
00943                 { "models/items/big_bacta.md3", 
00944                 0, 0, 0} ,
00945 /* view */              NULL,                   
00946 /* icon */              "gfx/hud/i_icon_big_bacta",
00947 /* pickup *///  "Bacta Canister",
00948                 25,
00949                 IT_HOLDABLE,
00950                 HI_MEDPAC_BIG,
00951 /* precache */ "",
00952 /* sounds */ "",
00953                 "@SP_INGAME_BACTA_DESC"                                 // description
00954         },
00955 
00956 /*QUAKED item_binoculars (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00957 These will be standard equipment on the player - DO NOT PLACE
00958 */
00959         {
00960                 "item_binoculars", 
00961                 "sound/weapons/w_pkup.wav",
00962                 { "models/items/binoculars.md3", 
00963                 0, 0, 0} ,
00964 /* view */              NULL,                   
00965 /* icon */              "gfx/hud/i_icon_zoom",
00966 /* pickup *///  "Binoculars",
00967                 60,
00968                 IT_HOLDABLE,
00969                 HI_BINOCULARS,
00970 /* precache */ "",
00971 /* sounds */ "",
00972                 "@SP_INGAME_LA_GOGGLES_DESC"                                    // description
00973         },
00974 
00975 /*QUAKED item_sentry_gun (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00976 Sentry gun inventory pickup.
00977 */
00978         {
00979                 "item_sentry_gun", 
00980                 "sound/weapons/w_pkup.wav",
00981                 { "models/items/psgun.glm", 
00982                 0, 0, 0} ,
00983 /* view */              NULL,                   
00984 /* icon */              "gfx/hud/i_icon_sentrygun",
00985 /* pickup *///  "Sentry Gun",
00986                 120,
00987                 IT_HOLDABLE,
00988                 HI_SENTRY_GUN,
00989 /* precache */ "",
00990 /* sounds */ "",
00991                 "@MENUS_THIS_DEADLY_WEAPON_IS"                                  // description
00992         },
00993 
00994 /*QUAKED item_jetpack (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
00995 Do not place.
00996 */
00997         {
00998                 "item_jetpack", 
00999                 "sound/weapons/w_pkup.wav",
01000                 { "models/items/psgun.glm", //FIXME: no model
01001                 0, 0, 0} ,
01002 /* view */              NULL,                   
01003 /* icon */              "gfx/hud/i_icon_jetpack",
01004 /* pickup *///  "Sentry Gun",
01005                 120,
01006                 IT_HOLDABLE,
01007                 HI_JETPACK,
01008 /* precache */ "effects/boba/jet.efx",
01009 /* sounds */ "sound/chars/boba/JETON.wav sound/chars/boba/JETHOVER.wav sound/effects/fire_lp.wav",
01010                 "@MENUS_JETPACK_DESC"                                   // description
01011         },
01012 
01013 /*QUAKED item_healthdisp (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
01014 Do not place. For siege classes ONLY.
01015 */
01016         {
01017                 "item_healthdisp", 
01018                 "sound/weapons/w_pkup.wav",
01019                 { "models/map_objects/mp/bacta.md3", //replace me
01020                 0, 0, 0} ,
01021 /* view */              NULL,                   
01022 /* icon */              "gfx/hud/i_icon_healthdisp",
01023 /* pickup *///  "Sentry Gun",
01024                 120,
01025                 IT_HOLDABLE,
01026                 HI_HEALTHDISP,
01027 /* precache */ "",
01028 /* sounds */ "",
01029                 ""                                      // description
01030         },
01031 
01032 /*QUAKED item_ammodisp (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
01033 Do not place. For siege classes ONLY.
01034 */
01035         {
01036                 "item_ammodisp", 
01037                 "sound/weapons/w_pkup.wav",
01038                 { "models/map_objects/mp/bacta.md3", //replace me
01039                 0, 0, 0} ,
01040 /* view */              NULL,                   
01041 /* icon */              "gfx/hud/i_icon_ammodisp",
01042 /* pickup *///  "Sentry Gun",
01043                 120,
01044                 IT_HOLDABLE,
01045                 HI_AMMODISP,
01046 /* precache */ "",
01047 /* sounds */ "",
01048                 ""                                      // description
01049         },
01050 
01051 /*QUAKED item_eweb_holdable (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
01052 Do not place. For siege classes ONLY.
01053 */
01054         {
01055                 "item_eweb_holdable", 
01056                 "sound/interface/shieldcon_empty",
01057                 { "models/map_objects/hoth/eweb_model.glm",
01058                 0, 0, 0} ,
01059 /* view */              NULL,                   
01060 /* icon */              "gfx/hud/i_icon_eweb",
01061 /* pickup *///  "Sentry Gun",
01062                 120,
01063                 IT_HOLDABLE,
01064                 HI_EWEB,
01065 /* precache */ "",
01066 /* sounds */ "",
01067                 "@MENUS_EWEB_DESC"                                      // description
01068         },
01069 
01070 /*QUAKED item_seeker (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
01071 30 seconds of seeker drone
01072 */
01073         {
01074                 "item_cloak", 
01075                 "sound/weapons/w_pkup.wav",
01076                 { "models/items/psgun.glm", //FIXME: no model
01077                 0, 0, 0} ,
01078 /* view */              NULL,                   
01079 /* icon */              "gfx/hud/i_icon_cloak",
01080 /* pickup *///  "Seeker Drone",
01081                 120,
01082                 IT_HOLDABLE,
01083                 HI_CLOAK,
01084 /* precache */ "",
01085 /* sounds */ "",
01086                 "@MENUS_CLOAK_DESC"                                     // description
01087         },
01088 
01089 /*QUAKED item_force_enlighten_light (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01090 Adds one rank to all Force powers temporarily. Only light jedi can use.
01091 */
01092         {
01093                 "item_force_enlighten_light",
01094                 "sound/player/enlightenment.wav",
01095                 { "models/map_objects/mp/jedi_enlightenment.md3", 
01096                 0, 0, 0} ,
01097 /* view */              NULL,                   
01098 /* icon */              "gfx/hud/mpi_jlight",
01099 /* pickup *///  "Light Force Enlightenment",
01100                 25,
01101                 IT_POWERUP,
01102                 PW_FORCE_ENLIGHTENED_LIGHT,
01103 /* precache */ "",
01104 /* sounds */ "",
01105                 ""                                      // description
01106         },
01107 
01108 /*QUAKED item_force_enlighten_dark (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01109 Adds one rank to all Force powers temporarily. Only dark jedi can use.
01110 */
01111         {
01112                 "item_force_enlighten_dark",
01113                 "sound/player/enlightenment.wav",
01114                 { "models/map_objects/mp/dk_enlightenment.md3", 
01115                 0, 0, 0} ,
01116 /* view */              NULL,                   
01117 /* icon */              "gfx/hud/mpi_dklight",
01118 /* pickup *///  "Dark Force Enlightenment",
01119                 25,
01120                 IT_POWERUP,
01121                 PW_FORCE_ENLIGHTENED_DARK,
01122 /* precache */ "",
01123 /* sounds */ "",
01124                 ""                                      // description
01125         },
01126 
01127 /*QUAKED item_force_boon (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01128 Unlimited Force Pool for a short time.
01129 */
01130         {
01131                 "item_force_boon",
01132                 "sound/player/boon.wav",
01133                 { "models/map_objects/mp/force_boon.md3", 
01134                 0, 0, 0} ,
01135 /* view */              NULL,                   
01136 /* icon */              "gfx/hud/mpi_fboon",
01137 /* pickup *///  "Force Boon",
01138                 25,
01139                 IT_POWERUP,
01140                 PW_FORCE_BOON,
01141 /* precache */ "",
01142 /* sounds */ "",
01143                 ""                                      // description
01144         },
01145 
01146 /*QUAKED item_ysalimari (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01147 A small lizard carried on the player, which prevents the possessor from using any Force power.  However, he is unaffected by any Force power.
01148 */
01149         {
01150                 "item_ysalimari",
01151                 "sound/player/ysalimari.wav",
01152                 { "models/map_objects/mp/ysalimari.md3", 
01153                 0, 0, 0} ,
01154 /* view */              NULL,                   
01155 /* icon */              "gfx/hud/mpi_ysamari",
01156 /* pickup *///  "Ysalamiri",
01157                 25,
01158                 IT_POWERUP,
01159                 PW_YSALAMIRI,
01160 /* precache */ "",
01161 /* sounds */ "",
01162                 ""                                      // description
01163         },
01164 
01165         //
01166         // WEAPONS 
01167         //
01168 
01169 /*QUAKED weapon_stun_baton (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01170 Don't place this
01171 */
01172         {
01173                 "weapon_stun_baton", 
01174                 "sound/weapons/w_pkup.wav",
01175         { "models/weapons2/stun_baton/baton_w.glm", 
01176                 0, 0, 0},
01177 /* view */              "models/weapons2/stun_baton/baton.md3", 
01178 /* icon */              "gfx/hud/w_icon_stunbaton",
01179 /* pickup *///  "Stun Baton",
01180                 100,
01181                 IT_WEAPON,
01182                 WP_STUN_BATON,
01183 /* precache */ "",
01184 /* sounds */ "",
01185                 ""                                      // description
01186         },
01187 
01188 /*QUAKED weapon_melee (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01189 Don't place this
01190 */
01191         {
01192                 "weapon_melee", 
01193                 "sound/weapons/w_pkup.wav",
01194         { "models/weapons2/stun_baton/baton_w.glm", 
01195                 0, 0, 0},
01196 /* view */              "models/weapons2/stun_baton/baton.md3", 
01197 /* icon */              "gfx/hud/w_icon_melee",
01198 /* pickup *///  "Stun Baton",
01199                 100,
01200                 IT_WEAPON,
01201                 WP_MELEE,
01202 /* precache */ "",
01203 /* sounds */ "",
01204                 "@MENUS_MELEE_DESC"                                     // description
01205         },
01206 
01207 /*QUAKED weapon_saber (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01208 Don't place this
01209 */
01210         {
01211                 "weapon_saber", 
01212                 "sound/weapons/w_pkup.wav",
01213         { "models/weapons2/saber/saber_w.glm",
01214                 0, 0, 0},
01215 /* view */              "models/weapons2/saber/saber_w.md3",
01216 /* icon */              "gfx/hud/w_icon_lightsaber",
01217 /* pickup *///  "Lightsaber",
01218                 100,
01219                 IT_WEAPON,
01220                 WP_SABER,
01221 /* precache */ "",
01222 /* sounds */ "",
01223                 "@MENUS_AN_ELEGANT_WEAPON_FOR"                          // description
01224         },
01225 
01226 /*QUAKED weapon_bryar_pistol (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01227 Don't place this
01228 */
01229         {
01230                 //"weapon_bryar_pistol", 
01231                 "weapon_blaster_pistol", 
01232                 "sound/weapons/w_pkup.wav",
01233         { "models/weapons2/blaster_pistol/blaster_pistol_w.glm",//"models/weapons2/briar_pistol/briar_pistol_w.glm", 
01234                 0, 0, 0},
01235 /* view */              "models/weapons2/blaster_pistol/blaster_pistol.md3",//"models/weapons2/briar_pistol/briar_pistol.md3", 
01236 /* icon */              "gfx/hud/w_icon_blaster_pistol",//"gfx/hud/w_icon_rifle",
01237 /* pickup *///  "Bryar Pistol",
01238                 100,
01239                 IT_WEAPON,
01240                 WP_BRYAR_PISTOL,
01241 /* precache */ "",
01242 /* sounds */ "",
01243                 "@MENUS_BLASTER_PISTOL_DESC"                                    // description
01244         },
01245 
01246 /*QUAKED weapon_concussion_rifle (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01247 */
01248         {
01249                 "weapon_concussion_rifle", 
01250                 "sound/weapons/w_pkup.wav",
01251         { "models/weapons2/concussion/c_rifle_w.glm", 
01252                 0, 0, 0},
01253 /* view */              "models/weapons2/concussion/c_rifle.md3", 
01254 /* icon */              "gfx/hud/w_icon_c_rifle",//"gfx/hud/w_icon_rifle",
01255 /* pickup *///  "Concussion Rifle",
01256                 50,
01257                 IT_WEAPON,
01258                 WP_CONCUSSION,
01259 /* precache */ "",
01260 /* sounds */ "",
01261                 "@MENUS_CONC_RIFLE_DESC"                                        // description
01262         },
01263 
01264 /*QUAKED weapon_bryar_pistol_old (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01265 Don't place this
01266 */
01267         {
01268                 "weapon_bryar_pistol", 
01269                 "sound/weapons/w_pkup.wav",
01270         { "models/weapons2/briar_pistol/briar_pistol_w.glm", 
01271                 0, 0, 0},
01272 /* view */              "models/weapons2/briar_pistol/briar_pistol.md3", 
01273 /* icon */              "gfx/hud/w_icon_briar",//"gfx/hud/w_icon_rifle",
01274 /* pickup *///  "Bryar Pistol",
01275                 100,
01276                 IT_WEAPON,
01277                 WP_BRYAR_OLD,
01278 /* precache */ "",
01279 /* sounds */ "",
01280                 "@SP_INGAME_BLASTER_PISTOL"                                     // description
01281         },
01282 
01283 /*QUAKED weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01284 */
01285         {
01286                 "weapon_blaster", 
01287                 "sound/weapons/w_pkup.wav",
01288         { "models/weapons2/blaster_r/blaster_w.glm", 
01289                 0, 0, 0},
01290 /* view */              "models/weapons2/blaster_r/blaster.md3", 
01291 /* icon */              "gfx/hud/w_icon_blaster",
01292 /* pickup *///  "E11 Blaster Rifle",
01293                 100,
01294                 IT_WEAPON,
01295                 WP_BLASTER,
01296 /* precache */ "",
01297 /* sounds */ "",
01298                 "@MENUS_THE_PRIMARY_WEAPON_OF"                          // description
01299         },
01300 
01301 /*QUAKED weapon_disruptor (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01302 */
01303         {
01304                 "weapon_disruptor",
01305                 "sound/weapons/w_pkup.wav",
01306         { "models/weapons2/disruptor/disruptor_w.glm", 
01307                 0, 0, 0},
01308 /* view */              "models/weapons2/disruptor/disruptor.md3", 
01309 /* icon */              "gfx/hud/w_icon_disruptor",
01310 /* pickup *///  "Tenloss Disruptor Rifle",
01311                 100,
01312                 IT_WEAPON,
01313                 WP_DISRUPTOR,
01314 /* precache */ "",
01315 /* sounds */ "",
01316                 "@MENUS_THIS_NEFARIOUS_WEAPON"                                  // description
01317         },
01318 
01319 /*QUAKED weapon_bowcaster (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01320 */
01321         {
01322                 "weapon_bowcaster",
01323                 "sound/weapons/w_pkup.wav",
01324         { "models/weapons2/bowcaster/bowcaster_w.glm", 
01325                 0, 0, 0},
01326 /* view */              "models/weapons2/bowcaster/bowcaster.md3", 
01327 /* icon */              "gfx/hud/w_icon_bowcaster",
01328 /* pickup *///  "Wookiee Bowcaster",
01329                 100,
01330                 IT_WEAPON,
01331                 WP_BOWCASTER,
01332 /* precache */ "",
01333 /* sounds */ "",
01334                 "@MENUS_THIS_ARCHAIC_LOOKING"                                   // description
01335         },
01336 
01337 /*QUAKED weapon_repeater (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01338 */
01339         {
01340                 "weapon_repeater", 
01341                 "sound/weapons/w_pkup.wav",
01342         { "models/weapons2/heavy_repeater/heavy_repeater_w.glm", 
01343                 0, 0, 0},
01344 /* view */              "models/weapons2/heavy_repeater/heavy_repeater.md3", 
01345 /* icon */              "gfx/hud/w_icon_repeater",
01346 /* pickup *///  "Imperial Heavy Repeater",
01347                 100,
01348                 IT_WEAPON,
01349                 WP_REPEATER,
01350 /* precache */ "",
01351 /* sounds */ "",
01352                 "@MENUS_THIS_DESTRUCTIVE_PROJECTILE"                                    // description
01353         },
01354 
01355 /*QUAKED weapon_demp2 (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01356 NOTENOTE This weapon is not yet complete.  Don't place it.
01357 */
01358         {
01359                 "weapon_demp2", 
01360                 "sound/weapons/w_pkup.wav",
01361         { "models/weapons2/demp2/demp2_w.glm", 
01362                 0, 0, 0},
01363 /* view */              "models/weapons2/demp2/demp2.md3", 
01364 /* icon */              "gfx/hud/w_icon_demp2",
01365 /* pickup *///  "DEMP2",
01366                 100,
01367                 IT_WEAPON,
01368                 WP_DEMP2,
01369 /* precache */ "",
01370 /* sounds */ "",
01371                 "@MENUS_COMMONLY_REFERRED_TO"                                   // description
01372         },
01373 
01374 /*QUAKED weapon_flechette (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01375 */
01376         {
01377                 "weapon_flechette", 
01378                 "sound/weapons/w_pkup.wav",
01379         { "models/weapons2/golan_arms/golan_arms_w.glm", 
01380                 0, 0, 0},
01381 /* view */              "models/weapons2/golan_arms/golan_arms.md3", 
01382 /* icon */              "gfx/hud/w_icon_flechette",
01383 /* pickup *///  "Golan Arms Flechette",
01384                 100,
01385                 IT_WEAPON,
01386                 WP_FLECHETTE,
01387 /* precache */ "",
01388 /* sounds */ "",
01389                 "@MENUS_WIDELY_USED_BY_THE_CORPORATE"                                   // description
01390         },
01391 
01392 /*QUAKED weapon_rocket_launcher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01393 */
01394         {
01395                 "weapon_rocket_launcher",
01396                 "sound/weapons/w_pkup.wav",
01397         { "models/weapons2/merr_sonn/merr_sonn_w.glm", 
01398                 0, 0, 0},
01399 /* view */              "models/weapons2/merr_sonn/merr_sonn.md3", 
01400 /* icon */              "gfx/hud/w_icon_merrsonn",
01401 /* pickup *///  "Merr-Sonn Missile System",
01402                 3,
01403                 IT_WEAPON,
01404                 WP_ROCKET_LAUNCHER,
01405 /* precache */ "",
01406 /* sounds */ "",
01407                 "@MENUS_THE_PLX_2M_IS_AN_EXTREMELY"                                     // description
01408         },
01409 
01410 /*QUAKED ammo_thermal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01411 */
01412         {
01413                 "ammo_thermal",
01414                 "sound/weapons/w_pkup.wav",
01415         { "models/weapons2/thermal/thermal_pu.md3", 
01416                 "models/weapons2/thermal/thermal_w.glm", 0, 0},
01417 /* view */              "models/weapons2/thermal/thermal.md3", 
01418 /* icon */              "gfx/hud/w_icon_thermal",
01419 /* pickup *///  "Thermal Detonators",
01420                 4,
01421                 IT_AMMO,
01422                 AMMO_THERMAL,
01423 /* precache */ "",
01424 /* sounds */ "",
01425                 "@MENUS_THE_THERMAL_DETONATOR"                                  // description
01426         },
01427 
01428 /*QUAKED ammo_tripmine (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01429 */
01430         {
01431                 "ammo_tripmine", 
01432                 "sound/weapons/w_pkup.wav",
01433         { "models/weapons2/laser_trap/laser_trap_pu.md3", 
01434                 "models/weapons2/laser_trap/laser_trap_w.glm", 0, 0},
01435 /* view */              "models/weapons2/laser_trap/laser_trap.md3", 
01436 /* icon */              "gfx/hud/w_icon_tripmine",
01437 /* pickup *///  "Trip Mines",
01438                 3,
01439                 IT_AMMO,
01440                 AMMO_TRIPMINE,
01441 /* precache */ "",
01442 /* sounds */ "",
01443                 "@MENUS_TRIP_MINES_CONSIST_OF"                                  // description
01444         },
01445 
01446 /*QUAKED ammo_detpack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01447 */
01448         {
01449                 "ammo_detpack", 
01450                 "sound/weapons/w_pkup.wav",
01451         { "models/weapons2/detpack/det_pack_pu.md3", "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_w.glm", 0},
01452 /* view */              "models/weapons2/detpack/det_pack.md3", 
01453 /* icon */              "gfx/hud/w_icon_detpack",
01454 /* pickup *///  "Det Packs",
01455                 3,
01456                 IT_AMMO,
01457                 AMMO_DETPACK,
01458 /* precache */ "",
01459 /* sounds */ "",
01460                 "@MENUS_A_DETONATION_PACK_IS"                                   // description
01461         },
01462 
01463 /*QUAKED weapon_thermal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01464 */
01465         {
01466                 "weapon_thermal",
01467                 "sound/weapons/w_pkup.wav",
01468         { "models/weapons2/thermal/thermal_w.glm", "models/weapons2/thermal/thermal_pu.md3",
01469                 0, 0 },
01470 /* view */              "models/weapons2/thermal/thermal.md3", 
01471 /* icon */              "gfx/hud/w_icon_thermal",
01472 /* pickup *///  "Thermal Detonator",
01473                 4,
01474                 IT_WEAPON,
01475                 WP_THERMAL,
01476 /* precache */ "",
01477 /* sounds */ "",
01478                 "@MENUS_THE_THERMAL_DETONATOR"                                  // description
01479         },
01480 
01481 /*QUAKED weapon_trip_mine (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01482 */
01483         {
01484                 "weapon_trip_mine", 
01485                 "sound/weapons/w_pkup.wav",
01486         { "models/weapons2/laser_trap/laser_trap_w.glm", "models/weapons2/laser_trap/laser_trap_pu.md3",
01487                 0, 0},
01488 /* view */              "models/weapons2/laser_trap/laser_trap.md3", 
01489 /* icon */              "gfx/hud/w_icon_tripmine",
01490 /* pickup *///  "Trip Mine",
01491                 3,
01492                 IT_WEAPON,
01493                 WP_TRIP_MINE,
01494 /* precache */ "",
01495 /* sounds */ "",
01496                 "@MENUS_TRIP_MINES_CONSIST_OF"                                  // description
01497         },
01498 
01499 /*QUAKED weapon_det_pack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01500 */
01501         {
01502                 "weapon_det_pack", 
01503                 "sound/weapons/w_pkup.wav",
01504         { "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_pu.md3", "models/weapons2/detpack/det_pack_w.glm", 0},
01505 /* view */              "models/weapons2/detpack/det_pack.md3", 
01506 /* icon */              "gfx/hud/w_icon_detpack",
01507 /* pickup *///  "Det Pack",
01508                 3,
01509                 IT_WEAPON,
01510                 WP_DET_PACK,
01511 /* precache */ "",
01512 /* sounds */ "",
01513                 "@MENUS_A_DETONATION_PACK_IS"                                   // description
01514         },
01515 
01516 /*QUAKED weapon_emplaced (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01517 */
01518         {
01519                 "weapon_emplaced", 
01520                 "sound/weapons/w_pkup.wav",
01521         { "models/weapons2/blaster_r/blaster_w.glm", 
01522                 0, 0, 0},
01523 /* view */              "models/weapons2/blaster_r/blaster.md3", 
01524 /* icon */              "gfx/hud/w_icon_blaster",
01525 /* pickup *///  "Emplaced Gun",
01526                 50,
01527                 IT_WEAPON,
01528                 WP_EMPLACED_GUN,
01529 /* precache */ "",
01530 /* sounds */ "",
01531                 ""                                      // description
01532         },
01533 
01534 
01535 //NOTE: This is to keep things from messing up because the turret weapon type isn't real
01536         {
01537                 "weapon_turretwp", 
01538                 "sound/weapons/w_pkup.wav",
01539         { "models/weapons2/blaster_r/blaster_w.glm", 
01540                 0, 0, 0},
01541 /* view */              "models/weapons2/blaster_r/blaster.md3", 
01542 /* icon */              "gfx/hud/w_icon_blaster",
01543 /* pickup *///  "Turret Gun",
01544                 50,
01545                 IT_WEAPON,
01546                 WP_TURRET,
01547 /* precache */ "",
01548 /* sounds */ "",
01549                 ""                                      // description
01550         },
01551 
01552         //
01553         // AMMO ITEMS
01554         //
01555 
01556 /*QUAKED ammo_force (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01557 Don't place this
01558 */
01559         {
01560                 "ammo_force",
01561                 "sound/player/pickupenergy.wav",
01562         { "models/items/energy_cell.md3", 
01563                 0, 0, 0},
01564 /* view */              NULL,                   
01565 /* icon */              "gfx/hud/w_icon_blaster",
01566 /* pickup *///  "Force??",
01567                 100,
01568                 IT_AMMO,
01569                 AMMO_FORCE,
01570 /* precache */ "",
01571 /* sounds */ "",
01572                 ""                                      // description
01573         },
01574 
01575 /*QUAKED ammo_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01576 Ammo for the Bryar and Blaster pistols.
01577 */
01578         {
01579                 "ammo_blaster",
01580                 "sound/player/pickupenergy.wav",
01581         { "models/items/energy_cell.md3", 
01582                 0, 0, 0},
01583 /* view */              NULL,                   
01584 /* icon */              "gfx/hud/i_icon_battery",
01585 /* pickup *///  "Blaster Pack",
01586                 100,
01587                 IT_AMMO,
01588                 AMMO_BLASTER,
01589 /* precache */ "",
01590 /* sounds */ "",
01591                 ""                                      // description
01592         },
01593 
01594 /*QUAKED ammo_powercell (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01595 Ammo for Tenloss Disruptor, Wookie Bowcaster, and the Destructive Electro Magnetic Pulse (demp2 ) guns
01596 */
01597         {
01598                 "ammo_powercell",
01599                 "sound/player/pickupenergy.wav",
01600         { "models/items/power_cell.md3", 
01601                 0, 0, 0},
01602 /* view */              NULL,                   
01603 /* icon */              "gfx/mp/ammo_power_cell",
01604 /* pickup *///  "Power Cell",
01605                 100,
01606                 IT_AMMO,
01607                 AMMO_POWERCELL,
01608 /* precache */ "",
01609 /* sounds */ "",
01610                 ""                                      // description
01611         },
01612 
01613 /*QUAKED ammo_metallic_bolts (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01614 Ammo for Imperial Heavy Repeater and the Golan Arms Flechette
01615 */
01616         {
01617                 "ammo_metallic_bolts",
01618                 "sound/player/pickupenergy.wav",
01619         { "models/items/metallic_bolts.md3", 
01620                 0, 0, 0},
01621 /* view */              NULL,                   
01622 /* icon */              "gfx/mp/ammo_metallic_bolts",
01623 /* pickup *///  "Metallic Bolts",
01624                 100,
01625                 IT_AMMO,
01626                 AMMO_METAL_BOLTS,
01627 /* precache */ "",
01628 /* sounds */ "",
01629                 ""                                      // description
01630         },
01631 
01632 /*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01633 Ammo for Merr-Sonn portable missile launcher
01634 */
01635         {
01636                 "ammo_rockets",
01637                 "sound/player/pickupenergy.wav",
01638         { "models/items/rockets.md3", 
01639                 0, 0, 0},
01640 /* view */              NULL,                   
01641 /* icon */              "gfx/mp/ammo_rockets",
01642 /* pickup *///  "Rockets",
01643                 3,
01644                 IT_AMMO,
01645                 AMMO_ROCKETS,
01646 /* precache */ "",
01647 /* sounds */ "",
01648                 ""                                      // description
01649         },
01650 
01651 /*QUAKED ammo_all (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
01652 DO NOT PLACE in a map, this is only for siege classes that have ammo
01653 dispensing ability
01654 */
01655         {
01656                 "ammo_all",
01657                 "sound/player/pickupenergy.wav",
01658         { "models/items/battery.md3",  //replace me
01659                 0, 0, 0},
01660 /* view */              NULL,                   
01661 /* icon */              "gfx/mp/ammo_rockets", //replace me
01662 /* pickup *///  "Rockets",
01663                 0,
01664                 IT_AMMO,
01665                 -1,
01666 /* precache */ "",
01667 /* sounds */ "",
01668                 ""                                      // description
01669         },
01670 
01671         //
01672         // POWERUP ITEMS
01673         //
01674 /*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16)
01675 Only in CTF games
01676 */
01677         {
01678                 "team_CTF_redflag",
01679                 NULL,
01680         { "models/flags/r_flag.md3",
01681                 "models/flags/r_flag_ysal.md3", 0, 0 },
01682 /* view */              NULL,                   
01683 /* icon */              "gfx/hud/mpi_rflag",
01684 /* pickup *///  "Red Flag",
01685                 0,
01686                 IT_TEAM,
01687                 PW_REDFLAG,
01688 /* precache */ "",
01689 /* sounds */ "",
01690                 ""                                      // description
01691         },
01692 
01693 /*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16)
01694 Only in CTF games
01695 */
01696         {
01697                 "team_CTF_blueflag",
01698                 NULL,
01699         { "models/flags/b_flag.md3",
01700                 "models/flags/b_flag_ysal.md3", 0, 0 },
01701 /* view */              NULL,                   
01702 /* icon */              "gfx/hud/mpi_bflag",
01703 /* pickup *///  "Blue Flag",
01704                 0,
01705                 IT_TEAM,
01706                 PW_BLUEFLAG,
01707 /* precache */ "",
01708 /* sounds */ "",
01709                 ""                                      // description
01710         },
01711 
01712         //
01713         // PERSISTANT POWERUP ITEMS
01714         //
01715 
01716         /*QUAKED team_CTF_neutralflag (0 0 1) (-16 -16 -16) (16 16 16)
01717 Only in One Flag CTF games
01718 */
01719         {
01720                 "team_CTF_neutralflag",
01721                 NULL,
01722         { "models/flags/n_flag.md3",
01723                 0, 0, 0 },
01724 /* view */              NULL,                   
01725 /* icon */              "icons/iconf_neutral1",
01726 /* pickup *///  "Neutral Flag",
01727                 0,
01728                 IT_TEAM,
01729                 PW_NEUTRALFLAG,
01730 /* precache */ "",
01731 /* sounds */ "",
01732                 ""                                      // description
01733         },
01734 
01735         {
01736                 "item_redcube",
01737                 "sound/player/pickupenergy.wav",
01738         { "models/powerups/orb/r_orb.md3",
01739                 0, 0, 0 },
01740 /* view */              NULL,                   
01741 /* icon */              "icons/iconh_rorb",
01742 /* pickup *///  "Red Cube",
01743                 0,
01744                 IT_TEAM,
01745                 0,
01746 /* precache */ "",
01747 /* sounds */ "",
01748                 ""                                      // description
01749         },
01750 
01751         {
01752                 "item_bluecube",
01753                 "sound/player/pickupenergy.wav",
01754         { "models/powerups/orb/b_orb.md3",
01755                 0, 0, 0 },
01756 /* view */              NULL,                   
01757 /* icon */              "icons/iconh_borb",
01758 /* pickup *///  "Blue Cube",
01759                 0,
01760                 IT_TEAM,
01761                 0,
01762 /* precache */ "",
01763 /* sounds */ "",
01764                 ""                                      // description
01765         },
01766 
01767         // end of list marker
01768         {NULL}
01769 };
01770 
01771 int             bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1;
01772 
01773 float vectoyaw( const vec3_t vec ) {
01774         float   yaw;
01775         
01776         if (vec[YAW] == 0 && vec[PITCH] == 0) {
01777                 yaw = 0;
01778         } else {
01779                 if (vec[PITCH]) {
01780                         yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI );
01781                 } else if (vec[YAW] > 0) {
01782                         yaw = 90;
01783                 } else {
01784                         yaw = 270;
01785                 }
01786                 if (yaw < 0) {
01787                         yaw += 360;
01788                 }
01789         }
01790 
01791         return yaw;
01792 }
01793 
01794 qboolean BG_HasYsalamiri(int gametype, playerState_t *ps)
01795 {
01796         if (gametype == GT_CTY &&
01797                 (ps->powerups[PW_REDFLAG] || ps->powerups[PW_BLUEFLAG]))
01798         {
01799                 return qtrue;
01800         }
01801 
01802         if (ps->powerups[PW_YSALAMIRI])
01803         {
01804                 return qtrue;
01805         }
01806 
01807         return qfalse;
01808 }
01809 
01810 qboolean BG_CanUseFPNow(int gametype, playerState_t *ps, int time, forcePowers_t power)
01811 {
01812         if (BG_HasYsalamiri(gametype, ps))
01813         {
01814                 return qfalse;
01815         }
01816 
01817         if ( ps->forceRestricted || ps->trueNonJedi )
01818         {
01819                 return qfalse;
01820         }
01821 
01822         if (ps->weapon == WP_EMPLACED_GUN)
01823         { //can't use any of your powers while on an emplaced weapon
01824                 return qfalse;
01825         }
01826 
01827         if (ps->m_iVehicleNum)
01828         { //can't use powers while riding a vehicle (this may change, I don't know)
01829                 return qfalse;
01830         }
01831 
01832         if (ps->duelInProgress)
01833         {
01834                 if (power != FP_SABER_OFFENSE && power != FP_SABER_DEFENSE && /*power != FP_SABERTHROW &&*/
01835                         power != FP_LEVITATION)
01836                 {
01837                         if (!ps->saberLockFrame || power != FP_PUSH)
01838                         {
01839                                 return qfalse;
01840                         }
01841                 }
01842         }
01843 
01844         if (ps->saberLockFrame || ps->saberLockTime > time)
01845         {
01846                 if (power != FP_PUSH)
01847                 {
01848                         return qfalse;
01849                 }
01850         }
01851 
01852         if (ps->fallingToDeath)
01853         {
01854                 return qfalse;
01855         }
01856 
01857         if ((ps->brokenLimbs & (1 << BROKENLIMB_RARM)) ||
01858                 (ps->brokenLimbs & (1 << BROKENLIMB_LARM)))
01859         { //powers we can't use with a broken arm
01860         switch (power)
01861                 {
01862                 case FP_PUSH:
01863                 case FP_PULL:
01864                 case FP_GRIP:
01865                 case FP_LIGHTNING:
01866                 case FP_DRAIN:
01867                         return qfalse;
01868                 default:
01869                         break;
01870                 }
01871         }
01872 
01873         return qtrue;
01874 }
01875 
01876 /*
01877 ==============
01878 BG_FindItemForPowerup
01879 ==============
01880 */
01881 gitem_t *BG_FindItemForPowerup( powerup_t pw ) {
01882         int             i;
01883 
01884         for ( i = 0 ; i < bg_numItems ; i++ ) {
01885                 if ( (bg_itemlist[i].giType == IT_POWERUP || 
01886                                         bg_itemlist[i].giType == IT_TEAM) && 
01887                         bg_itemlist[i].giTag == pw ) {
01888                         return &bg_itemlist[i];
01889                 }
01890         }
01891 
01892         return NULL;
01893 }
01894 
01895 
01896 /*
01897 ==============
01898 BG_FindItemForHoldable
01899 ==============
01900 */
01901 gitem_t *BG_FindItemForHoldable( holdable_t pw ) {
01902         int             i;
01903 
01904         for ( i = 0 ; i < bg_numItems ; i++ ) {
01905                 if ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) {
01906                         return &bg_itemlist[i];
01907                 }
01908         }
01909 
01910         Com_Error( ERR_DROP, "HoldableItem not found" );
01911 
01912         return NULL;
01913 }
01914 
01915 
01916 /*
01917 ===============
01918 BG_FindItemForWeapon
01919 
01920 ===============
01921 */
01922 gitem_t *BG_FindItemForWeapon( weapon_t weapon ) {
01923         gitem_t *it;
01924         
01925         for ( it = bg_itemlist + 1 ; it->classname ; it++) {
01926                 if ( it->giType == IT_WEAPON && it->giTag == weapon ) {
01927                         return it;
01928                 }
01929         }
01930 
01931         Com_Error( ERR_DROP, "Couldn't find item for weapon %i", weapon);
01932         return NULL;
01933 }
01934 
01935 /*
01936 ===============
01937 BG_FindItemForAmmo
01938 
01939 ===============
01940 */
01941 gitem_t *BG_FindItemForAmmo( ammo_t ammo ) {
01942         gitem_t *it;
01943         
01944         for ( it = bg_itemlist + 1 ; it->classname ; it++) {
01945                 if ( it->giType == IT_AMMO && it->giTag == ammo ) {
01946                         return it;
01947                 }
01948         }
01949 
01950         Com_Error( ERR_DROP, "Couldn't find item for ammo %i", ammo);
01951         return NULL;
01952 }
01953 
01954 /*
01955 ===============
01956 BG_FindItem
01957 
01958 ===============
01959 */
01960 gitem_t *BG_FindItem( const char *classname ) {
01961         gitem_t *it;
01962         
01963         for ( it = bg_itemlist + 1 ; it->classname ; it++ ) {
01964                 if ( !Q_stricmp( it->classname, classname) )
01965                         return it;
01966         }
01967 
01968         return NULL;
01969 }
01970 
01971 /*
01972 ============
01973 BG_PlayerTouchesItem
01974 
01975 Items can be picked up without actually touching their physical bounds to make
01976 grabbing them easier
01977 ============
01978 */
01979 qboolean        BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) {
01980         vec3_t          origin;
01981 
01982         BG_EvaluateTrajectory( &item->pos, atTime, origin );
01983 
01984         // we are ignoring ducked differences here
01985         if ( ps->origin[0] - origin[0] > 44
01986                 || ps->origin[0] - origin[0] < -50
01987                 || ps->origin[1] - origin[1] > 36
01988                 || ps->origin[1] - origin[1] < -36
01989                 || ps->origin[2] - origin[2] > 36
01990                 || ps->origin[2] - origin[2] < -36 ) {
01991                 return qfalse;
01992         }
01993 
01994         return qtrue;
01995 }
01996 
01997 int BG_ProperForceIndex(int power)
01998 {
01999         int i = 0;
02000 
02001         while (i < NUM_FORCE_POWERS)
02002         {
02003                 if (forcePowerSorted[i] == power)
02004                 {
02005                         return i;
02006                 }
02007 
02008                 i++;
02009         }
02010 
02011         return -1;
02012 }
02013 
02014 void BG_CycleForce(playerState_t *ps, int direction)
02015 {
02016         int i = ps->fd.forcePowerSelected;
02017         int x = i;
02018         int presel = i;
02019         int foundnext = -1;
02020 
02021         if (!ps->fd.forcePowersKnown & (1 << x) ||
02022                 x >= NUM_FORCE_POWERS ||
02023                 x == -1)
02024         { //apparently we have no valid force powers
02025                 return;
02026         }
02027 
02028         x = BG_ProperForceIndex(x);
02029         presel = x;
02030 
02031         if (direction == 1)
02032         { //get the next power
02033                 x++;
02034         }
02035         else
02036         { //get the previous power
02037                 x--;
02038         }
02039 
02040         if (x >= NUM_FORCE_POWERS)
02041         { //cycled off the end.. cycle around to the first
02042                 x = 0;
02043         }
02044         if (x < 0)
02045         { //cycled off the beginning.. cycle around to the last
02046                 x = NUM_FORCE_POWERS-1;
02047         }
02048 
02049         i = forcePowerSorted[x]; //the "sorted" value of this power
02050 
02051         while (x != presel)
02052         { //loop around to the current force power
02053                 if (ps->fd.forcePowersKnown & (1 << i) && i != ps->fd.forcePowerSelected)
02054                 { //we have the force power
02055                         if (i != FP_LEVITATION &&
02056                                 i != FP_SABER_OFFENSE &&
02057                                 i != FP_SABER_DEFENSE &&
02058                                 i != FP_SABERTHROW)
02059                         { //it's selectable
02060                                 foundnext = i;
02061                                 break;
02062                         }
02063                 }
02064 
02065                 if (direction == 1)
02066                 { //next
02067                         x++;
02068                 }
02069                 else
02070                 { //previous
02071                         x--;
02072                 }
02073         
02074                 if (x >= NUM_FORCE_POWERS)
02075                 { //loop around
02076                         x = 0;
02077                 }
02078                 if (x < 0)
02079                 { //loop around
02080                         x = NUM_FORCE_POWERS-1;
02081                 }
02082 
02083                 i = forcePowerSorted[x]; //set to the sorted value again
02084         }
02085 
02086         if (foundnext != -1)
02087         { //found one, select it
02088                 ps->fd.forcePowerSelected = foundnext;
02089         }
02090 }
02091 
02092 int BG_GetItemIndexByTag(int tag, int type)
02093 { //Get the itemlist index from the tag and type
02094         int i = 0;
02095 
02096         while (i < bg_numItems)
02097         {
02098                 if (bg_itemlist[i].giTag == tag &&
02099                         bg_itemlist[i].giType == type)
02100                 {
02101                         return i;
02102                 }
02103 
02104                 i++;
02105         }
02106 
02107         return 0;
02108 }
02109 
02110 //yeah..
02111 qboolean BG_IsItemSelectable(playerState_t *ps, int item)
02112 {
02113         if (item == HI_HEALTHDISP || item == HI_AMMODISP ||
02114                 item == HI_JETPACK)
02115         {
02116                 return qfalse;
02117         }
02118         return qtrue;
02119 }
02120 
02121 void BG_CycleInven(playerState_t *ps, int direction)
02122 {
02123         int i;
02124         int dontFreeze = 0;
02125         int original;
02126 
02127         i = bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giTag;
02128         original = i;
02129 
02130         if (direction == 1)
02131         { //next
02132                 i++;
02133                 if (i == HI_NUM_HOLDABLE)
02134                 {
02135                         i = 1;
02136                 }
02137         }
02138         else
02139         { //previous
02140                 i--;
02141                 if (i == 0)
02142                 {
02143                         i = HI_NUM_HOLDABLE-1;
02144                 }
02145         }
02146 
02147         while (i != original)
02148         { //go in a full loop until hitting something, if hit nothing then select nothing
02149                 if (ps->stats[STAT_HOLDABLE_ITEMS] & (1 << i))
02150                 { //we have it, select it.
02151                         if (BG_IsItemSelectable(ps, i))
02152                         {
02153                                 ps->stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(i, IT_HOLDABLE);
02154                                 break;
02155                         }
02156                 }
02157 
02158                 if (direction == 1)
02159                 { //next
02160                         i++;
02161                 }
02162                 else
02163                 { //previous
02164                         i--;
02165                 }
02166 
02167                 if (i <= 0)
02168                 { //wrap around to the last
02169                         i = HI_NUM_HOLDABLE-1;
02170                 }
02171                 else if (i >= HI_NUM_HOLDABLE)
02172                 { //wrap around to the first
02173                         i = 1;
02174                 }
02175 
02176                 dontFreeze++;
02177                 if (dontFreeze >= 32)
02178                 { //yeah, sure, whatever (it's 2 am and I'm paranoid and can't frickin think)
02179                         break;
02180                 }
02181         }
02182 }
02183 
02184 /*
02185 ================
02186 BG_CanItemBeGrabbed
02187 
02188 Returns false if the item should not be picked up.
02189 This needs to be the same for client side prediction and server use.
02190 ================
02191 */
02192 qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) {
02193         gitem_t *item;
02194 
02195         if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) {
02196                 Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" );
02197         }
02198 
02199         item = &bg_itemlist[ent->modelindex];
02200 
02201         if ( ps )
02202         {
02203                 if ( ps->trueJedi )
02204                 {//force powers and saber only
02205                         if ( item->giType != IT_TEAM //not a flag
02206                                 && item->giType != IT_ARMOR//not shields
02207                                 && (item->giType != IT_WEAPON || item->giTag != WP_SABER)//not a saber
02208                                 && (item->giType != IT_HOLDABLE || item->giTag != HI_SEEKER)//not a seeker
02209                                 && (item->giType != IT_POWERUP || item->giTag == PW_YSALAMIRI) )//not a force pick-up
02210                         {
02211                                 return qfalse;
02212                         }
02213                 }
02214                 else if ( ps->trueNonJedi )
02215                 {//can't pick up force powerups
02216                         if ( (item->giType == IT_POWERUP && item->giTag != PW_YSALAMIRI) //if a powerup, can only can pick up ysalamiri
02217                                 || (item->giType == IT_HOLDABLE && item->giTag == HI_SEEKER)//if holdable, cannot pick up seeker 
02218                                 || (item->giType == IT_WEAPON && item->giTag == WP_SABER ) )//or if it's a saber
02219                         {
02220                                 return qfalse;
02221                         }
02222                 }
02223                 if ( ps->isJediMaster && item && (item->giType == IT_WEAPON || item->giType == IT_AMMO))
02224                 {//jedi master cannot pick up weapons
02225                         return qfalse;
02226                 }
02227                 if ( ps->duelInProgress )
02228                 { //no picking stuff up while in a duel, no matter what the type is
02229                         return qfalse;
02230                 }
02231         }
02232         else
02233         {//safety return since below code assumes a non-null ps
02234                 return qfalse;
02235         }
02236 
02237         switch( item->giType ) {
02238         case IT_WEAPON:
02239                 if (ent->generic1 == ps->clientNum && ent->powerups)
02240                 {
02241                         return qfalse;
02242                 }
02243                 if (!(ent->eFlags & EF_DROPPEDWEAPON) && (ps->stats[STAT_WEAPONS] & (1 << item->giTag)) &&
02244                         item->giTag != WP_THERMAL && item->giTag != WP_TRIP_MINE && item->giTag != WP_DET_PACK)
02245                 { //weaponstay stuff.. if this isn't dropped, and you already have it, you don't get it.
02246                         return qfalse;
02247                 }
02248                 if (item->giTag == WP_THERMAL || item->giTag == WP_TRIP_MINE || item->giTag == WP_DET_PACK)
02249                 { //check to see if full on ammo for this, if so, then..
02250                         int ammoIndex = weaponData[item->giTag].ammoIndex;
02251                         if (ps->ammo[ammoIndex] >= ammoData[ammoIndex].max)
02252                         { //don't need it
02253                                 return qfalse;
02254                         }
02255                 }
02256                 return qtrue;   // weapons are always picked up
02257 
02258         case IT_AMMO:
02259                 if (item->giTag == -1)
02260                 { //special case for "all ammo" packs
02261                         return qtrue;
02262                 }
02263                 if ( ps->ammo[item->giTag] >= ammoData[item->giTag].max) {
02264                         return qfalse;          // can't hold any more
02265                 }
02266                 return qtrue;
02267 
02268         case IT_ARMOR:
02269                 if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH]/* * item->giTag*/ ) {
02270                         return qfalse;
02271                 }
02272                 return qtrue;
02273 
02274         case IT_HEALTH:
02275                 // small and mega healths will go over the max, otherwise
02276                 // don't pick up if already at max
02277                 if ((ps->fd.forcePowersActive & (1 << FP_RAGE)))
02278                 {
02279                         return qfalse;
02280                 }
02281 
02282                 if ( item->quantity == 5 || item->quantity == 100 ) {
02283                         if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
02284                                 return qfalse;
02285                         }
02286                         return qtrue;
02287                 }
02288 
02289                 if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) {
02290                         return qfalse;
02291                 }
02292                 return qtrue;
02293 
02294         case IT_POWERUP:
02295                 if (ps && (ps->powerups[PW_YSALAMIRI]))
02296                 {
02297                         if (item->giTag != PW_YSALAMIRI)
02298                         {
02299                                 return qfalse;
02300                         }
02301                 }
02302                 return qtrue;   // powerups are always picked up
02303 
02304         case IT_TEAM: // team items, such as flags
02305                 if( gametype == GT_CTF || gametype == GT_CTY ) {
02306                         // ent->modelindex2 is non-zero on items if they are dropped
02307                         // we need to know this because we can pick up our dropped flag (and return it)
02308                         // but we can't pick up our flag at base
02309                         if (ps->persistant[PERS_TEAM] == TEAM_RED) {
02310                                 if (item->giTag == PW_BLUEFLAG ||
02311                                         (item->giTag == PW_REDFLAG && ent->modelindex2) ||
02312                                         (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG]) )
02313                                         return qtrue;
02314                         } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) {
02315                                 if (item->giTag == PW_REDFLAG ||
02316                                         (item->giTag == PW_BLUEFLAG && ent->modelindex2) ||
02317                                         (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]) )
02318                                         return qtrue;
02319                         }
02320                 }
02321 
02322                 return qfalse;
02323 
02324         case IT_HOLDABLE:
02325                 if ( ps->stats[STAT_HOLDABLE_ITEMS] & (1 << item->giTag))
02326                 {
02327                         return qfalse;
02328                 }
02329                 return qtrue;
02330 
02331         case IT_BAD:
02332             Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" );
02333         default:
02334 #ifndef Q3_VM
02335 #ifndef NDEBUG // bk0001204
02336           Com_Printf("BG_CanItemBeGrabbed: unknown enum %d\n", item->giType );
02337 #endif
02338 #endif
02339          break;
02340         }
02341 
02342         return qfalse;
02343 }
02344 
02345 //======================================================================
02346 
02347 /*
02348 ================
02349 BG_EvaluateTrajectory
02350 
02351 ================
02352 */
02353 void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) {
02354         float           deltaTime;
02355         float           phase;
02356 
02357         switch( tr->trType ) {
02358         case TR_STATIONARY:
02359         case TR_INTERPOLATE:
02360                 VectorCopy( tr->trBase, result );
02361                 break;
02362         case TR_LINEAR:
02363                 deltaTime = ( atTime - tr->trTime ) * 0.001;    // milliseconds to seconds
02364                 VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
02365                 break;
02366         case TR_SINE:
02367                 deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;
02368                 phase = sin( deltaTime * M_PI * 2 );
02369                 VectorMA( tr->trBase, phase, tr->trDelta, result );
02370                 break;
02371         case TR_LINEAR_STOP:
02372                 if ( atTime > tr->trTime + tr->trDuration ) {
02373                         atTime = tr->trTime + tr->trDuration;
02374                 }
02375                 deltaTime = ( atTime - tr->trTime ) * 0.001;    // milliseconds to seconds
02376                 if ( deltaTime < 0 ) {
02377                         deltaTime = 0;
02378                 }
02379                 VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
02380                 break;
02381         case TR_NONLINEAR_STOP:
02382                 if ( atTime > tr->trTime + tr->trDuration ) 
02383                 {
02384                         atTime = tr->trTime + tr->trDuration;
02385                 }
02386                 //new slow-down at end
02387                 if ( atTime - tr->trTime > tr->trDuration || atTime - tr->trTime <= 0  )
02388                 {
02389                         deltaTime = 0;
02390                 }
02391                 else
02392                 {//FIXME: maybe scale this somehow?  So that it starts out faster and stops faster?
02393                         deltaTime = tr->trDuration*0.001f*((float)cos( DEG2RAD(90.0f - (90.0f*((float)atTime-tr->trTime)/(float)tr->trDuration)) ));
02394                 }
02395                 VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
02396                 break;
02397         case TR_GRAVITY:
02398                 deltaTime = ( atTime - tr->trTime ) * 0.001;    // milliseconds to seconds
02399                 VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
02400                 result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime;             // FIXME: local gravity...
02401                 break;
02402         default:
02403 #ifdef QAGAME
02404                 Com_Error( ERR_DROP, "BG_EvaluateTrajectory: [GAME SIDE] unknown trType: %i", tr->trType );
02405 #else
02406                 Com_Error( ERR_DROP, "BG_EvaluateTrajectory: [CLIENTGAME SIDE] unknown trType: %i", tr->trType );
02407 #endif
02408                 break;
02409         }
02410 }
02411 
02412 /*
02413 ================
02414 BG_EvaluateTrajectoryDelta
02415 
02416 For determining velocity at a given time
02417 ================
02418 */
02419 void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) {
02420         float   deltaTime;
02421         float   phase;
02422 
02423         switch( tr->trType ) {
02424         case TR_STATIONARY:
02425         case TR_INTERPOLATE:
02426                 VectorClear( result );
02427                 break;
02428         case TR_LINEAR:
02429                 VectorCopy( tr->trDelta, result );
02430                 break;
02431         case TR_SINE:
02432                 deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;
02433                 phase = cos( deltaTime * M_PI * 2 );    // derivative of sin = cos
02434                 phase *= 0.5;
02435                 VectorScale( tr->trDelta, phase, result );
02436                 break;
02437         case TR_LINEAR_STOP:
02438                 if ( atTime > tr->trTime + tr->trDuration ) {
02439                         VectorClear( result );
02440                         return;
02441                 }
02442                 VectorCopy( tr->trDelta, result );
02443                 break;
02444         case TR_NONLINEAR_STOP:
02445                 if ( atTime - tr->trTime > tr->trDuration || atTime - tr->trTime <= 0  )
02446                 {
02447                         VectorClear( result );
02448                         return;
02449                 }
02450                 deltaTime = tr->trDuration*0.001f*((float)cos( DEG2RAD(90.0f - (90.0f*((float)atTime-tr->trTime)/(float)tr->trDuration)) ));
02451                 VectorScale( tr->trDelta, deltaTime, result );
02452                 break;
02453         case TR_GRAVITY:
02454                 deltaTime = ( atTime - tr->trTime ) * 0.001;    // milliseconds to seconds
02455                 VectorCopy( tr->trDelta, result );
02456                 result[2] -= DEFAULT_GRAVITY * deltaTime;               // FIXME: local gravity...
02457                 break;
02458         default:
02459                 Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime );
02460                 break;
02461         }
02462 }
02463 
02464 char *eventnames[] = {
02465         "EV_NONE",
02466 
02467         "EV_CLIENTJOIN",
02468 
02469         "EV_FOOTSTEP",
02470         "EV_FOOTSTEP_METAL",
02471         "EV_FOOTSPLASH",
02472         "EV_FOOTWADE",
02473         "EV_SWIM",
02474 
02475         "EV_STEP_4",
02476         "EV_STEP_8",
02477         "EV_STEP_12",
02478         "EV_STEP_16",
02479 
02480         "EV_FALL",
02481 
02482         "EV_JUMP_PAD",                  // boing sound at origin", jump sound on player
02483 
02484         "EV_GHOUL2_MARK",                       //create a projectile impact mark on something with a client-side g2 instance.
02485 
02486         "EV_GLOBAL_DUEL",
02487         "EV_PRIVATE_DUEL",
02488 
02489         "EV_JUMP",
02490         "EV_ROLL",
02491         "EV_WATER_TOUCH",       // foot touches
02492         "EV_WATER_LEAVE",       // foot leaves
02493         "EV_WATER_UNDER",       // head touches
02494         "EV_WATER_CLEAR",       // head leaves
02495 
02496         "EV_ITEM_PICKUP",                       // normal item pickups are predictable
02497         "EV_GLOBAL_ITEM_PICKUP",        // powerup / team sounds are broadcast to everyone
02498 
02499         "EV_VEH_FIRE",
02500 
02501         "EV_NOAMMO",
02502         "EV_CHANGE_WEAPON",
02503         "EV_FIRE_WEAPON",
02504         "EV_ALT_FIRE",
02505         "EV_SABER_ATTACK",
02506         "EV_SABER_HIT",
02507         "EV_SABER_BLOCK",
02508         "EV_SABER_CLASHFLARE",
02509         "EV_SABER_UNHOLSTER",
02510         "EV_BECOME_JEDIMASTER",
02511         "EV_DISRUPTOR_MAIN_SHOT",
02512         "EV_DISRUPTOR_SNIPER_SHOT",
02513         "EV_DISRUPTOR_SNIPER_MISS",
02514         "EV_DISRUPTOR_HIT",
02515         "EV_DISRUPTOR_ZOOMSOUND",
02516 
02517         "EV_PREDEFSOUND",
02518 
02519         "EV_TEAM_POWER",
02520 
02521         "EV_SCREENSHAKE",
02522         
02523         "EV_LOCALTIMER",
02524 
02525         "EV_USE",                       // +Use key
02526 
02527         "EV_USE_ITEM0",
02528         "EV_USE_ITEM1",
02529         "EV_USE_ITEM2",
02530         "EV_USE_ITEM3",
02531         "EV_USE_ITEM4",
02532         "EV_USE_ITEM5",
02533         "EV_USE_ITEM6",
02534         "EV_USE_ITEM7",
02535         "EV_USE_ITEM8",
02536         "EV_USE_ITEM9",
02537         "EV_USE_ITEM10",
02538         "EV_USE_ITEM11",
02539         "EV_USE_ITEM12",
02540         "EV_USE_ITEM13",
02541         "EV_USE_ITEM14",
02542         "EV_USE_ITEM15",
02543 
02544         "EV_ITEMUSEFAIL",
02545 
02546         "EV_ITEM_RESPAWN",
02547         "EV_ITEM_POP",
02548         "EV_PLAYER_TELEPORT_IN",
02549         "EV_PLAYER_TELEPORT_OUT",
02550 
02551         "EV_GRENADE_BOUNCE",            // eventParm will be the soundindex
02552         "EV_MISSILE_STICK",
02553 
02554         "EV_PLAY_EFFECT",
02555         "EV_PLAY_EFFECT_ID", //finally gave in and added it..
02556         "EV_PLAY_PORTAL_EFFECT_ID",
02557 
02558         "EV_PLAYDOORSOUND",
02559         "EV_PLAYDOORLOOPSOUND",
02560         "EV_BMODEL_SOUND",
02561 
02562         "EV_MUTE_SOUND",
02563         "EV_VOICECMD_SOUND",
02564         "EV_GENERAL_SOUND",
02565         "EV_GLOBAL_SOUND",              // no attenuation
02566         "EV_GLOBAL_TEAM_SOUND",
02567         "EV_ENTITY_SOUND",
02568 
02569         "EV_PLAY_ROFF",
02570 
02571         "EV_GLASS_SHATTER",
02572         "EV_DEBRIS",
02573         "EV_MISC_MODEL_EXP",
02574 
02575         "EV_CONC_ALT_IMPACT",
02576 
02577         "EV_MISSILE_HIT",
02578         "EV_MISSILE_MISS",
02579         "EV_MISSILE_MISS_METAL",
02580         "EV_BULLET",                            // otherEntity is the shooter
02581 
02582         "EV_PAIN",
02583         "EV_DEATH1",
02584         "EV_DEATH2",
02585         "EV_DEATH3",
02586         "EV_OBITUARY",
02587 
02588         "EV_POWERUP_QUAD",
02589         "EV_POWERUP_BATTLESUIT",
02590         //"EV_POWERUP_REGEN",
02591 
02592         "EV_FORCE_DRAINED",
02593 
02594         "EV_GIB_PLAYER",                        // gib a previously living player
02595         "EV_SCOREPLUM",                 // score plum
02596 
02597         "EV_CTFMESSAGE",
02598 
02599         "EV_BODYFADE",
02600 
02601         "EV_SIEGE_ROUNDOVER",
02602         "EV_SIEGE_OBJECTIVECOMPLETE",
02603 
02604         "EV_DESTROY_GHOUL2_INSTANCE",
02605 
02606         "EV_DESTROY_WEAPON_MODEL",
02607 
02608         "EV_GIVE_NEW_RANK",
02609         "EV_SET_FREE_SABER",
02610         "EV_SET_FORCE_DISABLE",
02611 
02612         "EV_WEAPON_CHARGE",
02613         "EV_WEAPON_CHARGE_ALT",
02614 
02615         "EV_SHIELD_HIT",
02616 
02617         "EV_DEBUG_LINE",
02618         "EV_TESTLINE",
02619         "EV_STOPLOOPINGSOUND",
02620         "EV_STARTLOOPINGSOUND",
02621         "EV_TAUNT",
02622 //fixme, added a bunch that aren't here!
02623 };
02624 
02625 /*
02626 ===============
02627 BG_AddPredictableEventToPlayerstate
02628 
02629 Handles the sequence numbers
02630 ===============
02631 */
02632 
02633 //void  trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
02634 
02635 void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) {
02636 
02637 #ifdef _DEBUG
02638         {
02639                 static vmCvar_t         showEvents;
02640                 static qboolean         isRegistered = qfalse;
02641 
02642                 if (!isRegistered)
02643                 {
02644                         trap_Cvar_Register(&showEvents, "showevents", "0", 0);
02645                         isRegistered = qtrue;
02646                 }
02647 
02648                 if ( showEvents.integer != 0 ) {
02649 #ifdef QAGAME
02650                         Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);
02651 #else
02652                         Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);
02653 #endif
02654                 }
02655         }
02656 #endif
02657         ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent;
02658         ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm;
02659         ps->eventSequence++;
02660 }
02661 
02662 /*
02663 ========================
02664 BG_TouchJumpPad
02665 ========================
02666 */
02667 void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) {
02668         vec3_t  angles;
02669         float p;
02670         int effectNum;
02671 
02672         // spectators don't use jump pads
02673         if ( ps->pm_type != PM_NORMAL && ps->pm_type != PM_JETPACK && ps->pm_type != PM_FLOAT ) {
02674                 return;
02675         }
02676 
02677         // if we didn't hit this same jumppad the previous frame
02678         // then don't play the event sound again if we are in a fat trigger
02679         if ( ps->jumppad_ent != jumppad->number ) {
02680 
02681                 vectoangles( jumppad->origin2, angles);
02682                 p = fabs( AngleNormalize180( angles[PITCH] ) );
02683                 if( p < 45 ) {
02684                         effectNum = 0;
02685                 } else {
02686                         effectNum = 1;
02687                 }
02688         }
02689         // remember hitting this jumppad this frame
02690         ps->jumppad_ent = jumppad->number;
02691         ps->jumppad_frame = ps->pmove_framecount;
02692         // give the player the velocity from the jumppad
02693         VectorCopy( jumppad->origin2, ps->velocity );
02694 }
02695 
02696 /*
02697 =================
02698 BG_EmplacedView
02699 
02700 Shared code for emplaced angle gun constriction
02701 =================
02702 */
02703 int BG_EmplacedView(vec3_t baseAngles, vec3_t angles, float *newYaw, float constraint)
02704 {
02705         float dif = AngleSubtract(baseAngles[YAW], angles[YAW]);
02706 
02707         if (dif > constraint ||
02708                 dif < -constraint)
02709         {
02710                 float amt;
02711 
02712                 if (dif > constraint)
02713                 {
02714                         amt = (dif-constraint);
02715                         dif = constraint;
02716                 }
02717                 else if (dif < -constraint)
02718                 {
02719                         amt = (dif+constraint);
02720                         dif = -constraint;
02721                 }
02722                 else
02723                 {
02724                         amt = 0.0f;
02725                 }
02726 
02727                 *newYaw = AngleSubtract(angles[YAW], -dif);
02728 
02729                 if (amt > 1.0f || amt < -1.0f)
02730                 { //significant, force the view
02731                         return 2;
02732                 }
02733                 else
02734                 { //just a little out of range
02735                         return 1;
02736                 }
02737         }
02738 
02739         return 0;
02740 }
02741 
02742 //To see if the client is trying to use one of the included skins not meant for MP.
02743 //I don't much care for hardcoded strings, but this seems the best way to go.
02744 qboolean BG_IsValidCharacterModel(const char *modelName, const char *skinName)
02745 {
02746         if (!Q_stricmp(skinName, "menu"))
02747         {
02748                 return qfalse;
02749         }
02750         else if (!Q_stricmp(modelName, "kyle"))
02751         {
02752                 if (!Q_stricmp(skinName, "fpls"))
02753                 {
02754                         return qfalse;
02755                 }
02756                 else if (!Q_stricmp(skinName, "fpls2"))
02757                 {
02758                         return qfalse;
02759                 }
02760                 else if (!Q_stricmp(skinName, "fpls3"))
02761                 {
02762                         return qfalse;
02763                 }
02764         }
02765         return qtrue;
02766 }
02767 
02768 qboolean BG_ValidateSkinForTeam( const char *modelName, char *skinName, int team, float *colors )
02769 {
02770         if (!Q_stricmpn(modelName, "jedi_",5))
02771         { //argh, it's a custom player skin!
02772                 if (team == TEAM_RED && colors)
02773                 {
02774                         colors[0] = 1.0f;
02775                         colors[1] = 0.0f;
02776                         colors[2] = 0.0f;
02777                 }
02778                 else if (team == TEAM_BLUE && colors)
02779                 {
02780                         colors[0] = 0.0f;
02781                         colors[1] = 0.0f;
02782                         colors[2] = 1.0f;
02783                 }
02784                 return qtrue;
02785         }
02786 
02787         if (team == TEAM_RED)
02788         {
02789                 if ( Q_stricmp( "red", skinName ) != 0 )
02790                 {//not "red"
02791                         if ( Q_stricmp( "blue", skinName ) == 0
02792                                 || Q_stricmp( "default", skinName ) == 0
02793                                 || strchr(skinName, '|')//a multi-skin playerModel
02794                                 || !BG_IsValidCharacterModel(modelName, skinName) )
02795                         {
02796                                 Q_strncpyz(skinName, "red", MAX_QPATH);
02797                                 return qfalse;
02798                         }
02799                         else
02800                         {//need to set it to red
02801                                 int len = strlen( skinName );
02802                                 if ( len < 3 )
02803                                 {//too short to be "red"
02804                                         Q_strcat(skinName, MAX_QPATH, "_red");
02805                                 }
02806                                 else
02807                                 {
02808                                         char    *start = &skinName[len-3];
02809                                         if ( Q_strncmp( "red", start, 3 ) != 0 )
02810                                         {//doesn't already end in "red"
02811                                                 if ( len+4 >= MAX_QPATH )
02812                                                 {//too big to append "_red"
02813                                                         Q_strncpyz(skinName, "red", MAX_QPATH);
02814                                                         return qfalse;
02815                                                 }
02816                                                 else
02817                                                 {
02818                                                         Q_strcat(skinName, MAX_QPATH, "_red");
02819                                                 }
02820                                         }
02821                                 }
02822                                 //if file does not exist, set to "red"
02823                                 if ( !BG_FileExists( va( "models/players/%s/model_%s.skin", modelName, skinName ) ) )
02824                                 {
02825                                         Q_strncpyz(skinName, "red", MAX_QPATH);
02826                                 }
02827                                 return qfalse;
02828                         }
02829                 }
02830 
02831         }
02832         else if (team == TEAM_BLUE)
02833         {
02834                 if ( Q_stricmp( "blue", skinName ) != 0 )
02835                 {
02836                         if ( Q_stricmp( "red", skinName ) == 0
02837                                 || Q_stricmp( "default", skinName ) == 0
02838                                 || strchr(skinName, '|')//a multi-skin playerModel
02839                                 || !BG_IsValidCharacterModel(modelName, skinName) )
02840                         {
02841                                 Q_strncpyz(skinName, "blue", MAX_QPATH);
02842                                 return qfalse;
02843                         }
02844                         else
02845                         {//need to set it to blue
02846                                 int len = strlen( skinName );
02847                                 if ( len < 4 )
02848                                 {//too short to be "blue"
02849                                         Q_strcat(skinName, MAX_QPATH, "_blue");
02850                                 }
02851                                 else 
02852                                 {
02853                                         char    *start = &skinName[len-4];
02854                                         if ( Q_strncmp( "blue", start, 4 ) != 0 )
02855                                         {//doesn't already end in "blue"
02856                                                 if ( len+5 >= MAX_QPATH )
02857                                                 {//too big to append "_blue"
02858                                                         Q_strncpyz(skinName, "blue", MAX_QPATH);
02859                                                         return qfalse;
02860                                                 }
02861                                                 else
02862                                                 {
02863                                                         Q_strcat(skinName, MAX_QPATH, "_blue");
02864                                                 }
02865                                         }
02866                                 }
02867                                 //if file does not exist, set to "blue"
02868                                 if ( !BG_FileExists( va( "models/players/%s/model_%s.skin", modelName, skinName ) ) )
02869                                 {
02870                                         Q_strncpyz(skinName, "blue", MAX_QPATH);
02871                                 }
02872                                 return qfalse;
02873                         }
02874                 }
02875         }
02876         return qtrue;
02877 }
02878 
02879 /*
02880 ========================
02881 BG_PlayerStateToEntityState
02882 
02883 This is done after each set of usercmd_t on the server,
02884 and after local prediction on the client
02885 ========================
02886 */
02887 void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) {
02888         int             i;
02889 
02890         if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
02891                 s->eType = ET_INVISIBLE;
02892         } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
02893                 s->eType = ET_INVISIBLE;
02894         } else {
02895                 s->eType = ET_PLAYER;
02896         }
02897 
02898         s->number = ps->clientNum;
02899 
02900         s->pos.trType = TR_INTERPOLATE;
02901         VectorCopy( ps->origin, s->pos.trBase );
02902         if ( snap ) {
02903                 SnapVector( s->pos.trBase );
02904         }
02905         // set the trDelta for flag direction
02906         VectorCopy( ps->velocity, s->pos.trDelta );
02907 
02908         s->apos.trType = TR_INTERPOLATE;
02909         VectorCopy( ps->viewangles, s->apos.trBase );
02910         if ( snap ) {
02911                 SnapVector( s->apos.trBase );
02912         }
02913 
02914         s->trickedentindex = ps->fd.forceMindtrickTargetIndex;
02915         s->trickedentindex2 = ps->fd.forceMindtrickTargetIndex2;
02916         s->trickedentindex3 = ps->fd.forceMindtrickTargetIndex3;
02917         s->trickedentindex4 = ps->fd.forceMindtrickTargetIndex4;
02918 
02919         s->forceFrame = ps->saberLockFrame;
02920 
02921         s->emplacedOwner = ps->electrifyTime;
02922 
02923         s->speed = ps->speed;
02924 
02925         s->genericenemyindex = ps->genericEnemyIndex;
02926 
02927         s->activeForcePass = ps->activeForcePass;
02928 
02929         s->angles2[YAW] = ps->movementDir;
02930         s->legsAnim = ps->legsAnim;
02931         s->torsoAnim = ps->torsoAnim;
02932 
02933         s->legsFlip = ps->legsFlip;
02934         s->torsoFlip = ps->torsoFlip;
02935 
02936         s->clientNum = ps->clientNum;           // ET_PLAYER looks here instead of at number
02937                                                                                 // so corpses can also reference the proper config
02938         s->eFlags = ps->eFlags;
02939         s->eFlags2 = ps->eFlags2;
02940 
02941         s->saberInFlight = ps->saberInFlight;
02942         s->saberEntityNum = ps->saberEntityNum;
02943         s->saberMove = ps->saberMove;
02944         s->forcePowersActive = ps->fd.forcePowersActive;
02945 
02946         if (ps->duelInProgress)
02947         {
02948                 s->bolt1 = 1;
02949         }
02950         else
02951         {
02952                 s->bolt1 = 0;
02953         }
02954 
02955         s->otherEntityNum2 = ps->emplacedIndex;
02956 
02957         s->saberHolstered = ps->saberHolstered;
02958 
02959         if (ps->genericEnemyIndex != -1)
02960         {
02961                 s->eFlags |= EF_SEEKERDRONE;
02962         }
02963 
02964         if ( ps->stats[STAT_HEALTH] <= 0 ) {
02965                 s->eFlags |= EF_DEAD;
02966         } else {
02967                 s->eFlags &= ~EF_DEAD;
02968         }
02969 
02970         if ( ps->externalEvent ) {
02971                 s->event = ps->externalEvent;
02972                 s->eventParm = ps->externalEventParm;
02973         } else if ( ps->entityEventSequence < ps->eventSequence ) {
02974                 int             seq;
02975 
02976                 if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
02977                         ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
02978                 }
02979                 seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
02980                 s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
02981                 s->eventParm = ps->eventParms[ seq ];
02982                 ps->entityEventSequence++;
02983         }
02984 
02985 
02986         s->weapon = ps->weapon;
02987         s->groundEntityNum = ps->groundEntityNum;
02988 
02989         s->powerups = 0;
02990         for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
02991                 if ( ps->powerups[ i ] ) {
02992                         s->powerups |= 1 << i;
02993                 }
02994         }
02995 
02996         s->loopSound = ps->loopSound;
02997         s->generic1 = ps->generic1;
02998 
02999         //NOT INCLUDED IN ENTITYSTATETOPLAYERSTATE:
03000         s->modelindex2 = ps->weaponstate;
03001         s->constantLight = ps->weaponChargeTime;
03002 
03003         VectorCopy(ps->lastHitLoc, s->origin2);
03004 
03005         s->isJediMaster = ps->isJediMaster;
03006 
03007         s->time2 = ps->holocronBits;
03008 
03009         s->fireflag = ps->fd.saberAnimLevel;
03010 
03011         s->heldByClient = ps->heldByClient;
03012         s->ragAttach = ps->ragAttach;
03013 
03014         s->iModelScale = ps->iModelScale;
03015 
03016         s->brokenLimbs = ps->brokenLimbs;
03017 
03018         s->hasLookTarget = ps->hasLookTarget;
03019         s->lookTarget = ps->lookTarget;
03020 
03021         s->customRGBA[0] = ps->customRGBA[0];
03022         s->customRGBA[1] = ps->customRGBA[1];
03023         s->customRGBA[2] = ps->customRGBA[2];
03024         s->customRGBA[3] = ps->customRGBA[3];
03025 
03026         s->m_iVehicleNum = ps->m_iVehicleNum;
03027 }
03028 
03029 /*
03030 ========================
03031 BG_PlayerStateToEntityStateExtraPolate
03032 
03033 This is done after each set of usercmd_t on the server,
03034 and after local prediction on the client
03035 ========================
03036 */
03037 void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) {
03038         int             i;
03039 
03040         if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
03041                 s->eType = ET_INVISIBLE;
03042         } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
03043                 s->eType = ET_INVISIBLE;
03044         } else {
03045                 s->eType = ET_PLAYER;
03046         }
03047 
03048         s->number = ps->clientNum;
03049 
03050         s->pos.trType = TR_LINEAR_STOP;
03051         VectorCopy( ps->origin, s->pos.trBase );
03052         if ( snap ) {
03053                 SnapVector( s->pos.trBase );
03054         }
03055         // set the trDelta for flag direction and linear prediction
03056         VectorCopy( ps->velocity, s->pos.trDelta );
03057         // set the time for linear prediction
03058         s->pos.trTime = time;
03059         // set maximum extra polation time
03060         s->pos.trDuration = 50; // 1000 / sv_fps (default = 20)
03061 
03062         s->apos.trType = TR_INTERPOLATE;
03063         VectorCopy( ps->viewangles, s->apos.trBase );
03064         if ( snap ) {
03065                 SnapVector( s->apos.trBase );
03066         }
03067 
03068         s->trickedentindex = ps->fd.forceMindtrickTargetIndex;
03069         s->trickedentindex2 = ps->fd.forceMindtrickTargetIndex2;
03070         s->trickedentindex3 = ps->fd.forceMindtrickTargetIndex3;
03071         s->trickedentindex4 = ps->fd.forceMindtrickTargetIndex4;
03072 
03073         s->forceFrame = ps->saberLockFrame;
03074 
03075         s->emplacedOwner = ps->electrifyTime;
03076 
03077         s->speed = ps->speed;
03078 
03079         s->genericenemyindex = ps->genericEnemyIndex;
03080 
03081         s->activeForcePass = ps->activeForcePass;
03082 
03083         s->angles2[YAW] = ps->movementDir;
03084         s->legsAnim = ps->legsAnim;
03085         s->torsoAnim = ps->torsoAnim;
03086 
03087         s->legsFlip = ps->legsFlip;
03088         s->torsoFlip = ps->torsoFlip;
03089 
03090         s->clientNum = ps->clientNum;           // ET_PLAYER looks here instead of at number
03091                                                                                 // so corpses can also reference the proper config
03092         s->eFlags = ps->eFlags;
03093         s->eFlags2 = ps->eFlags2;
03094 
03095         s->saberInFlight = ps->saberInFlight;
03096         s->saberEntityNum = ps->saberEntityNum;
03097         s->saberMove = ps->saberMove;
03098         s->forcePowersActive = ps->fd.forcePowersActive;
03099 
03100         if (ps->duelInProgress)
03101         {
03102                 s->bolt1 = 1;
03103         }
03104         else
03105         {
03106                 s->bolt1 = 0;
03107         }
03108 
03109         s->otherEntityNum2 = ps->emplacedIndex;
03110 
03111         s->saberHolstered = ps->saberHolstered;
03112 
03113         if (ps->genericEnemyIndex != -1)
03114         {
03115                 s->eFlags |= EF_SEEKERDRONE;
03116         }
03117 
03118         if ( ps->stats[STAT_HEALTH] <= 0 ) {
03119                 s->eFlags |= EF_DEAD;
03120         } else {
03121                 s->eFlags &= ~EF_DEAD;
03122         }
03123 
03124         if ( ps->externalEvent ) {
03125                 s->event = ps->externalEvent;
03126                 s->eventParm = ps->externalEventParm;
03127         } else if ( ps->entityEventSequence < ps->eventSequence ) {
03128                 int             seq;
03129 
03130                 if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
03131                         ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
03132                 }
03133                 seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
03134                 s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
03135                 s->eventParm = ps->eventParms[ seq ];
03136                 ps->entityEventSequence++;
03137         }
03138         s->weapon = ps->weapon;
03139         s->groundEntityNum = ps->groundEntityNum;
03140 
03141         s->powerups = 0;
03142         for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
03143                 if ( ps->powerups[ i ] ) {
03144                         s->powerups |= 1 << i;
03145                 }
03146         }
03147 
03148         s->loopSound = ps->loopSound;
03149         s->generic1 = ps->generic1;
03150 
03151         //NOT INCLUDED IN ENTITYSTATETOPLAYERSTATE:
03152         s->modelindex2 = ps->weaponstate;
03153         s->constantLight = ps->weaponChargeTime;
03154 
03155         VectorCopy(ps->lastHitLoc, s->origin2);
03156 
03157         s->isJediMaster = ps->isJediMaster;
03158 
03159         s->time2 = ps->holocronBits;
03160 
03161         s->fireflag = ps->fd.saberAnimLevel;
03162 
03163         s->heldByClient = ps->heldByClient;
03164         s->ragAttach = ps->ragAttach;
03165 
03166         s->iModelScale = ps->iModelScale;
03167 
03168         s->brokenLimbs = ps->brokenLimbs;
03169 
03170         s->hasLookTarget = ps->hasLookTarget;
03171         s->lookTarget = ps->lookTarget;
03172 
03173         s->customRGBA[0] = ps->customRGBA[0];
03174         s->customRGBA[1] = ps->customRGBA[1];
03175         s->customRGBA[2] = ps->customRGBA[2];
03176         s->customRGBA[3] = ps->customRGBA[3];
03177 
03178         s->m_iVehicleNum = ps->m_iVehicleNum;
03179 }
03180 
03181 /*
03182 =============================================================================
03183 
03184 PLAYER ANGLES
03185 
03186 =============================================================================
03187 */
03188 
03189 //perform the appropriate model precache routine
03190 #ifdef QAGAME //game
03191 extern int trap_G2API_InitGhoul2Model(void **ghoul2Ptr, const char *fileName, int modelIndex, qhandle_t customSkin,
03192                                                   qhandle_t customShader, int modelFlags, int lodBias); //exists on game/cgame/ui, only used on game
03193 extern void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr); //exists on game/cgame/ui, only used on game
03194 #else //cgame/ui
03195 extern qhandle_t trap_R_RegisterModel( const char *name ); //exists on cgame/ui
03196 #endif
03197 //game/cgame/ui
03198 extern qhandle_t trap_R_RegisterSkin( const char *name ); //exists on game/cgame/ui
03199 
03200 int BG_ModelCache(const char *modelName, const char *skinName)
03201 {
03202 #ifdef QAGAME
03203         void *g2 = NULL;
03204 
03205         if (skinName && skinName[0])
03206         {
03207                 trap_R_RegisterSkin(skinName);
03208         }
03209 
03210         //I could hook up a precache ghoul2 function, but oh well, this works
03211         trap_G2API_InitGhoul2Model(&g2, modelName, 0, 0, 0, 0, 0);
03212         if (g2)
03213         { //now get rid of it
03214                 trap_G2API_CleanGhoul2Models(&g2);
03215         }
03216         return 0;
03217 #else
03218         if (skinName && skinName[0])
03219         {
03220                 trap_R_RegisterSkin(skinName);
03221         }
03222         return trap_R_RegisterModel(modelName);
03223 #endif
03224 }
03225 
03226 #ifdef _XBOX    // Hacky BG_Alloc replacement
03227 
03228 // This file claims to be stateless. Yeah, right. Regardless, I'm not setting
03229 // aside 5.5 MB of static buffers for this crap. Let's use Z_Malloc. Of course,
03230 // we still need to deal with the fact that any code using BG_Malloc is almost
03231 // certainly leaking memory like a sieve.
03232 
03233 // Dave addendum - TAG_BG_ALLOC is entirely freed when the level starts.
03234 void *BG_Alloc ( int size )
03235 {
03236         return Z_Malloc(size, TAG_BG_ALLOC, qfalse, 4);
03237 }
03238 
03239 void *BG_AllocUnaligned ( int size )
03240 {
03241         // Ignore the unaligned hint, this function isn't called anyway
03242         return Z_Malloc(size, TAG_BG_ALLOC, qfalse, 4);
03243 }
03244 
03245 // Because the interface to BG_TempAlloc/BG_TempFree is brain-dead, we need
03246 // to remember our last few temporary allocations performed.
03247 #define MAX_TEMP_ALLOCS 3
03248 static void     *tempAllocPointers[MAX_TEMP_ALLOCS] = { 0 };
03249 static int      tempAllocSizes[MAX_TEMP_ALLOCS] = { 0 };
03250 
03251 void *BG_TempAlloc( int size )
03252 {
03253         int i;
03254 
03255         // Do we have a free spot?
03256         for (i = 0; i < MAX_TEMP_ALLOCS; ++i)
03257                 if (!tempAllocPointers[i])
03258                         break;
03259 
03260         if (i == MAX_TEMP_ALLOCS)
03261         {
03262                 assert(!"No space for TempAlloc -> Increase MAX_TEMP_ALLOCS");
03263                 return NULL;
03264         }
03265 
03266         tempAllocPointers[i] = Z_Malloc(size, TAG_TEMP_WORKSPACE, qfalse, 4);
03267         tempAllocSizes[i] = size;
03268 
03269         return tempAllocPointers[i];
03270 }
03271 
03272 void BG_TempFree( int size )
03273 {
03274         int i;
03275 
03276         // Find the allocation
03277         for (i = MAX_TEMP_ALLOCS - 1; i >= 0; --i)
03278                 if (tempAllocPointers[i] && (tempAllocSizes[i] == size))
03279                         break;
03280 
03281         if (i < 0)
03282         {
03283                 assert(!"BG_TempFree doesn't match a call to BG_TempAlloc");
03284                 return;
03285         }
03286 
03287         Z_Free(tempAllocPointers[i]);
03288         tempAllocPointers[i] = 0;
03289         tempAllocSizes[i] = 0;
03290 
03291         return;
03292 }
03293 
03294 char *BG_StringAlloc ( const char *source )
03295 {
03296         char *dest;
03297 
03298         dest = (char *) BG_Alloc ( strlen ( source ) + 1 );
03299         strcpy ( dest, source );
03300         return dest;
03301 }
03302 
03303 qboolean BG_OutOfMemory ( void )
03304 {
03305         // Never called
03306         return qfalse;
03307 }
03308 
03309 #else // _XBOX
03310 
03311 #ifdef QAGAME
03312 #define MAX_POOL_SIZE   3000000 //1024000
03313 #elif defined CGAME //don't need as much for cgame stuff. 2mb will be fine.
03314 #define MAX_POOL_SIZE   2048000
03315 #else //And for the ui the only thing we'll be using this for anyway is allocating anim data for g2 menu models
03316 #define MAX_POOL_SIZE   512000
03317 #endif
03318 
03319 //I am using this for all the stuff like NPC client structures on server/client and
03320 //non-humanoid animations as well until/if I can get dynamic memory working properly
03321 //with casted datatypes, which is why it is so large.
03322 
03323 
03324 static char             bg_pool[MAX_POOL_SIZE];
03325 static int              bg_poolSize = 0;
03326 static int              bg_poolTail = MAX_POOL_SIZE;
03327 
03328 void *BG_Alloc ( int size )
03329 {
03330         bg_poolSize = ((bg_poolSize + 0x00000003) & 0xfffffffc);
03331 
03332         if (bg_poolSize + size > bg_poolTail)
03333         {
03334                 Com_Error( ERR_DROP, "BG_Alloc: buffer exceeded tail (%d > %d)", bg_poolSize + size, bg_poolTail);
03335                 return 0;
03336         }
03337 
03338         bg_poolSize += size;
03339 
03340         return &bg_pool[bg_poolSize-size];
03341 }
03342 
03343 void *BG_AllocUnaligned ( int size )
03344 {
03345         if (bg_poolSize + size > bg_poolTail)
03346         {
03347                 Com_Error( ERR_DROP, "BG_AllocUnaligned: buffer exceeded tail (%d > %d)", bg_poolSize + size, bg_poolTail);
03348                 return 0;
03349         }
03350 
03351         bg_poolSize += size;
03352 
03353         return &bg_pool[bg_poolSize-size];
03354 }
03355 
03356 void *BG_TempAlloc( int size )
03357 {
03358         size = ((size + 0x00000003) & 0xfffffffc);
03359 
03360         if (bg_poolTail - size < bg_poolSize)
03361         {
03362                 Com_Error( ERR_DROP, "BG_TempAlloc: buffer exceeded head (%d > %d)", bg_poolTail - size, bg_poolSize);
03363                 return 0;
03364         }
03365 
03366         bg_poolTail -= size;
03367 
03368         return &bg_pool[bg_poolTail];
03369 }
03370 
03371 void BG_TempFree( int size )
03372 {
03373         size = ((size + 0x00000003) & 0xfffffffc);
03374 
03375         if (bg_poolTail+size > MAX_POOL_SIZE)
03376         {
03377                 Com_Error( ERR_DROP, "BG_TempFree: tail greater than size (%d > %d)", bg_poolTail+size, MAX_POOL_SIZE );
03378         }
03379 
03380         bg_poolTail += size;
03381 }
03382 
03383 char *BG_StringAlloc ( const char *source )
03384 {
03385         char *dest;
03386 
03387         dest = BG_Alloc ( strlen ( source ) + 1 );
03388         strcpy ( dest, source );
03389         return dest;
03390 }
03391 
03392 qboolean BG_OutOfMemory ( void )
03393 {
03394         return bg_poolSize >= MAX_POOL_SIZE;
03395 }
03396 
03397 #endif // _XBOX && QAGAME
03398 
03399 #include "../namespace_end.h"