00001
00002
00003
00004 #include "g_local.h"
00005 #include "g_ICARUScb.h"
00006 #include "g_nav.h"
00007 #include "bg_saga.h"
00008
00009 level_locals_t level;
00010
00011 int eventClearTime = 0;
00012 static int navCalcPathTime = 0;
00013 extern int fatalErrors;
00014
00015 int killPlayerTimer = 0;
00016
00017 typedef struct {
00018 vmCvar_t *vmCvar;
00019 char *cvarName;
00020 char *defaultString;
00021 int cvarFlags;
00022 int modificationCount;
00023 qboolean trackChange;
00024 qboolean teamShader;
00025 } cvarTable_t;
00026
00027 gentity_t g_entities[MAX_GENTITIES];
00028 gclient_t g_clients[MAX_CLIENTS];
00029
00030 qboolean gDuelExit = qfalse;
00031
00032 vmCvar_t g_trueJedi;
00033
00034 vmCvar_t g_gametype;
00035 vmCvar_t g_MaxHolocronCarry;
00036 vmCvar_t g_ff_objectives;
00037 vmCvar_t g_autoMapCycle;
00038 vmCvar_t g_dmflags;
00039 vmCvar_t g_maxForceRank;
00040 vmCvar_t g_forceBasedTeams;
00041 vmCvar_t g_privateDuel;
00042
00043 vmCvar_t g_allowNPC;
00044
00045 vmCvar_t g_armBreakage;
00046
00047 vmCvar_t g_saberLocking;
00048 vmCvar_t g_saberLockFactor;
00049 vmCvar_t g_saberTraceSaberFirst;
00050
00051 vmCvar_t d_saberKickTweak;
00052
00053 vmCvar_t d_powerDuelPrint;
00054
00055 vmCvar_t d_saberGhoul2Collision;
00056 vmCvar_t g_saberBladeFaces;
00057 vmCvar_t d_saberAlwaysBoxTrace;
00058 vmCvar_t d_saberBoxTraceSize;
00059
00060 vmCvar_t d_siegeSeekerNPC;
00061
00062 vmCvar_t g_debugMelee;
00063 vmCvar_t g_stepSlideFix;
00064
00065 vmCvar_t g_noSpecMove;
00066
00067 #ifdef _DEBUG
00068 vmCvar_t g_disableServerG2;
00069 #endif
00070
00071 vmCvar_t d_perPlayerGhoul2;
00072
00073 vmCvar_t d_projectileGhoul2Collision;
00074
00075 vmCvar_t g_g2TraceLod;
00076
00077 vmCvar_t g_optvehtrace;
00078
00079 vmCvar_t g_locationBasedDamage;
00080
00081 vmCvar_t g_allowHighPingDuelist;
00082
00083 vmCvar_t g_logClientInfo;
00084
00085 vmCvar_t g_slowmoDuelEnd;
00086
00087 vmCvar_t g_saberDamageScale;
00088
00089 vmCvar_t g_useWhileThrowing;
00090
00091 vmCvar_t g_RMG;
00092
00093 vmCvar_t g_svfps;
00094
00095 vmCvar_t g_forceRegenTime;
00096 vmCvar_t g_spawnInvulnerability;
00097 vmCvar_t g_forcePowerDisable;
00098 vmCvar_t g_weaponDisable;
00099 vmCvar_t g_duelWeaponDisable;
00100 vmCvar_t g_allowDuelSuicide;
00101 vmCvar_t g_fraglimitVoteCorrection;
00102 vmCvar_t g_fraglimit;
00103 vmCvar_t g_duel_fraglimit;
00104 vmCvar_t g_timelimit;
00105 vmCvar_t g_capturelimit;
00106 vmCvar_t d_saberInterpolate;
00107 vmCvar_t g_friendlyFire;
00108 vmCvar_t g_friendlySaber;
00109 vmCvar_t g_password;
00110 vmCvar_t g_needpass;
00111 vmCvar_t g_maxclients;
00112 vmCvar_t g_maxGameClients;
00113 vmCvar_t g_dedicated;
00114 vmCvar_t g_developer;
00115 vmCvar_t g_speed;
00116 vmCvar_t g_gravity;
00117 vmCvar_t g_cheats;
00118 vmCvar_t g_knockback;
00119 vmCvar_t g_quadfactor;
00120 vmCvar_t g_forcerespawn;
00121 vmCvar_t g_siegeRespawn;
00122 vmCvar_t g_inactivity;
00123 vmCvar_t g_debugMove;
00124 #ifndef FINAL_BUILD
00125 vmCvar_t g_debugDamage;
00126 #endif
00127 vmCvar_t g_debugAlloc;
00128 vmCvar_t g_debugServerSkel;
00129 vmCvar_t g_weaponRespawn;
00130 vmCvar_t g_weaponTeamRespawn;
00131 vmCvar_t g_adaptRespawn;
00132 vmCvar_t g_motd;
00133 vmCvar_t g_synchronousClients;
00134 vmCvar_t g_warmup;
00135 vmCvar_t g_doWarmup;
00136 vmCvar_t g_restarted;
00137 vmCvar_t g_log;
00138 vmCvar_t g_logSync;
00139 vmCvar_t g_statLog;
00140 vmCvar_t g_statLogFile;
00141 vmCvar_t g_blood;
00142 vmCvar_t g_podiumDist;
00143 vmCvar_t g_podiumDrop;
00144 vmCvar_t g_allowVote;
00145 vmCvar_t g_teamAutoJoin;
00146 vmCvar_t g_teamForceBalance;
00147 vmCvar_t g_banIPs;
00148 vmCvar_t g_filterBan;
00149 vmCvar_t g_debugForward;
00150 vmCvar_t g_debugRight;
00151 vmCvar_t g_debugUp;
00152 vmCvar_t g_smoothClients;
00153
00154 #include "../namespace_begin.h"
00155 vmCvar_t pmove_fixed;
00156 vmCvar_t pmove_msec;
00157 #include "../namespace_end.h"
00158
00159 vmCvar_t g_listEntity;
00160
00161
00162 vmCvar_t g_singlePlayer;
00163 vmCvar_t g_enableBreath;
00164 vmCvar_t g_dismember;
00165 vmCvar_t g_forceDodge;
00166 vmCvar_t g_timeouttospec;
00167
00168 vmCvar_t g_saberDmgVelocityScale;
00169 vmCvar_t g_saberDmgDelay_Idle;
00170 vmCvar_t g_saberDmgDelay_Wound;
00171
00172 vmCvar_t g_saberDebugPrint;
00173
00174 vmCvar_t g_siegeTeamSwitch;
00175
00176 vmCvar_t bg_fighterAltControl;
00177
00178 #ifdef DEBUG_SABER_BOX
00179 vmCvar_t g_saberDebugBox;
00180 #endif
00181
00182
00183 vmCvar_t d_altRoutes;
00184 vmCvar_t d_patched;
00185
00186 vmCvar_t g_saberRealisticCombat;
00187 vmCvar_t g_saberRestrictForce;
00188 vmCvar_t d_saberSPStyleDamage;
00189 vmCvar_t g_debugSaberLocks;
00190 vmCvar_t g_saberLockRandomNess;
00191
00192 vmCvar_t g_saberWallDamageScale;
00193
00194 vmCvar_t d_saberStanceDebug;
00195
00196 vmCvar_t debugNPCAI;
00197 vmCvar_t debugNPCFreeze;
00198 vmCvar_t debugNPCAimingBeam;
00199 vmCvar_t debugBreak;
00200 vmCvar_t debugNoRoam;
00201 vmCvar_t d_saberCombat;
00202 vmCvar_t d_JediAI;
00203 vmCvar_t d_noGroupAI;
00204 vmCvar_t d_asynchronousGroupAI;
00205 vmCvar_t d_slowmodeath;
00206 vmCvar_t d_noIntermissionWait;
00207
00208 vmCvar_t g_spskill;
00209
00210
00211 vmCvar_t g_siegeTeam1;
00212 vmCvar_t g_siegeTeam2;
00213
00214 vmCvar_t g_austrian;
00215
00216 vmCvar_t g_powerDuelStartHealth;
00217 vmCvar_t g_powerDuelEndHealth;
00218
00219
00220
00221 vmCvar_t g_showDuelHealths;
00222
00223
00224 static cvarTable_t gameCvarTable[] = {
00225
00226 { &g_cheats, "sv_cheats", "", 0, 0, qfalse },
00227
00228 { &g_debugMelee, "g_debugMelee", "0", CVAR_SERVERINFO, 0, qtrue },
00229 { &g_stepSlideFix, "g_stepSlideFix", "1", CVAR_SERVERINFO, 0, qtrue },
00230
00231 { &g_noSpecMove, "g_noSpecMove", "0", CVAR_SERVERINFO, 0, qtrue },
00232
00233
00234 { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
00235 { NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse },
00236 { &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse },
00237 { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
00238
00239
00240 { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse },
00241 { &g_MaxHolocronCarry, "g_MaxHolocronCarry", "3", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse },
00242
00243 { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
00244 { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
00245
00246 { &g_trueJedi, "g_jediVmerc", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qtrue },
00247
00248
00249 { &g_ff_objectives, "g_ff_objectives", "0", CVAR_CHEAT | CVAR_NORESTART, 0, qtrue },
00250
00251 { &g_autoMapCycle, "g_autoMapCycle", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
00252 { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
00253
00254 { &g_maxForceRank, "g_maxForceRank", "6", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse },
00255 { &g_forceBasedTeams, "g_forceBasedTeams", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse },
00256 { &g_privateDuel, "g_privateDuel", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
00257
00258 { &g_allowNPC, "g_allowNPC", "1", CVAR_SERVERINFO | CVAR_CHEAT, 0, qtrue },
00259
00260 { &g_armBreakage, "g_armBreakage", "0", 0, 0, qtrue },
00261
00262 { &g_saberLocking, "g_saberLocking", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
00263 { &g_saberLockFactor, "g_saberLockFactor", "2", CVAR_ARCHIVE, 0, qtrue },
00264 { &g_saberTraceSaberFirst, "g_saberTraceSaberFirst", "0", CVAR_ARCHIVE, 0, qtrue },
00265
00266 { &d_saberKickTweak, "d_saberKickTweak", "1", 0, 0, qtrue },
00267
00268 { &d_powerDuelPrint, "d_powerDuelPrint", "0", 0, qtrue },
00269
00270 { &d_saberGhoul2Collision, "d_saberGhoul2Collision", "1", CVAR_CHEAT, 0, qtrue },
00271 { &g_saberBladeFaces, "g_saberBladeFaces", "1", 0, 0, qtrue },
00272
00273 { &d_saberAlwaysBoxTrace, "d_saberAlwaysBoxTrace", "0", CVAR_CHEAT, 0, qtrue },
00274 { &d_saberBoxTraceSize, "d_saberBoxTraceSize", "0", CVAR_CHEAT, 0, qtrue },
00275
00276 { &d_siegeSeekerNPC, "d_siegeSeekerNPC", "0", CVAR_CHEAT, 0, qtrue },
00277
00278 #ifdef _DEBUG
00279 { &g_disableServerG2, "g_disableServerG2", "0", 0, 0, qtrue },
00280 #endif
00281
00282 { &d_perPlayerGhoul2, "d_perPlayerGhoul2", "0", CVAR_CHEAT, 0, qtrue },
00283
00284 { &d_projectileGhoul2Collision, "d_projectileGhoul2Collision", "1", CVAR_CHEAT, 0, qtrue },
00285
00286 { &g_g2TraceLod, "g_g2TraceLod", "3", 0, 0, qtrue },
00287
00288 { &g_optvehtrace, "com_optvehtrace", "0", 0, 0, qtrue },
00289
00290 { &g_locationBasedDamage, "g_locationBasedDamage", "1", 0, 0, qtrue },
00291
00292 { &g_allowHighPingDuelist, "g_allowHighPingDuelist", "1", 0, 0, qtrue },
00293
00294 { &g_logClientInfo, "g_logClientInfo", "0", CVAR_ARCHIVE, 0, qtrue },
00295
00296 { &g_slowmoDuelEnd, "g_slowmoDuelEnd", "0", CVAR_ARCHIVE, 0, qtrue },
00297
00298 { &g_saberDamageScale, "g_saberDamageScale", "1", CVAR_ARCHIVE, 0, qtrue },
00299
00300 { &g_useWhileThrowing, "g_useWhileThrowing", "1", 0, 0, qtrue },
00301
00302 { &g_RMG, "RMG", "0", 0, 0, qtrue },
00303
00304 { &g_svfps, "sv_fps", "20", 0, 0, qtrue },
00305
00306 { &g_forceRegenTime, "g_forceRegenTime", "200", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
00307
00308 { &g_spawnInvulnerability, "g_spawnInvulnerability", "3000", CVAR_ARCHIVE, 0, qtrue },
00309
00310 { &g_forcePowerDisable, "g_forcePowerDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue },
00311 { &g_weaponDisable, "g_weaponDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue },
00312 { &g_duelWeaponDisable, "g_duelWeaponDisable", "1", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue },
00313
00314 { &g_allowDuelSuicide, "g_allowDuelSuicide", "1", CVAR_ARCHIVE, 0, qtrue },
00315
00316 { &g_fraglimitVoteCorrection, "g_fraglimitVoteCorrection", "1", CVAR_ARCHIVE, 0, qtrue },
00317
00318 { &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
00319 { &g_duel_fraglimit, "duel_fraglimit", "10", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
00320 { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
00321 { &g_capturelimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
00322
00323 { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
00324
00325 { &d_saberInterpolate, "d_saberInterpolate", "0", CVAR_CHEAT, 0, qtrue },
00326
00327 { &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE, 0, qtrue },
00328 { &g_friendlySaber, "g_friendlySaber", "0", CVAR_ARCHIVE, 0, qtrue },
00329
00330 { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE },
00331 { &g_teamForceBalance, "g_teamForceBalance", "0", CVAR_ARCHIVE },
00332
00333 { &g_warmup, "g_warmup", "20", CVAR_ARCHIVE, 0, qtrue },
00334 { &g_doWarmup, "g_doWarmup", "0", 0, 0, qtrue },
00335 { &g_log, "g_log", "games.log", CVAR_ARCHIVE, 0, qfalse },
00336 { &g_logSync, "g_logSync", "0", CVAR_ARCHIVE, 0, qfalse },
00337
00338 { &g_statLog, "g_statLog", "0", CVAR_ARCHIVE, 0, qfalse },
00339 { &g_statLogFile, "g_statLogFile", "statlog.log", CVAR_ARCHIVE, 0, qfalse },
00340
00341 { &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse },
00342
00343 { &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse },
00344 { &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse },
00345
00346 { &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
00347
00348 { &g_dedicated, "dedicated", "0", 0, 0, qfalse },
00349
00350 { &g_developer, "developer", "0", 0, 0, qfalse },
00351
00352 { &g_speed, "g_speed", "250", 0, 0, qtrue },
00353 { &g_gravity, "g_gravity", "800", 0, 0, qtrue },
00354 { &g_knockback, "g_knockback", "1000", 0, 0, qtrue },
00355 { &g_quadfactor, "g_quadfactor", "3", 0, 0, qtrue },
00356 { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue },
00357 { &g_weaponTeamRespawn, "g_weaponTeamRespawn", "5", 0, 0, qtrue },
00358 { &g_adaptRespawn, "g_adaptrespawn", "1", 0, 0, qtrue },
00359 { &g_forcerespawn, "g_forcerespawn", "60", 0, 0, qtrue },
00360 { &g_siegeRespawn, "g_siegeRespawn", "20", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
00361 { &g_inactivity, "g_inactivity", "0", 0, 0, qtrue },
00362 { &g_debugMove, "g_debugMove", "0", 0, 0, qfalse },
00363 #ifndef FINAL_BUILD
00364 { &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse },
00365 #endif
00366 { &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse },
00367 { &g_debugServerSkel, "g_debugServerSkel", "0", CVAR_CHEAT, 0, qfalse },
00368 { &g_motd, "g_motd", "", 0, 0, qfalse },
00369 { &g_blood, "com_blood", "1", 0, 0, qfalse },
00370
00371 { &g_podiumDist, "g_podiumDist", "80", 0, 0, qfalse },
00372 { &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse },
00373
00374 { &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0, qfalse },
00375 { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse },
00376
00377 #if 0
00378 { &g_debugForward, "g_debugForward", "0", 0, 0, qfalse },
00379 { &g_debugRight, "g_debugRight", "0", 0, 0, qfalse },
00380 { &g_debugUp, "g_debugUp", "0", 0, 0, qfalse },
00381 #endif
00382
00383
00384
00385 { &g_singlePlayer, "ui_singlePlayerActive", "", 0, 0, qfalse, qfalse },
00386
00387 { &g_enableBreath, "g_enableBreath", "0", 0, 0, qtrue, qfalse },
00388 { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
00389 { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse},
00390 { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse},
00391
00392 { &g_dismember, "g_dismember", "0", CVAR_ARCHIVE, 0, qtrue },
00393 { &g_forceDodge, "g_forceDodge", "1", 0, 0, qtrue },
00394
00395 { &g_timeouttospec, "g_timeouttospec", "70", CVAR_ARCHIVE, 0, qfalse },
00396
00397 { &g_saberDmgVelocityScale, "g_saberDmgVelocityScale", "0", CVAR_ARCHIVE, 0, qtrue },
00398 { &g_saberDmgDelay_Idle, "g_saberDmgDelay_Idle", "350", CVAR_ARCHIVE, 0, qtrue },
00399 { &g_saberDmgDelay_Wound, "g_saberDmgDelay_Wound", "0", CVAR_ARCHIVE, 0, qtrue },
00400
00401 #ifndef FINAL_BUILD
00402 { &g_saberDebugPrint, "g_saberDebugPrint", "0", CVAR_CHEAT, 0, qfalse },
00403 #endif
00404 { &g_debugSaberLocks, "g_debugSaberLocks", "0", CVAR_CHEAT, 0, qfalse },
00405 { &g_saberLockRandomNess, "g_saberLockRandomNess", "2", CVAR_CHEAT, 0, qfalse },
00406
00407 { &g_saberWallDamageScale, "g_saberWallDamageScale", "0.4", CVAR_SERVERINFO, 0, qfalse },
00408
00409 { &d_saberStanceDebug, "d_saberStanceDebug", "0", 0, 0, qfalse },
00410
00411 { &g_siegeTeamSwitch, "g_siegeTeamSwitch", "1", CVAR_SERVERINFO|CVAR_ARCHIVE, qfalse },
00412
00413 { &bg_fighterAltControl, "bg_fighterAltControl", "0", CVAR_SERVERINFO, 0, qtrue },
00414
00415 #ifdef DEBUG_SABER_BOX
00416 { &g_saberDebugBox, "g_saberDebugBox", "0", CVAR_CHEAT, 0, qfalse },
00417 #endif
00418
00419 { &d_altRoutes, "d_altRoutes", "0", CVAR_CHEAT, 0, qfalse },
00420 { &d_patched, "d_patched", "0", CVAR_CHEAT, 0, qfalse },
00421
00422 { &g_saberRealisticCombat, "g_saberRealisticCombat", "0", CVAR_CHEAT },
00423 { &g_saberRestrictForce, "g_saberRestrictForce", "0", CVAR_CHEAT },
00424 { &d_saberSPStyleDamage, "d_saberSPStyleDamage", "1", CVAR_CHEAT },
00425
00426 { &debugNoRoam, "d_noroam", "0", CVAR_CHEAT },
00427 { &debugNPCAimingBeam, "d_npcaiming", "0", CVAR_CHEAT },
00428 { &debugBreak, "d_break", "0", CVAR_CHEAT },
00429 { &debugNPCAI, "d_npcai", "0", CVAR_CHEAT },
00430 { &debugNPCFreeze, "d_npcfreeze", "0", CVAR_CHEAT },
00431 { &d_JediAI, "d_JediAI", "0", CVAR_CHEAT },
00432 { &d_noGroupAI, "d_noGroupAI", "0", CVAR_CHEAT },
00433 { &d_asynchronousGroupAI, "d_asynchronousGroupAI", "0", CVAR_CHEAT },
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 { &d_slowmodeath, "d_slowmodeath", "0", CVAR_CHEAT },
00444
00445 { &d_saberCombat, "d_saberCombat", "0", CVAR_CHEAT },
00446
00447 { &g_spskill, "g_npcspskill", "0", CVAR_ARCHIVE | CVAR_INTERNAL },
00448
00449
00450 { &g_siegeTeam1, "g_siegeTeam1", "none", CVAR_ARCHIVE|CVAR_SERVERINFO, 0, qfalse },
00451 { &g_siegeTeam2, "g_siegeTeam2", "none", CVAR_ARCHIVE|CVAR_SERVERINFO, 0, qfalse },
00452
00453
00454
00455 { &d_noIntermissionWait, "d_noIntermissionWait", "0", CVAR_CHEAT, 0, qfalse },
00456
00457 { &g_austrian, "g_austrian", "0", CVAR_ARCHIVE, 0, qfalse },
00458
00459
00460 { &g_showDuelHealths, "g_showDuelHealths", "0", CVAR_SERVERINFO },
00461 { &g_powerDuelStartHealth, "g_powerDuelStartHealth", "150", CVAR_ARCHIVE, 0, qtrue },
00462 { &g_powerDuelEndHealth, "g_powerDuelEndHealth", "90", CVAR_ARCHIVE, 0, qtrue },
00463 };
00464
00465
00466 static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );
00467
00468
00469 void G_InitGame ( int levelTime, int randomSeed, int restart );
00470 void G_RunFrame ( int levelTime );
00471 void G_ShutdownGame ( int restart );
00472 void CheckExitRules ( void );
00473 void G_ROFF_NotetrackCallback ( gentity_t *cent, const char *notetrack);
00474
00475 extern stringID_table_t setTable[];
00476
00477 qboolean G_ParseSpawnVars( qboolean inSubBSP );
00478 void G_SpawnGEntityFromSpawnVars( qboolean inSubBSP );
00479
00480
00481 qboolean NAV_ClearPathToPoint( gentity_t *self, vec3_t pmins, vec3_t pmaxs, vec3_t point, int clipmask, int okToHitEntNum );
00482 qboolean NPC_ClearLOS2( gentity_t *ent, const vec3_t end );
00483 int NAVNEW_ClearPathBetweenPoints(vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int ignore, int clipmask);
00484 qboolean NAV_CheckNodeFailedForEnt( gentity_t *ent, int nodeNum );
00485 qboolean G_EntIsUnlockedDoor( int entityNum );
00486 qboolean G_EntIsDoor( int entityNum );
00487 qboolean G_EntIsBreakable( int entityNum );
00488 qboolean G_EntIsRemovableUsable( int entNum );
00489 void CP_FindCombatPointWaypoints( void );
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499 #include "../namespace_begin.h"
00500 #ifdef __linux__
00501 extern "C" {
00502 #endif
00503 int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
00504 switch ( command ) {
00505 case GAME_INIT:
00506 G_InitGame( arg0, arg1, arg2 );
00507 return 0;
00508 case GAME_SHUTDOWN:
00509 G_ShutdownGame( arg0 );
00510 return 0;
00511 case GAME_CLIENT_CONNECT:
00512 return (int)ClientConnect( arg0, arg1, arg2 );
00513 case GAME_CLIENT_THINK:
00514 ClientThink( arg0, NULL );
00515 return 0;
00516 case GAME_CLIENT_USERINFO_CHANGED:
00517 ClientUserinfoChanged( arg0 );
00518 return 0;
00519 case GAME_CLIENT_DISCONNECT:
00520 ClientDisconnect( arg0 );
00521 return 0;
00522 case GAME_CLIENT_BEGIN:
00523 ClientBegin( arg0, qtrue );
00524 return 0;
00525 case GAME_CLIENT_COMMAND:
00526 ClientCommand( arg0 );
00527 return 0;
00528 case GAME_RUN_FRAME:
00529 G_RunFrame( arg0 );
00530 return 0;
00531 case GAME_CONSOLE_COMMAND:
00532 return ConsoleCommand();
00533 case BOTAI_START_FRAME:
00534 return BotAIStartFrame( arg0 );
00535 case GAME_ROFF_NOTETRACK_CALLBACK:
00536 G_ROFF_NotetrackCallback( &g_entities[arg0], (const char *)arg1 );
00537 return 0;
00538 case GAME_SPAWN_RMG_ENTITY:
00539 if (G_ParseSpawnVars(qfalse))
00540 {
00541 G_SpawnGEntityFromSpawnVars(qfalse);
00542 }
00543 return 0;
00544
00545
00546 case GAME_ICARUS_PLAYSOUND:
00547 {
00548 T_G_ICARUS_PLAYSOUND *sharedMem = (T_G_ICARUS_PLAYSOUND *)gSharedBuffer;
00549 return Q3_PlaySound(sharedMem->taskID, sharedMem->entID, sharedMem->name, sharedMem->channel);
00550 }
00551 case GAME_ICARUS_SET:
00552 {
00553 T_G_ICARUS_SET *sharedMem = (T_G_ICARUS_SET *)gSharedBuffer;
00554 return Q3_Set(sharedMem->taskID, sharedMem->entID, sharedMem->type_name, sharedMem->data);
00555 }
00556 case GAME_ICARUS_LERP2POS:
00557 {
00558 T_G_ICARUS_LERP2POS *sharedMem = (T_G_ICARUS_LERP2POS *)gSharedBuffer;
00559 if (sharedMem->nullAngles)
00560 {
00561 Q3_Lerp2Pos(sharedMem->taskID, sharedMem->entID, sharedMem->origin, NULL, sharedMem->duration);
00562 }
00563 else
00564 {
00565 Q3_Lerp2Pos(sharedMem->taskID, sharedMem->entID, sharedMem->origin, sharedMem->angles, sharedMem->duration);
00566 }
00567 }
00568 return 0;
00569 case GAME_ICARUS_LERP2ORIGIN:
00570 {
00571 T_G_ICARUS_LERP2ORIGIN *sharedMem = (T_G_ICARUS_LERP2ORIGIN *)gSharedBuffer;
00572 Q3_Lerp2Origin(sharedMem->taskID, sharedMem->entID, sharedMem->origin, sharedMem->duration);
00573 }
00574 return 0;
00575 case GAME_ICARUS_LERP2ANGLES:
00576 {
00577 T_G_ICARUS_LERP2ANGLES *sharedMem = (T_G_ICARUS_LERP2ANGLES *)gSharedBuffer;
00578 Q3_Lerp2Angles(sharedMem->taskID, sharedMem->entID, sharedMem->angles, sharedMem->duration);
00579 }
00580 return 0;
00581 case GAME_ICARUS_GETTAG:
00582 {
00583 T_G_ICARUS_GETTAG *sharedMem = (T_G_ICARUS_GETTAG *)gSharedBuffer;
00584 return Q3_GetTag(sharedMem->entID, sharedMem->name, sharedMem->lookup, sharedMem->info);
00585 }
00586 case GAME_ICARUS_LERP2START:
00587 {
00588 T_G_ICARUS_LERP2START *sharedMem = (T_G_ICARUS_LERP2START *)gSharedBuffer;
00589 Q3_Lerp2Start(sharedMem->entID, sharedMem->taskID, sharedMem->duration);
00590 }
00591 return 0;
00592 case GAME_ICARUS_LERP2END:
00593 {
00594 T_G_ICARUS_LERP2END *sharedMem = (T_G_ICARUS_LERP2END *)gSharedBuffer;
00595 Q3_Lerp2End(sharedMem->entID, sharedMem->taskID, sharedMem->duration);
00596 }
00597 return 0;
00598 case GAME_ICARUS_USE:
00599 {
00600 T_G_ICARUS_USE *sharedMem = (T_G_ICARUS_USE *)gSharedBuffer;
00601 Q3_Use(sharedMem->entID, sharedMem->target);
00602 }
00603 return 0;
00604 case GAME_ICARUS_KILL:
00605 {
00606 T_G_ICARUS_KILL *sharedMem = (T_G_ICARUS_KILL *)gSharedBuffer;
00607 Q3_Kill(sharedMem->entID, sharedMem->name);
00608 }
00609 return 0;
00610 case GAME_ICARUS_REMOVE:
00611 {
00612 T_G_ICARUS_REMOVE *sharedMem = (T_G_ICARUS_REMOVE *)gSharedBuffer;
00613 Q3_Remove(sharedMem->entID, sharedMem->name);
00614 }
00615 return 0;
00616 case GAME_ICARUS_PLAY:
00617 {
00618 T_G_ICARUS_PLAY *sharedMem = (T_G_ICARUS_PLAY *)gSharedBuffer;
00619 Q3_Play(sharedMem->taskID, sharedMem->entID, sharedMem->type, sharedMem->name);
00620 }
00621 return 0;
00622 case GAME_ICARUS_GETFLOAT:
00623 {
00624 T_G_ICARUS_GETFLOAT *sharedMem = (T_G_ICARUS_GETFLOAT *)gSharedBuffer;
00625 return Q3_GetFloat(sharedMem->entID, sharedMem->type, sharedMem->name, &sharedMem->value);
00626 }
00627 case GAME_ICARUS_GETVECTOR:
00628 {
00629 T_G_ICARUS_GETVECTOR *sharedMem = (T_G_ICARUS_GETVECTOR *)gSharedBuffer;
00630 return Q3_GetVector(sharedMem->entID, sharedMem->type, sharedMem->name, sharedMem->value);
00631 }
00632 case GAME_ICARUS_GETSTRING:
00633 {
00634 T_G_ICARUS_GETSTRING *sharedMem = (T_G_ICARUS_GETSTRING *)gSharedBuffer;
00635 int r;
00636 char *crap = NULL;
00637 char **morecrap = &crap;
00638 r = Q3_GetString(sharedMem->entID, sharedMem->type, sharedMem->name, morecrap);
00639
00640 if (crap)
00641 {
00642 strcpy(sharedMem->value, crap);
00643 }
00644
00645 return r;
00646 }
00647 case GAME_ICARUS_SOUNDINDEX:
00648 {
00649 T_G_ICARUS_SOUNDINDEX *sharedMem = (T_G_ICARUS_SOUNDINDEX *)gSharedBuffer;
00650 G_SoundIndex(sharedMem->filename);
00651 }
00652 return 0;
00653 case GAME_ICARUS_GETSETIDFORSTRING:
00654 {
00655 T_G_ICARUS_GETSETIDFORSTRING *sharedMem = (T_G_ICARUS_GETSETIDFORSTRING *)gSharedBuffer;
00656 return GetIDForString(setTable, sharedMem->string);
00657 }
00658
00659
00660 case GAME_NAV_CLEARPATHTOPOINT:
00661 return NAV_ClearPathToPoint(&g_entities[arg0], (float *)arg1, (float *)arg2, (float *)arg3, arg4, arg5);
00662 case GAME_NAV_CLEARLOS:
00663 return NPC_ClearLOS2(&g_entities[arg0], (const float *)arg1);
00664 case GAME_NAV_CLEARPATHBETWEENPOINTS:
00665 return NAVNEW_ClearPathBetweenPoints((float *)arg0, (float *)arg1, (float *)arg2, (float *)arg3, arg4, arg5);
00666 case GAME_NAV_CHECKNODEFAILEDFORENT:
00667 return NAV_CheckNodeFailedForEnt(&g_entities[arg0], arg1);
00668 case GAME_NAV_ENTISUNLOCKEDDOOR:
00669 return G_EntIsUnlockedDoor(arg0);
00670 case GAME_NAV_ENTISDOOR:
00671 return G_EntIsDoor(arg0);
00672 case GAME_NAV_ENTISBREAKABLE:
00673 return G_EntIsBreakable(arg0);
00674 case GAME_NAV_ENTISREMOVABLEUSABLE:
00675 return G_EntIsRemovableUsable(arg0);
00676 case GAME_NAV_FINDCOMBATPOINTWAYPOINTS:
00677 CP_FindCombatPointWaypoints();
00678 return 0;
00679 case GAME_GETITEMINDEXBYTAG:
00680 return BG_GetItemIndexByTag(arg0, arg1);
00681 }
00682
00683 return -1;
00684 }
00685 #ifdef __linux__
00686 }
00687 #endif
00688 #include "../namespace_end.h"
00689
00690
00691 void QDECL G_Printf( const char *fmt, ... ) {
00692 va_list argptr;
00693 char text[1024];
00694
00695 va_start (argptr, fmt);
00696 vsprintf (text, fmt, argptr);
00697 va_end (argptr);
00698
00699 trap_Printf( text );
00700 }
00701
00702 void QDECL G_Error( const char *fmt, ... ) {
00703 va_list argptr;
00704 char text[1024];
00705
00706 va_start (argptr, fmt);
00707 vsprintf (text, fmt, argptr);
00708 va_end (argptr);
00709
00710 trap_Error( text );
00711 }
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724 void G_FindTeams( void ) {
00725 gentity_t *e, *e2;
00726 int i, j;
00727 int c, c2;
00728
00729 c = 0;
00730 c2 = 0;
00731 for ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){
00732 if (!e->inuse)
00733 continue;
00734 if (!e->team)
00735 continue;
00736 if (e->flags & FL_TEAMSLAVE)
00737 continue;
00738 if (e->r.contents==CONTENTS_TRIGGER)
00739 continue;
00740 e->teammaster = e;
00741 c++;
00742 c2++;
00743 for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)
00744 {
00745 if (!e2->inuse)
00746 continue;
00747 if (!e2->team)
00748 continue;
00749 if (e2->flags & FL_TEAMSLAVE)
00750 continue;
00751 if (!strcmp(e->team, e2->team))
00752 {
00753 c2++;
00754 e2->teamchain = e->teamchain;
00755 e->teamchain = e2;
00756 e2->teammaster = e;
00757 e2->flags |= FL_TEAMSLAVE;
00758
00759
00760 if ( e2->targetname ) {
00761 e->targetname = e2->targetname;
00762 e2->targetname = NULL;
00763 }
00764 }
00765 }
00766 }
00767
00768
00769 }
00770
00771 void G_RemapTeamShaders( void ) {
00772 #if 0
00773 char string[1024];
00774 float f = level.time * 0.001;
00775 Com_sprintf( string, sizeof(string), "team_icon/%s_red", g_redteam.string );
00776 AddRemap("textures/ctf2/redteam01", string, f);
00777 AddRemap("textures/ctf2/redteam02", string, f);
00778 Com_sprintf( string, sizeof(string), "team_icon/%s_blue", g_blueteam.string );
00779 AddRemap("textures/ctf2/blueteam01", string, f);
00780 AddRemap("textures/ctf2/blueteam02", string, f);
00781 trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
00782 #endif
00783 }
00784
00785
00786
00787
00788
00789
00790
00791 void G_RegisterCvars( void ) {
00792 int i;
00793 cvarTable_t *cv;
00794 qboolean remapped = qfalse;
00795
00796 for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
00797 trap_Cvar_Register( cv->vmCvar, cv->cvarName,
00798 cv->defaultString, cv->cvarFlags );
00799 if ( cv->vmCvar )
00800 cv->modificationCount = cv->vmCvar->modificationCount;
00801
00802 if (cv->teamShader) {
00803 remapped = qtrue;
00804 }
00805 }
00806
00807 if (remapped) {
00808 G_RemapTeamShaders();
00809 }
00810
00811
00812 if ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) {
00813 G_Printf( "g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer );
00814 trap_Cvar_Set( "g_gametype", "0" );
00815 }
00816 else if (g_gametype.integer == GT_HOLOCRON)
00817 {
00818 G_Printf( "This gametype is not supported.\n" );
00819 trap_Cvar_Set( "g_gametype", "0" );
00820 }
00821 else if (g_gametype.integer == GT_JEDIMASTER)
00822 {
00823 G_Printf( "This gametype is not supported.\n" );
00824 trap_Cvar_Set( "g_gametype", "0" );
00825 }
00826 else if (g_gametype.integer == GT_CTY)
00827 {
00828 G_Printf( "This gametype is not supported.\n" );
00829 trap_Cvar_Set( "g_gametype", "0" );
00830 }
00831
00832 level.warmupModificationCount = g_warmup.modificationCount;
00833 }
00834
00835
00836
00837
00838
00839
00840 void G_UpdateCvars( void ) {
00841 int i;
00842 cvarTable_t *cv;
00843 qboolean remapped = qfalse;
00844
00845 for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
00846 if ( cv->vmCvar ) {
00847 trap_Cvar_Update( cv->vmCvar );
00848
00849 if ( cv->modificationCount != cv->vmCvar->modificationCount ) {
00850 cv->modificationCount = cv->vmCvar->modificationCount;
00851
00852 if ( cv->trackChange ) {
00853 trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"",
00854 cv->cvarName, cv->vmCvar->string ) );
00855 }
00856
00857 if (cv->teamShader) {
00858 remapped = qtrue;
00859 }
00860 }
00861 }
00862 }
00863
00864 if (remapped) {
00865 G_RemapTeamShaders();
00866 }
00867 }
00868
00869 char gSharedBuffer[MAX_G_SHARED_BUFFER_SIZE];
00870
00871 #include "../namespace_begin.h"
00872 void WP_SaberLoadParms( void );
00873 void BG_VehicleLoadParms( void );
00874 #include "../namespace_end.h"
00875
00876
00877
00878
00879
00880
00881
00882 extern void RemoveAllWP(void);
00883 extern void BG_ClearVehicleParseParms(void);
00884 void G_InitGame( int levelTime, int randomSeed, int restart ) {
00885 int i;
00886 vmCvar_t mapname;
00887 vmCvar_t ckSum;
00888
00889 #ifdef _XBOX
00890 if(restart) {
00891 BG_ClearVehicleParseParms();
00892 RemoveAllWP();
00893 }
00894 #endif
00895
00896
00897 trap_Cvar_Set("RMG", "0");
00898 g_RMG.integer = 0;
00899
00900
00901 trap_G2API_CleanEntAttachments();
00902
00903 BG_InitAnimsets();
00904
00905 B_InitAlloc();
00906
00907 trap_SV_RegisterSharedMemory(gSharedBuffer);
00908
00909
00910 BG_VehicleLoadParms();
00911
00912 G_Printf ("------- Game Initialization -------\n");
00913 G_Printf ("gamename: %s\n", GAMEVERSION);
00914 G_Printf ("gamedate: %s\n", __DATE__);
00915
00916 srand( randomSeed );
00917
00918 G_RegisterCvars();
00919
00920 G_ProcessIPBans();
00921
00922 G_InitMemory();
00923
00924
00925 memset( &level, 0, sizeof( level ) );
00926 level.time = levelTime;
00927 level.startTime = levelTime;
00928
00929 level.snd_fry = G_SoundIndex("sound/player/fry.wav");
00930
00931 level.snd_hack = G_SoundIndex("sound/player/hacking.wav");
00932 level.snd_medHealed = G_SoundIndex("sound/player/supp_healed.wav");
00933 level.snd_medSupplied = G_SoundIndex("sound/player/supp_supplied.wav");
00934
00935
00936
00937 #ifndef _XBOX
00938 if ( g_log.string[0] ) {
00939 if ( g_logSync.integer ) {
00940 trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_SYNC );
00941 } else {
00942 trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND );
00943 }
00944 if ( !level.logFile ) {
00945 G_Printf( "WARNING: Couldn't open logfile: %s\n", g_log.string );
00946 } else {
00947 char serverinfo[MAX_INFO_STRING];
00948
00949 trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
00950
00951 G_LogPrintf("------------------------------------------------------------\n" );
00952 G_LogPrintf("InitGame: %s\n", serverinfo );
00953 }
00954 } else {
00955 G_Printf( "Not logging to disk.\n" );
00956 }
00957 #endif
00958
00959 G_LogWeaponInit();
00960
00961 G_InitWorldSession();
00962
00963
00964 memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
00965 level.gentities = g_entities;
00966
00967
00968 level.maxclients = g_maxclients.integer;
00969 memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
00970 level.clients = g_clients;
00971
00972
00973 for ( i=0 ; i<level.maxclients ; i++ ) {
00974 g_entities[i].client = level.clients + i;
00975 }
00976
00977
00978
00979
00980 level.num_entities = MAX_CLIENTS;
00981
00982
00983 trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
00984 &level.clients[0].ps, sizeof( level.clients[0] ) );
00985
00986
00987 WP_SaberLoadParms();
00988
00989 NPC_InitGame();
00990
00991 TIMER_Clear();
00992
00993
00994
00995
00996
00997 trap_ICARUS_Init();
00998
00999
01000
01001
01002
01003
01004
01005 InitBodyQue();
01006
01007 ClearRegisteredItems();
01008
01009
01010 InitSiegeMode();
01011
01012 trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
01013 trap_Cvar_Register( &ckSum, "sv_mapChecksum", "", CVAR_ROM );
01014
01015 navCalculatePaths = ( trap_Nav_Load( mapname.string, ckSum.integer ) == qfalse );
01016
01017
01018 G_SpawnEntitiesFromString(qfalse);
01019
01020
01021 G_FindTeams();
01022
01023
01024 if( g_gametype.integer >= GT_TEAM ) {
01025 G_CheckTeamItems();
01026 }
01027 else if ( g_gametype.integer == GT_JEDIMASTER )
01028 {
01029 trap_SetConfigstring ( CS_CLIENT_JEDIMASTER, "-1" );
01030 }
01031
01032 if (g_gametype.integer == GT_POWERDUEL)
01033 {
01034 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("-1|-1|-1") );
01035 }
01036 else
01037 {
01038 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("-1|-1") );
01039 }
01040
01041 trap_SetConfigstring ( CS_CLIENT_DUELHEALTHS, va("-1|-1|!") );
01042 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("-1") );
01043
01044 SaveRegisteredItems();
01045
01046
01047
01048 if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
01049 G_ModelIndex( SP_PODIUM_MODEL );
01050 G_SoundIndex( "sound/player/gurp1.wav" );
01051 G_SoundIndex( "sound/player/gurp2.wav" );
01052 }
01053
01054 if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
01055 BotAISetup( restart );
01056 BotAILoadMap( restart );
01057 G_InitBots( restart );
01058 }
01059
01060 G_RemapTeamShaders();
01061
01062 if ( g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL )
01063 {
01064 G_LogPrintf("Duel Tournament Begun: kill limit %d, win limit: %d\n", g_fraglimit.integer, g_duel_fraglimit.integer );
01065 }
01066
01067 if ( navCalculatePaths )
01068 {
01069 navCalcPathTime = level.time + START_TIME_NAV_CALC;
01070 }
01071 else
01072 {
01073
01074
01075
01076
01077 trap_Nav_SetPathsCalculated(qtrue);
01078
01079 CP_FindCombatPointWaypoints();
01080 navCalcPathTime = 0;
01081
01082
01083
01084
01085
01086
01087
01088
01089 }
01090
01091 if (g_gametype.integer == GT_SIEGE)
01092 {
01093 int i = 0;
01094 while (i < MAX_CUSTOM_SIEGE_SOUNDS)
01095 {
01096 if (!bg_customSiegeSoundNames[i])
01097 {
01098 break;
01099 }
01100 G_SoundIndex((char *)bg_customSiegeSoundNames[i]);
01101 i++;
01102 }
01103 }
01104 }
01105
01106
01107
01108
01109
01110
01111
01112
01113 void G_ShutdownGame( int restart ) {
01114 int i = 0;
01115 gentity_t *ent;
01116
01117
01118
01119 G_CleanAllFakeClients();
01120
01121 BG_ClearAnimsets();
01122
01123
01124 while (i < MAX_GENTITIES)
01125 {
01126 ent = &g_entities[i];
01127
01128 if (ent->ghoul2 && trap_G2_HaveWeGhoul2Models(ent->ghoul2))
01129 {
01130 trap_G2API_CleanGhoul2Models(&ent->ghoul2);
01131 ent->ghoul2 = NULL;
01132 }
01133 if (ent->client)
01134 {
01135 int j = 0;
01136
01137 while (j < MAX_SABERS)
01138 {
01139 if (ent->client->weaponGhoul2[j] && trap_G2_HaveWeGhoul2Models(ent->client->weaponGhoul2[j]))
01140 {
01141 trap_G2API_CleanGhoul2Models(&ent->client->weaponGhoul2[j]);
01142 }
01143 j++;
01144 }
01145 }
01146 i++;
01147 }
01148 if (g2SaberInstance && trap_G2_HaveWeGhoul2Models(g2SaberInstance))
01149 {
01150 trap_G2API_CleanGhoul2Models(&g2SaberInstance);
01151 g2SaberInstance = NULL;
01152 }
01153 if (precachedKyle && trap_G2_HaveWeGhoul2Models(precachedKyle))
01154 {
01155 trap_G2API_CleanGhoul2Models(&precachedKyle);
01156 precachedKyle = NULL;
01157 }
01158
01159
01160 trap_ICARUS_Shutdown ();
01161
01162
01163 TAG_Init();
01164
01165 G_LogWeaponOutput();
01166
01167 if ( level.logFile ) {
01168 G_LogPrintf("ShutdownGame:\n" );
01169 G_LogPrintf("------------------------------------------------------------\n" );
01170 trap_FS_FCloseFile( level.logFile );
01171 }
01172
01173
01174 G_WriteSessionData();
01175
01176 trap_ROFF_Clean();
01177
01178 if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
01179 BotAIShutdown( restart );
01180 }
01181
01182 B_CleanupAlloc();
01183 }
01184
01185
01186
01187
01188
01189 #ifndef GAME_HARD_LINKED
01190
01191
01192 void QDECL Com_Error ( int level, const char *error, ... ) {
01193 va_list argptr;
01194 char text[1024];
01195
01196 va_start (argptr, error);
01197 vsprintf (text, error, argptr);
01198 va_end (argptr);
01199
01200 G_Error( "%s", text);
01201 }
01202
01203 void QDECL Com_Printf( const char *msg, ... ) {
01204 va_list argptr;
01205 char text[1024];
01206
01207 va_start (argptr, msg);
01208 vsprintf (text, msg, argptr);
01209 va_end (argptr);
01210
01211 G_Printf ("%s", text);
01212 }
01213
01214 #endif
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232 void AddTournamentPlayer( void ) {
01233 int i;
01234 gclient_t *client;
01235 gclient_t *nextInLine;
01236
01237 if ( level.numPlayingClients >= 2 ) {
01238 return;
01239 }
01240
01241
01242
01243
01244
01245
01246 nextInLine = NULL;
01247
01248 for ( i = 0 ; i < level.maxclients ; i++ ) {
01249 client = &level.clients[i];
01250 if ( client->pers.connected != CON_CONNECTED ) {
01251 continue;
01252 }
01253 if (!g_allowHighPingDuelist.integer && client->ps.ping >= 999)
01254 {
01255 continue;
01256 }
01257 if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
01258 continue;
01259 }
01260
01261 if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ||
01262 client->sess.spectatorClient < 0 ) {
01263 continue;
01264 }
01265
01266 if ( !nextInLine || client->sess.spectatorTime < nextInLine->sess.spectatorTime ) {
01267 nextInLine = client;
01268 }
01269 }
01270
01271 if ( !nextInLine ) {
01272 return;
01273 }
01274
01275 level.warmupTime = -1;
01276
01277
01278 SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
01279 }
01280
01281
01282
01283
01284
01285
01286
01287
01288 void RemoveTournamentLoser( void ) {
01289 int clientNum;
01290
01291 if ( level.numPlayingClients != 2 ) {
01292 return;
01293 }
01294
01295 clientNum = level.sortedClients[1];
01296
01297 if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
01298 return;
01299 }
01300
01301
01302 SetTeam( &g_entities[ clientNum ], "s" );
01303 }
01304
01305 void G_PowerDuelCount(int *loners, int *doubles, qboolean countSpec)
01306 {
01307 int i = 0;
01308 gclient_t *cl;
01309
01310 while (i < MAX_CLIENTS)
01311 {
01312 cl = g_entities[i].client;
01313
01314 if (g_entities[i].inuse && cl && (countSpec || cl->sess.sessionTeam != TEAM_SPECTATOR))
01315 {
01316 if (cl->sess.duelTeam == DUELTEAM_LONE)
01317 {
01318 (*loners)++;
01319 }
01320 else if (cl->sess.duelTeam == DUELTEAM_DOUBLE)
01321 {
01322 (*doubles)++;
01323 }
01324 }
01325 i++;
01326 }
01327 }
01328
01329 qboolean g_duelAssigning = qfalse;
01330 void AddPowerDuelPlayers( void )
01331 {
01332 int i;
01333 int loners = 0;
01334 int doubles = 0;
01335 int nonspecLoners = 0;
01336 int nonspecDoubles = 0;
01337 gclient_t *client;
01338 gclient_t *nextInLine;
01339
01340 if ( level.numPlayingClients >= 3 )
01341 {
01342 return;
01343 }
01344
01345 nextInLine = NULL;
01346
01347 G_PowerDuelCount(&nonspecLoners, &nonspecDoubles, qfalse);
01348 if (nonspecLoners >= 1 && nonspecDoubles >= 2)
01349 {
01350 return;
01351 }
01352
01353
01354 G_PowerDuelCount(&loners, &doubles, qtrue);
01355
01356 if (loners < 1 || doubles < 2)
01357 {
01358 return;
01359 }
01360
01361
01362 loners = nonspecLoners;
01363 doubles = nonspecDoubles;
01364
01365
01366 for ( i = 0 ; i < level.maxclients ; i++ ) {
01367 client = &level.clients[i];
01368 if ( client->pers.connected != CON_CONNECTED ) {
01369 continue;
01370 }
01371 if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
01372 continue;
01373 }
01374 if (client->sess.duelTeam == DUELTEAM_FREE)
01375 {
01376 continue;
01377 }
01378 if (client->sess.duelTeam == DUELTEAM_LONE && loners >= 1)
01379 {
01380 continue;
01381 }
01382 if (client->sess.duelTeam == DUELTEAM_DOUBLE && doubles >= 2)
01383 {
01384 continue;
01385 }
01386
01387
01388 if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ||
01389 client->sess.spectatorClient < 0 ) {
01390 continue;
01391 }
01392
01393 if ( !nextInLine || client->sess.spectatorTime < nextInLine->sess.spectatorTime ) {
01394 nextInLine = client;
01395 }
01396 }
01397
01398 if ( !nextInLine ) {
01399 return;
01400 }
01401
01402 level.warmupTime = -1;
01403
01404
01405 SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
01406
01407
01408 AddPowerDuelPlayers();
01409 }
01410
01411 qboolean g_dontFrickinCheck = qfalse;
01412
01413 void RemovePowerDuelLosers(void)
01414 {
01415 int remClients[3];
01416 int remNum = 0;
01417 int i = 0;
01418 gclient_t *cl;
01419
01420 while (i < MAX_CLIENTS && remNum < 3)
01421 {
01422
01423 cl = &level.clients[i];
01424
01425 if (cl->pers.connected == CON_CONNECTED)
01426 {
01427 if ((cl->ps.stats[STAT_HEALTH] <= 0 || cl->iAmALoser) &&
01428 (cl->sess.sessionTeam != TEAM_SPECTATOR || cl->iAmALoser))
01429 {
01430 remClients[remNum] = cl->ps.clientNum;
01431 remNum++;
01432 }
01433 }
01434
01435 i++;
01436 }
01437
01438 if (!remNum)
01439 {
01440 remClients[remNum] = level.sortedClients[0];
01441 remNum++;
01442 }
01443
01444 i = 0;
01445 while (i < remNum)
01446 {
01447 SetTeam( &g_entities[ remClients[i] ], "s" );
01448 i++;
01449 }
01450
01451 g_dontFrickinCheck = qfalse;
01452
01453
01454 CalculateRanks();
01455 }
01456
01457 void RemoveDuelDrawLoser(void)
01458 {
01459 int clFirst = 0;
01460 int clSec = 0;
01461 int clFailure = 0;
01462
01463 if ( level.clients[ level.sortedClients[0] ].pers.connected != CON_CONNECTED )
01464 {
01465 return;
01466 }
01467 if ( level.clients[ level.sortedClients[1] ].pers.connected != CON_CONNECTED )
01468 {
01469 return;
01470 }
01471
01472 clFirst = level.clients[ level.sortedClients[0] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[0] ].ps.stats[STAT_ARMOR];
01473 clSec = level.clients[ level.sortedClients[1] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[1] ].ps.stats[STAT_ARMOR];
01474
01475 if (clFirst > clSec)
01476 {
01477 clFailure = 1;
01478 }
01479 else if (clSec > clFirst)
01480 {
01481 clFailure = 0;
01482 }
01483 else
01484 {
01485 clFailure = 2;
01486 }
01487
01488 if (clFailure != 2)
01489 {
01490 SetTeam( &g_entities[ level.sortedClients[clFailure] ], "s" );
01491 }
01492 else
01493 {
01494 SetTeam( &g_entities[ level.sortedClients[1] ], "s" );
01495 }
01496 }
01497
01498
01499
01500
01501
01502
01503 void RemoveTournamentWinner( void ) {
01504 int clientNum;
01505
01506 if ( level.numPlayingClients != 2 ) {
01507 return;
01508 }
01509
01510 clientNum = level.sortedClients[0];
01511
01512 if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
01513 return;
01514 }
01515
01516
01517 SetTeam( &g_entities[ clientNum ], "s" );
01518 }
01519
01520
01521
01522
01523
01524
01525 void AdjustTournamentScores( void ) {
01526 int clientNum;
01527
01528 if (level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE] ==
01529 level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE] &&
01530 level.clients[level.sortedClients[0]].pers.connected == CON_CONNECTED &&
01531 level.clients[level.sortedClients[1]].pers.connected == CON_CONNECTED)
01532 {
01533 int clFirst = level.clients[ level.sortedClients[0] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[0] ].ps.stats[STAT_ARMOR];
01534 int clSec = level.clients[ level.sortedClients[1] ].ps.stats[STAT_HEALTH] + level.clients[ level.sortedClients[1] ].ps.stats[STAT_ARMOR];
01535 int clFailure = 0;
01536 int clSuccess = 0;
01537
01538 if (clFirst > clSec)
01539 {
01540 clFailure = 1;
01541 clSuccess = 0;
01542 }
01543 else if (clSec > clFirst)
01544 {
01545 clFailure = 0;
01546 clSuccess = 1;
01547 }
01548 else
01549 {
01550 clFailure = 2;
01551 clSuccess = 2;
01552 }
01553
01554 if (clFailure != 2)
01555 {
01556 clientNum = level.sortedClients[clSuccess];
01557
01558 level.clients[ clientNum ].sess.wins++;
01559 ClientUserinfoChanged( clientNum );
01560 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) );
01561
01562 clientNum = level.sortedClients[clFailure];
01563
01564 level.clients[ clientNum ].sess.losses++;
01565 ClientUserinfoChanged( clientNum );
01566 }
01567 else
01568 {
01569 clSuccess = 0;
01570 clFailure = 1;
01571
01572 clientNum = level.sortedClients[clSuccess];
01573
01574 level.clients[ clientNum ].sess.wins++;
01575 ClientUserinfoChanged( clientNum );
01576 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) );
01577
01578 clientNum = level.sortedClients[clFailure];
01579
01580 level.clients[ clientNum ].sess.losses++;
01581 ClientUserinfoChanged( clientNum );
01582 }
01583 }
01584 else
01585 {
01586 clientNum = level.sortedClients[0];
01587 if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
01588 level.clients[ clientNum ].sess.wins++;
01589 ClientUserinfoChanged( clientNum );
01590
01591 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) );
01592 }
01593
01594 clientNum = level.sortedClients[1];
01595 if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
01596 level.clients[ clientNum ].sess.losses++;
01597 ClientUserinfoChanged( clientNum );
01598 }
01599 }
01600 }
01601
01602
01603
01604
01605
01606
01607
01608 int QDECL SortRanks( const void *a, const void *b ) {
01609 gclient_t *ca, *cb;
01610
01611 ca = &level.clients[*(int *)a];
01612 cb = &level.clients[*(int *)b];
01613
01614 if (g_gametype.integer == GT_POWERDUEL)
01615 {
01616
01617 if (ca->sess.duelTeam == DUELTEAM_LONE && ca->sess.sessionTeam != TEAM_SPECTATOR)
01618 {
01619 return -1;
01620 }
01621 if (cb->sess.duelTeam == DUELTEAM_LONE && cb->sess.sessionTeam != TEAM_SPECTATOR)
01622 {
01623 return 1;
01624 }
01625
01626
01627 }
01628
01629
01630 if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {
01631 return 1;
01632 }
01633 if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0 ) {
01634 return -1;
01635 }
01636
01637
01638 if ( ca->pers.connected == CON_CONNECTING ) {
01639 return 1;
01640 }
01641 if ( cb->pers.connected == CON_CONNECTING ) {
01642 return -1;
01643 }
01644
01645
01646
01647 if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {
01648 if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) {
01649 return -1;
01650 }
01651 if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) {
01652 return 1;
01653 }
01654 return 0;
01655 }
01656 if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {
01657 return 1;
01658 }
01659 if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {
01660 return -1;
01661 }
01662
01663
01664 if ( ca->ps.persistant[PERS_SCORE]
01665 > cb->ps.persistant[PERS_SCORE] ) {
01666 return -1;
01667 }
01668 if ( ca->ps.persistant[PERS_SCORE]
01669 < cb->ps.persistant[PERS_SCORE] ) {
01670 return 1;
01671 }
01672 return 0;
01673 }
01674
01675 qboolean gQueueScoreMessage = qfalse;
01676 int gQueueScoreMessageTime = 0;
01677
01678
01679 qboolean G_CanResetDuelists(void)
01680 {
01681 int i;
01682 gentity_t *ent;
01683
01684 i = 0;
01685 while (i < 3)
01686 {
01687 ent = &g_entities[level.sortedClients[i]];
01688
01689 if (!ent->inuse || !ent->client || ent->health <= 0 ||
01690 ent->client->sess.sessionTeam == TEAM_SPECTATOR ||
01691 ent->client->sess.duelTeam <= DUELTEAM_FREE)
01692 {
01693 return qfalse;
01694 }
01695 i++;
01696 }
01697
01698 return qtrue;
01699 }
01700
01701 qboolean g_noPDuelCheck = qfalse;
01702 void G_ResetDuelists(void)
01703 {
01704 int i;
01705 gentity_t *ent;
01706 gentity_t *tent;
01707
01708 i = 0;
01709 while (i < 3)
01710 {
01711 ent = &g_entities[level.sortedClients[i]];
01712
01713 g_noPDuelCheck = qtrue;
01714 player_die(ent, ent, ent, 999, MOD_SUICIDE);
01715 g_noPDuelCheck = qfalse;
01716 trap_UnlinkEntity (ent);
01717 ClientSpawn(ent);
01718
01719
01720 tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
01721 tent->s.clientNum = ent->s.clientNum;
01722 i++;
01723 }
01724 }
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735 void CalculateRanks( void ) {
01736 int i;
01737 int rank;
01738 int score;
01739 int newScore;
01740 int preNumSpec = 0;
01741
01742 gclient_t *cl;
01743
01744 preNumSpec = level.numNonSpectatorClients;
01745
01746 level.follow1 = -1;
01747 level.follow2 = -1;
01748 level.numConnectedClients = 0;
01749 level.numNonSpectatorClients = 0;
01750 level.numPlayingClients = 0;
01751 level.numVotingClients = 0;
01752 for ( i = 0; i < TEAM_NUM_TEAMS; i++ ) {
01753 level.numteamVotingClients[i] = 0;
01754 }
01755 for ( i = 0 ; i < level.maxclients ; i++ ) {
01756 if ( level.clients[i].pers.connected != CON_DISCONNECTED ) {
01757 level.sortedClients[level.numConnectedClients] = i;
01758 level.numConnectedClients++;
01759
01760 if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR || g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL )
01761 {
01762 if (level.clients[i].sess.sessionTeam != TEAM_SPECTATOR)
01763 {
01764 level.numNonSpectatorClients++;
01765
01766 }
01767
01768
01769 if ( level.clients[i].pers.connected == CON_CONNECTED )
01770 {
01771 if (level.clients[i].sess.sessionTeam != TEAM_SPECTATOR || level.clients[i].iAmALoser)
01772 {
01773 level.numPlayingClients++;
01774 }
01775 if ( !(g_entities[i].r.svFlags & SVF_BOT) )
01776 {
01777 level.numVotingClients++;
01778 if ( level.clients[i].sess.sessionTeam == TEAM_RED )
01779 level.numteamVotingClients[0]++;
01780 else if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )
01781 level.numteamVotingClients[1]++;
01782 }
01783 if ( level.follow1 == -1 ) {
01784 level.follow1 = i;
01785 } else if ( level.follow2 == -1 ) {
01786 level.follow2 = i;
01787 }
01788 }
01789 }
01790 }
01791 }
01792
01793
01794 if (1)
01795 {
01796 level.warmupTime = 0;
01797 }
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813 qsort( level.sortedClients, level.numConnectedClients,
01814 sizeof(level.sortedClients[0]), SortRanks );
01815
01816
01817 if ( g_gametype.integer >= GT_TEAM ) {
01818
01819 for ( i = 0; i < level.numConnectedClients; i++ ) {
01820 cl = &level.clients[ level.sortedClients[i] ];
01821 if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {
01822 cl->ps.persistant[PERS_RANK] = 2;
01823 } else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {
01824 cl->ps.persistant[PERS_RANK] = 0;
01825 } else {
01826 cl->ps.persistant[PERS_RANK] = 1;
01827 }
01828 }
01829 } else {
01830 rank = -1;
01831 score = 0;
01832 for ( i = 0; i < level.numPlayingClients; i++ ) {
01833 cl = &level.clients[ level.sortedClients[i] ];
01834 newScore = cl->ps.persistant[PERS_SCORE];
01835 if ( i == 0 || newScore != score ) {
01836 rank = i;
01837
01838 level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
01839 } else {
01840
01841 level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
01842 level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
01843 }
01844 score = newScore;
01845 if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {
01846 level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
01847 }
01848 }
01849 }
01850
01851
01852 if ( g_gametype.integer >= GT_TEAM ) {
01853 trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) );
01854 trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) );
01855 } else {
01856 if ( level.numConnectedClients == 0 ) {
01857 trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) );
01858 trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
01859 } else if ( level.numConnectedClients == 1 ) {
01860 trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
01861 trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
01862 } else {
01863 trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
01864 trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );
01865 }
01866
01867 if (g_gametype.integer != GT_DUEL || g_gametype.integer != GT_POWERDUEL)
01868 {
01869 if ( level.numConnectedClients >= 1 )
01870 {
01871 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", level.sortedClients[0] ) );
01872 }
01873 else
01874 {
01875 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" );
01876 }
01877 }
01878 }
01879
01880
01881 CheckExitRules();
01882
01883
01884 if ( level.intermissiontime || g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL ) {
01885 gQueueScoreMessage = qtrue;
01886 gQueueScoreMessageTime = level.time + 500;
01887
01888
01889 }
01890 }
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909 void SendScoreboardMessageToAllClients( void ) {
01910 int i;
01911
01912 for ( i = 0 ; i < level.maxclients ; i++ ) {
01913 if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
01914 DeathmatchScoreboardMessage( g_entities + i );
01915 }
01916 }
01917 }
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927 void MoveClientToIntermission( gentity_t *ent ) {
01928
01929 if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
01930 StopFollowing( ent );
01931 }
01932
01933
01934
01935 VectorCopy( level.intermission_origin, ent->s.origin );
01936 VectorCopy( level.intermission_origin, ent->client->ps.origin );
01937 VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
01938 ent->client->ps.pm_type = PM_INTERMISSION;
01939
01940
01941 memset( ent->client->ps.powerups, 0, sizeof(ent->client->ps.powerups) );
01942
01943 ent->client->ps.eFlags = 0;
01944 ent->s.eFlags = 0;
01945 ent->s.eType = ET_GENERAL;
01946 ent->s.modelindex = 0;
01947 ent->s.loopSound = 0;
01948 ent->s.loopIsSoundset = qfalse;
01949 ent->s.event = 0;
01950 ent->r.contents = 0;
01951 }
01952
01953
01954
01955
01956
01957
01958
01959
01960 extern qboolean gSiegeRoundBegun;
01961 extern qboolean gSiegeRoundEnded;
01962 extern qboolean gSiegeRoundWinningTeam;
01963 void FindIntermissionPoint( void ) {
01964 gentity_t *ent = NULL;
01965 gentity_t *target;
01966 vec3_t dir;
01967
01968
01969 if ( g_gametype.integer == GT_SIEGE
01970 && level.intermissiontime
01971 && level.intermissiontime <= level.time
01972 && gSiegeRoundEnded )
01973 {
01974 if (gSiegeRoundWinningTeam == SIEGETEAM_TEAM1)
01975 {
01976 ent = G_Find (NULL, FOFS(classname), "info_player_intermission_red");
01977 if ( ent && ent->target2 )
01978 {
01979 G_UseTargets2( ent, ent, ent->target2 );
01980 }
01981 }
01982 else if (gSiegeRoundWinningTeam == SIEGETEAM_TEAM2)
01983 {
01984 ent = G_Find (NULL, FOFS(classname), "info_player_intermission_blue");
01985 if ( ent && ent->target2 )
01986 {
01987 G_UseTargets2( ent, ent, ent->target2 );
01988 }
01989 }
01990 }
01991 if ( !ent )
01992 {
01993 ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
01994 }
01995 if ( !ent ) {
01996 SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle, TEAM_SPECTATOR );
01997 } else {
01998 VectorCopy (ent->s.origin, level.intermission_origin);
01999 VectorCopy (ent->s.angles, level.intermission_angle);
02000
02001 if ( ent->target ) {
02002 target = G_PickTarget( ent->target );
02003 if ( target ) {
02004 VectorSubtract( target->s.origin, level.intermission_origin, dir );
02005 vectoangles( dir, level.intermission_angle );
02006 }
02007 }
02008 }
02009
02010 }
02011
02012 qboolean DuelLimitHit(void);
02013
02014
02015
02016
02017
02018
02019 void BeginIntermission( void ) {
02020 int i;
02021 gentity_t *client;
02022
02023 if ( level.intermissiontime ) {
02024 return;
02025 }
02026
02027
02028 if ( g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL ) {
02029 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" );
02030
02031 if (g_gametype.integer != GT_POWERDUEL)
02032 {
02033 AdjustTournamentScores();
02034 }
02035 if (DuelLimitHit())
02036 {
02037 gDuelExit = qtrue;
02038 }
02039 else
02040 {
02041 gDuelExit = qfalse;
02042 }
02043 }
02044
02045 level.intermissiontime = level.time;
02046 FindIntermissionPoint();
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057 for (i=0 ; i< level.maxclients ; i++) {
02058 client = g_entities + i;
02059 if (!client->inuse)
02060 continue;
02061
02062 if (client->health <= 0) {
02063 if (g_gametype.integer != GT_POWERDUEL ||
02064 !client->client ||
02065 client->client->sess.sessionTeam != TEAM_SPECTATOR)
02066 {
02067 respawn(client);
02068 }
02069 }
02070 MoveClientToIntermission( client );
02071 }
02072
02073
02074 SendScoreboardMessageToAllClients();
02075
02076 }
02077
02078 qboolean DuelLimitHit(void)
02079 {
02080 int i;
02081 gclient_t *cl;
02082
02083 for ( i=0 ; i< g_maxclients.integer ; i++ ) {
02084 cl = level.clients + i;
02085 if ( cl->pers.connected != CON_CONNECTED ) {
02086 continue;
02087 }
02088
02089 if ( g_duel_fraglimit.integer && cl->sess.wins >= g_duel_fraglimit.integer )
02090 {
02091 return qtrue;
02092 }
02093 }
02094
02095 return qfalse;
02096 }
02097
02098 void DuelResetWinsLosses(void)
02099 {
02100 int i;
02101 gclient_t *cl;
02102
02103 for ( i=0 ; i< g_maxclients.integer ; i++ ) {
02104 cl = level.clients + i;
02105 if ( cl->pers.connected != CON_CONNECTED ) {
02106 continue;
02107 }
02108
02109 cl->sess.wins = 0;
02110 cl->sess.losses = 0;
02111 }
02112 }
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123 extern void SiegeDoTeamAssign(void);
02124 extern siegePers_t g_siegePersistant;
02125 void ExitLevel (void) {
02126 int i;
02127 gclient_t *cl;
02128
02129
02130
02131 if ( g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL ) {
02132 if (!DuelLimitHit())
02133 {
02134 if ( !level.restarted ) {
02135 trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
02136 level.restarted = qtrue;
02137 level.changemap = NULL;
02138 level.intermissiontime = 0;
02139 }
02140 return;
02141 }
02142
02143 DuelResetWinsLosses();
02144 }
02145
02146
02147 if (g_gametype.integer == GT_SIEGE &&
02148 g_siegeTeamSwitch.integer &&
02149 g_siegePersistant.beatingTime)
02150 {
02151 trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
02152 }
02153 else
02154 {
02155 trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" );
02156 }
02157 level.changemap = NULL;
02158 level.intermissiontime = 0;
02159
02160 if (g_gametype.integer == GT_SIEGE &&
02161 g_siegeTeamSwitch.integer)
02162 {
02163 SiegeDoTeamAssign();
02164 }
02165
02166
02167 level.teamScores[TEAM_RED] = 0;
02168 level.teamScores[TEAM_BLUE] = 0;
02169 for ( i=0 ; i< g_maxclients.integer ; i++ ) {
02170 cl = level.clients + i;
02171 if ( cl->pers.connected != CON_CONNECTED ) {
02172 continue;
02173 }
02174 cl->ps.persistant[PERS_SCORE] = 0;
02175 }
02176
02177
02178 G_WriteSessionData();
02179
02180
02181
02182 for (i=0 ; i< g_maxclients.integer ; i++) {
02183 if ( level.clients[i].pers.connected == CON_CONNECTED ) {
02184 level.clients[i].pers.connected = CON_CONNECTING;
02185 }
02186 }
02187
02188 }
02189
02190
02191
02192
02193
02194
02195
02196
02197 void QDECL G_LogPrintf( const char *fmt, ... ) {
02198 va_list argptr;
02199 char string[1024];
02200 int min, tens, sec;
02201
02202 sec = level.time / 1000;
02203
02204 min = sec / 60;
02205 sec -= min * 60;
02206 tens = sec / 10;
02207 sec -= tens * 10;
02208
02209 Com_sprintf( string, sizeof(string), "%3i:%i%i ", min, tens, sec );
02210
02211 va_start( argptr, fmt );
02212 vsprintf( string +7 , fmt,argptr );
02213 va_end( argptr );
02214
02215 if ( g_dedicated.integer ) {
02216 G_Printf( "%s", string + 7 );
02217 }
02218
02219 if ( !level.logFile ) {
02220 return;
02221 }
02222
02223 trap_FS_Write( string, strlen( string ), level.logFile );
02224 }
02225
02226
02227
02228
02229
02230
02231
02232
02233 void LogExit( const char *string ) {
02234 int i, numSorted;
02235 gclient_t *cl;
02236
02237 G_LogPrintf( "Exit: %s\n", string );
02238
02239 level.intermissionQueued = level.time;
02240
02241
02242
02243 trap_SetConfigstring( CS_INTERMISSION, "1" );
02244
02245
02246 numSorted = level.numConnectedClients;
02247 if ( numSorted > 32 ) {
02248 numSorted = 32;
02249 }
02250
02251 if ( g_gametype.integer >= GT_TEAM ) {
02252 G_LogPrintf( "red:%i blue:%i\n",
02253 level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE] );
02254 }
02255
02256 for (i=0 ; i < numSorted ; i++) {
02257 int ping;
02258
02259 cl = &level.clients[level.sortedClients[i]];
02260
02261 if ( cl->sess.sessionTeam == TEAM_SPECTATOR ) {
02262 continue;
02263 }
02264 if ( cl->pers.connected == CON_CONNECTING ) {
02265 continue;
02266 }
02267
02268 ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
02269
02270 G_LogPrintf( "score: %i ping: %i client: %i %s\n", cl->ps.persistant[PERS_SCORE], ping, level.sortedClients[i], cl->pers.netname );
02271
02272
02273
02274
02275
02276 }
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287 }
02288
02289 qboolean gDidDuelStuff = qfalse;
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301 void CheckIntermissionExit( void ) {
02302 int ready, notReady;
02303 int i;
02304 gclient_t *cl;
02305 int readyMask;
02306
02307
02308 ready = 0;
02309 notReady = 0;
02310 readyMask = 0;
02311 for (i=0 ; i< g_maxclients.integer ; i++) {
02312 cl = level.clients + i;
02313 if ( cl->pers.connected != CON_CONNECTED ) {
02314 continue;
02315 }
02316 if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
02317 continue;
02318 }
02319
02320 if ( cl->readyToExit ) {
02321 ready++;
02322 if ( i < 16 ) {
02323 readyMask |= 1 << i;
02324 }
02325 } else {
02326 notReady++;
02327 }
02328 }
02329
02330 if ( (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) && !gDidDuelStuff &&
02331 (level.time > level.intermissiontime + 2000) )
02332 {
02333 gDidDuelStuff = qtrue;
02334
02335 if ( g_austrian.integer && g_gametype.integer != GT_POWERDUEL )
02336 {
02337 G_LogPrintf("Duel Results:\n");
02338
02339 G_LogPrintf("winner: %s, score: %d, wins/losses: %d/%d\n",
02340 level.clients[level.sortedClients[0]].pers.netname,
02341 level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE],
02342 level.clients[level.sortedClients[0]].sess.wins,
02343 level.clients[level.sortedClients[0]].sess.losses );
02344 G_LogPrintf("loser: %s, score: %d, wins/losses: %d/%d\n",
02345 level.clients[level.sortedClients[1]].pers.netname,
02346 level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE],
02347 level.clients[level.sortedClients[1]].sess.wins,
02348 level.clients[level.sortedClients[1]].sess.losses );
02349 }
02350
02351
02352 if (!DuelLimitHit())
02353 {
02354 if (g_gametype.integer == GT_POWERDUEL)
02355 {
02356 RemovePowerDuelLosers();
02357 AddPowerDuelPlayers();
02358 }
02359 else
02360 {
02361 if (level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE] ==
02362 level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE] &&
02363 level.clients[level.sortedClients[0]].pers.connected == CON_CONNECTED &&
02364 level.clients[level.sortedClients[1]].pers.connected == CON_CONNECTED)
02365 {
02366 RemoveDuelDrawLoser();
02367 }
02368 else
02369 {
02370 RemoveTournamentLoser();
02371 }
02372 AddTournamentPlayer();
02373 }
02374
02375 if ( g_austrian.integer )
02376 {
02377 if (g_gametype.integer == GT_POWERDUEL)
02378 {
02379 G_LogPrintf("Power Duel Initiated: %s %d/%d vs %s %d/%d and %s %d/%d, kill limit: %d\n",
02380 level.clients[level.sortedClients[0]].pers.netname,
02381 level.clients[level.sortedClients[0]].sess.wins,
02382 level.clients[level.sortedClients[0]].sess.losses,
02383 level.clients[level.sortedClients[1]].pers.netname,
02384 level.clients[level.sortedClients[1]].sess.wins,
02385 level.clients[level.sortedClients[1]].sess.losses,
02386 level.clients[level.sortedClients[2]].pers.netname,
02387 level.clients[level.sortedClients[2]].sess.wins,
02388 level.clients[level.sortedClients[2]].sess.losses,
02389 g_fraglimit.integer );
02390 }
02391 else
02392 {
02393 G_LogPrintf("Duel Initiated: %s %d/%d vs %s %d/%d, kill limit: %d\n",
02394 level.clients[level.sortedClients[0]].pers.netname,
02395 level.clients[level.sortedClients[0]].sess.wins,
02396 level.clients[level.sortedClients[0]].sess.losses,
02397 level.clients[level.sortedClients[1]].pers.netname,
02398 level.clients[level.sortedClients[1]].sess.wins,
02399 level.clients[level.sortedClients[1]].sess.losses,
02400 g_fraglimit.integer );
02401 }
02402 }
02403
02404 if (g_gametype.integer == GT_POWERDUEL)
02405 {
02406 if (level.numPlayingClients >= 3 && level.numNonSpectatorClients >= 3)
02407 {
02408 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i|%i", level.sortedClients[0], level.sortedClients[1], level.sortedClients[2] ) );
02409 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" );
02410 }
02411 }
02412 else
02413 {
02414 if (level.numPlayingClients >= 2)
02415 {
02416 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) );
02417 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" );
02418 }
02419 }
02420
02421 return;
02422 }
02423
02424 if ( g_austrian.integer && g_gametype.integer != GT_POWERDUEL )
02425 {
02426 G_LogPrintf("Duel Tournament Winner: %s wins/losses: %d/%d\n",
02427 level.clients[level.sortedClients[0]].pers.netname,
02428 level.clients[level.sortedClients[0]].sess.wins,
02429 level.clients[level.sortedClients[0]].sess.losses );
02430 }
02431
02432 if (g_gametype.integer == GT_POWERDUEL)
02433 {
02434 RemovePowerDuelLosers();
02435 AddPowerDuelPlayers();
02436
02437 if (level.numPlayingClients >= 3 && level.numNonSpectatorClients >= 3)
02438 {
02439 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i|%i", level.sortedClients[0], level.sortedClients[1], level.sortedClients[2] ) );
02440 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" );
02441 }
02442 }
02443 else
02444 {
02445
02446
02447
02448 if (level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE] ==
02449 level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE] &&
02450 level.clients[level.sortedClients[0]].pers.connected == CON_CONNECTED &&
02451 level.clients[level.sortedClients[1]].pers.connected == CON_CONNECTED)
02452 {
02453 RemoveDuelDrawLoser();
02454 }
02455 else
02456 {
02457 RemoveTournamentLoser();
02458 }
02459
02460 AddTournamentPlayer();
02461
02462 if (level.numPlayingClients >= 2)
02463 {
02464 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) );
02465 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" );
02466 }
02467 }
02468 }
02469
02470 if ((g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) && !gDuelExit)
02471 {
02472 if ( level.time > level.intermissiontime + 4000 )
02473 {
02474 ExitLevel();
02475 return;
02476 }
02477
02478 for (i=0 ; i< g_maxclients.integer ; i++)
02479 {
02480
02481
02482 cl = level.clients + i;
02483 if ( cl->pers.connected != CON_CONNECTED )
02484 {
02485 continue;
02486 }
02487 cl->ps.stats[STAT_CLIENTS_READY] = 0;
02488 }
02489 return;
02490 }
02491
02492
02493
02494 for (i=0 ; i< g_maxclients.integer ; i++) {
02495 cl = level.clients + i;
02496 if ( cl->pers.connected != CON_CONNECTED ) {
02497 continue;
02498 }
02499 cl->ps.stats[STAT_CLIENTS_READY] = readyMask;
02500 }
02501
02502
02503 if ( level.time < level.intermissiontime + 5000 ) {
02504 return;
02505 }
02506
02507 if (d_noIntermissionWait.integer)
02508 {
02509 ExitLevel();
02510 return;
02511 }
02512
02513
02514 if ( !ready ) {
02515 level.readyToExit = qfalse;
02516 return;
02517 }
02518
02519
02520 if ( !notReady ) {
02521 ExitLevel();
02522 return;
02523 }
02524
02525
02526 if ( !level.readyToExit ) {
02527 level.readyToExit = qtrue;
02528 level.exitTime = level.time;
02529 }
02530
02531
02532
02533 if ( level.time < level.exitTime + 10000 ) {
02534 return;
02535 }
02536
02537 ExitLevel();
02538 }
02539
02540
02541
02542
02543
02544
02545 qboolean ScoreIsTied( void ) {
02546 int a, b;
02547
02548 if ( level.numPlayingClients < 2 ) {
02549 return qfalse;
02550 }
02551
02552 if ( g_gametype.integer >= GT_TEAM ) {
02553 return level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];
02554 }
02555
02556 a = level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE];
02557 b = level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE];
02558
02559 return a == b;
02560 }
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570
02571 qboolean g_endPDuel = qfalse;
02572 void CheckExitRules( void ) {
02573 int i;
02574 gclient_t *cl;
02575 char *sKillLimit;
02576 qboolean printLimit = qtrue;
02577
02578
02579 if ( level.intermissiontime ) {
02580 CheckIntermissionExit ();
02581 return;
02582 }
02583
02584 if (gDoSlowMoDuel)
02585 {
02586 return;
02587 }
02588
02589 if (gEscaping)
02590 {
02591 int i = 0;
02592 int numLiveClients = 0;
02593
02594 while (i < MAX_CLIENTS)
02595 {
02596 if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0)
02597 {
02598 if (g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR &&
02599 !(g_entities[i].client->ps.pm_flags & PMF_FOLLOW))
02600 {
02601 numLiveClients++;
02602 }
02603 }
02604
02605 i++;
02606 }
02607 if (gEscapeTime < level.time)
02608 {
02609 gEscaping = qfalse;
02610 LogExit( "Escape time ended." );
02611 return;
02612 }
02613 if (!numLiveClients)
02614 {
02615 gEscaping = qfalse;
02616 LogExit( "Everyone failed to escape." );
02617 return;
02618 }
02619 }
02620
02621 if ( level.intermissionQueued ) {
02622
02623 int time = INTERMISSION_DELAY_TIME;
02624 if ( level.time - level.intermissionQueued >= time ) {
02625 level.intermissionQueued = 0;
02626 BeginIntermission();
02627 }
02628 return;
02629 }
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650 if (g_gametype.integer != GT_SIEGE)
02651 {
02652 if ( ScoreIsTied() ) {
02653
02654 if ((g_gametype.integer != GT_DUEL) || !g_timelimit.integer)
02655 {
02656 if (g_gametype.integer != GT_POWERDUEL)
02657 {
02658 return;
02659 }
02660 }
02661 }
02662 }
02663
02664 if (g_gametype.integer != GT_SIEGE)
02665 {
02666 if ( g_timelimit.integer && !level.warmupTime ) {
02667 if ( level.time - level.startTime >= g_timelimit.integer*60000 ) {
02668
02669 trap_SendServerCommand( -1, va("print \"%s.\n\"",G_GetStringEdString("MP_SVGAME", "TIMELIMIT_HIT")));
02670 if (d_powerDuelPrint.integer)
02671 {
02672 Com_Printf("POWERDUEL WIN CONDITION: Timelimit hit (1)\n");
02673 }
02674 LogExit( "Timelimit hit." );
02675 return;
02676 }
02677 }
02678 }
02679
02680 if (g_gametype.integer == GT_POWERDUEL && level.numPlayingClients >= 3)
02681 {
02682 if (g_endPDuel)
02683 {
02684 g_endPDuel = qfalse;
02685 LogExit("Powerduel ended.");
02686 }
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788
02789
02790
02791 return;
02792 }
02793
02794 if ( level.numPlayingClients < 2 ) {
02795 return;
02796 }
02797
02798 if (g_gametype.integer == GT_DUEL ||
02799 g_gametype.integer == GT_POWERDUEL)
02800 {
02801 if (g_fraglimit.integer > 1)
02802 {
02803 sKillLimit = "Kill limit hit.";
02804 }
02805 else
02806 {
02807 sKillLimit = "";
02808 printLimit = qfalse;
02809 }
02810 }
02811 else
02812 {
02813 sKillLimit = "Kill limit hit.";
02814 }
02815 if ( g_gametype.integer < GT_SIEGE && g_fraglimit.integer ) {
02816 if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
02817 trap_SendServerCommand( -1, va("print \"Red %s\n\"", G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")) );
02818 if (d_powerDuelPrint.integer)
02819 {
02820 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (1)\n");
02821 }
02822 LogExit( sKillLimit );
02823 return;
02824 }
02825
02826 if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
02827 trap_SendServerCommand( -1, va("print \"Blue %s\n\"", G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")) );
02828 if (d_powerDuelPrint.integer)
02829 {
02830 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (2)\n");
02831 }
02832 LogExit( sKillLimit );
02833 return;
02834 }
02835
02836 for ( i=0 ; i< g_maxclients.integer ; i++ ) {
02837 cl = level.clients + i;
02838 if ( cl->pers.connected != CON_CONNECTED ) {
02839 continue;
02840 }
02841 if ( cl->sess.sessionTeam != TEAM_FREE ) {
02842 continue;
02843 }
02844
02845 if ( (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) && g_duel_fraglimit.integer && cl->sess.wins >= g_duel_fraglimit.integer )
02846 {
02847 if (d_powerDuelPrint.integer)
02848 {
02849 Com_Printf("POWERDUEL WIN CONDITION: Duel limit hit (1)\n");
02850 }
02851 LogExit( "Duel limit hit." );
02852 gDuelExit = qtrue;
02853 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the win limit.\n\"",
02854 cl->pers.netname ) );
02855 return;
02856 }
02857
02858 if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
02859 if (d_powerDuelPrint.integer)
02860 {
02861 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (3)\n");
02862 }
02863 LogExit( sKillLimit );
02864 gDuelExit = qfalse;
02865 if (printLimit)
02866 {
02867 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s.\n\"",
02868 cl->pers.netname,
02869 G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")
02870 )
02871 );
02872 }
02873 return;
02874 }
02875 }
02876 }
02877
02878 if ( g_gametype.integer >= GT_CTF && g_capturelimit.integer ) {
02879
02880 if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer )
02881 {
02882 trap_SendServerCommand( -1, va("print \"%s \"", G_GetStringEdString("MP_SVGAME", "PRINTREDTEAM")));
02883 trap_SendServerCommand( -1, va("print \"%s.\n\"", G_GetStringEdString("MP_SVGAME", "HIT_CAPTURE_LIMIT")));
02884 LogExit( "Capturelimit hit." );
02885 return;
02886 }
02887
02888 if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
02889 trap_SendServerCommand( -1, va("print \"%s \"", G_GetStringEdString("MP_SVGAME", "PRINTBLUETEAM")));
02890 trap_SendServerCommand( -1, va("print \"%s.\n\"", G_GetStringEdString("MP_SVGAME", "HIT_CAPTURE_LIMIT")));
02891 LogExit( "Capturelimit hit." );
02892 return;
02893 }
02894 }
02895 }
02896
02897
02898
02899
02900
02901
02902
02903
02904
02905
02906
02907 void G_RemoveDuelist(int team)
02908 {
02909 int i = 0;
02910 gentity_t *ent;
02911 while (i < MAX_CLIENTS)
02912 {
02913 ent = &g_entities[i];
02914
02915 if (ent->inuse && ent->client && ent->client->sess.sessionTeam != TEAM_SPECTATOR &&
02916 ent->client->sess.duelTeam == team)
02917 {
02918 SetTeam(ent, "s");
02919 }
02920 i++;
02921 }
02922 }
02923
02924
02925
02926
02927
02928
02929
02930
02931 int g_duelPrintTimer = 0;
02932 void CheckTournament( void ) {
02933
02934
02935
02936
02937
02938
02939 if (g_gametype.integer == GT_POWERDUEL)
02940 {
02941 if (level.numPlayingClients >= 3 && level.numNonSpectatorClients >= 3)
02942 {
02943 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i|%i", level.sortedClients[0], level.sortedClients[1], level.sortedClients[2] ) );
02944 }
02945 }
02946 else
02947 {
02948 if (level.numPlayingClients >= 2)
02949 {
02950 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) );
02951 }
02952 }
02953
02954 if ( g_gametype.integer == GT_DUEL )
02955 {
02956
02957 if ( level.numPlayingClients < 2 && !level.intermissiontime && !level.intermissionQueued ) {
02958 AddTournamentPlayer();
02959
02960 if (level.numPlayingClients >= 2)
02961 {
02962 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) );
02963 }
02964 }
02965
02966 if (level.numPlayingClients >= 2)
02967 {
02968
02969 if ( g_showDuelHealths.integer >= 1 )
02970 {
02971 playerState_t *ps1, *ps2;
02972 ps1 = &level.clients[level.sortedClients[0]].ps;
02973 ps2 = &level.clients[level.sortedClients[1]].ps;
02974 trap_SetConfigstring ( CS_CLIENT_DUELHEALTHS, va("%i|%i|!",
02975 ps1->stats[STAT_HEALTH], ps2->stats[STAT_HEALTH]));
02976 }
02977 }
02978
02979
02980
02981 {
02982 level.warmupTime = 0;
02983 return;
02984 }
02985 #if 0
02986
02987 if ( level.numPlayingClients != 2 ) {
02988 if ( level.warmupTime != -1 ) {
02989 level.warmupTime = -1;
02990 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
02991 G_LogPrintf( "Warmup:\n" );
02992 }
02993 return;
02994 }
02995
02996 if ( level.warmupTime == 0 ) {
02997 return;
02998 }
02999
03000
03001 if ( g_warmup.modificationCount != level.warmupModificationCount ) {
03002 level.warmupModificationCount = g_warmup.modificationCount;
03003 level.warmupTime = -1;
03004 }
03005
03006
03007 if ( level.warmupTime < 0 ) {
03008 if ( level.numPlayingClients == 2 ) {
03009
03010 level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
03011
03012 if (level.warmupTime < (level.time + 3000))
03013 {
03014 level.warmupTime = level.time + 3000;
03015 }
03016 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
03017 }
03018 return;
03019 }
03020
03021
03022 if ( level.time > level.warmupTime ) {
03023 level.warmupTime += 10000;
03024 trap_Cvar_Set( "g_restarted", "1" );
03025 trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
03026 level.restarted = qtrue;
03027 return;
03028 }
03029 #endif
03030 }
03031 else if (g_gametype.integer == GT_POWERDUEL)
03032 {
03033 if (level.numPlayingClients < 2)
03034 {
03035 g_dontFrickinCheck = qfalse;
03036 }
03037
03038 if (level.numPlayingClients > 3)
03039 {
03040 int lone = 0, dbl = 0;
03041
03042 G_PowerDuelCount(&lone, &dbl, qfalse);
03043 if (lone > 1)
03044 {
03045 G_RemoveDuelist(DUELTEAM_LONE);
03046 }
03047 else if (dbl > 2)
03048 {
03049 G_RemoveDuelist(DUELTEAM_DOUBLE);
03050 }
03051 }
03052 else if (level.numPlayingClients < 3)
03053 {
03054 int lone = 0, dbl = 0;
03055
03056 G_PowerDuelCount(&lone, &dbl, qfalse);
03057 if (lone < 1)
03058 {
03059 g_dontFrickinCheck = qfalse;
03060 }
03061 else if (dbl < 1)
03062 {
03063 g_dontFrickinCheck = qfalse;
03064 }
03065 }
03066
03067
03068 if (level.numPlayingClients < 3 && !g_dontFrickinCheck)
03069 {
03070 AddPowerDuelPlayers();
03071
03072 if (level.numPlayingClients >= 3 &&
03073 G_CanResetDuelists())
03074 {
03075 gentity_t *te = G_TempEntity(vec3_origin, EV_GLOBAL_DUEL);
03076 te->r.svFlags |= SVF_BROADCAST;
03077
03078 te->s.otherEntityNum = level.sortedClients[0];
03079 te->s.otherEntityNum2 = level.sortedClients[1];
03080 te->s.groundEntityNum = level.sortedClients[2];
03081
03082 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i|%i", level.sortedClients[0], level.sortedClients[1], level.sortedClients[2] ) );
03083 G_ResetDuelists();
03084
03085 g_dontFrickinCheck = qtrue;
03086 }
03087 else if (level.numPlayingClients > 0 ||
03088 level.numConnectedClients > 0)
03089 {
03090 if (g_duelPrintTimer < level.time)
03091 {
03092 int lone = 0, dbl = 0;
03093
03094 G_PowerDuelCount(&lone, &dbl, qtrue);
03095 if (lone < 1)
03096 {
03097 trap_SendServerCommand( -1, va("cp \"%s\n\"", G_GetStringEdString("MP_SVGAME", "DUELMORESINGLE")) );
03098 }
03099 else
03100 {
03101 trap_SendServerCommand( -1, va("cp \"%s\n\"", G_GetStringEdString("MP_SVGAME", "DUELMOREPAIRED")) );
03102 }
03103 g_duelPrintTimer = level.time + 10000;
03104 }
03105 }
03106
03107 if (level.numPlayingClients >= 3 && level.numNonSpectatorClients >= 3)
03108 {
03109 if (G_CanResetDuelists())
03110 {
03111 gentity_t *te = G_TempEntity(vec3_origin, EV_GLOBAL_DUEL);
03112 te->r.svFlags |= SVF_BROADCAST;
03113
03114 te->s.otherEntityNum = level.sortedClients[0];
03115 te->s.otherEntityNum2 = level.sortedClients[1];
03116 te->s.groundEntityNum = level.sortedClients[2];
03117
03118 trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i|%i", level.sortedClients[0], level.sortedClients[1], level.sortedClients[2] ) );
03119
03120 if ( g_austrian.integer )
03121 {
03122 G_LogPrintf("Duel Initiated: %s %d/%d vs %s %d/%d and %s %d/%d, kill limit: %d\n",
03123 level.clients[level.sortedClients[0]].pers.netname,
03124 level.clients[level.sortedClients[0]].sess.wins,
03125 level.clients[level.sortedClients[0]].sess.losses,
03126 level.clients[level.sortedClients[1]].pers.netname,
03127 level.clients[level.sortedClients[1]].sess.wins,
03128 level.clients[level.sortedClients[1]].sess.losses,
03129 level.clients[level.sortedClients[2]].pers.netname,
03130 level.clients[level.sortedClients[2]].sess.wins,
03131 level.clients[level.sortedClients[2]].sess.losses,
03132 g_fraglimit.integer );
03133 }
03134
03135
03136 }
03137 }
03138 }
03139 else
03140 {
03141 g_dontFrickinCheck = qtrue;
03142 }
03143
03144 level.warmupTime = 0;
03145 return;
03146 }
03147 else if ( level.warmupTime != 0 ) {
03148 int counts[TEAM_NUM_TEAMS];
03149 qboolean notEnough = qfalse;
03150
03151 if ( g_gametype.integer > GT_TEAM ) {
03152 counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
03153 counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
03154
03155 if (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) {
03156 notEnough = qtrue;
03157 }
03158 } else if ( level.numPlayingClients < 2 ) {
03159 notEnough = qtrue;
03160 }
03161
03162 if ( notEnough ) {
03163 if ( level.warmupTime != -1 ) {
03164 level.warmupTime = -1;
03165 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
03166 G_LogPrintf( "Warmup:\n" );
03167 }
03168 return;
03169 }
03170
03171 if ( level.warmupTime == 0 ) {
03172 return;
03173 }
03174
03175
03176
03177
03178
03179
03180
03181
03182
03183
03184 if ( level.warmupTime < 0 ) {
03185
03186 level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
03187 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
03188 return;
03189 }
03190
03191
03192 if ( level.time > level.warmupTime ) {
03193 level.warmupTime += 10000;
03194 trap_Cvar_Set( "g_restarted", "1" );
03195 trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
03196 level.restarted = qtrue;
03197 return;
03198 }
03199 }
03200 }
03201
03202 void G_KickAllBots(void)
03203 {
03204 int i;
03205 char netname[36];
03206 gclient_t *cl;
03207
03208 for ( i=0 ; i< g_maxclients.integer ; i++ )
03209 {
03210 cl = level.clients + i;
03211 if ( cl->pers.connected != CON_CONNECTED )
03212 {
03213 continue;
03214 }
03215 if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) )
03216 {
03217 continue;
03218 }
03219 strcpy(netname, cl->pers.netname);
03220 Q_CleanStr(netname);
03221 trap_SendConsoleCommand( EXEC_INSERT, va("kick \"%s\"\n", netname) );
03222 }
03223 }
03224
03225
03226
03227
03228
03229
03230 void CheckVote( void ) {
03231 if ( level.voteExecuteTime && level.voteExecuteTime < level.time ) {
03232 level.voteExecuteTime = 0;
03233 trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
03234
03235 if (level.votingGametype)
03236 {
03237 if (trap_Cvar_VariableIntegerValue("g_gametype") != level.votingGametypeTo)
03238 {
03239 const char *nextMap = G_RefreshNextMap(level.votingGametypeTo, qtrue);
03240
03241 if (level.votingGametypeTo == GT_SIEGE)
03242 {
03243 G_KickAllBots();
03244
03245
03246 }
03247
03248 if (nextMap && nextMap[0])
03249 {
03250 trap_SendConsoleCommand( EXEC_APPEND, va("map %s\n", nextMap ) );
03251 }
03252 }
03253 else
03254 {
03255 G_RefreshNextMap(level.votingGametypeTo, qfalse);
03256 }
03257
03258 if (g_fraglimitVoteCorrection.integer)
03259 {
03260 const int currentGT = trap_Cvar_VariableIntegerValue("g_gametype");
03261 const int currentFL = trap_Cvar_VariableIntegerValue("fraglimit");
03262 const int currentTL = trap_Cvar_VariableIntegerValue("timelimit");
03263
03264 if ((level.votingGametypeTo == GT_DUEL || level.votingGametypeTo == GT_POWERDUEL) && currentGT != GT_DUEL && currentGT != GT_POWERDUEL)
03265 {
03266 if (currentFL > 3 || !currentFL)
03267 {
03268 trap_SendConsoleCommand(EXEC_APPEND, "fraglimit 3\n");
03269 }
03270 if (currentTL)
03271 {
03272 trap_SendConsoleCommand(EXEC_APPEND, "timelimit 0\n");
03273 }
03274 }
03275 else if ((level.votingGametypeTo != GT_DUEL && level.votingGametypeTo != GT_POWERDUEL) &&
03276 (currentGT == GT_DUEL || currentGT == GT_POWERDUEL))
03277 {
03278 if (currentFL && currentFL < 20)
03279 {
03280 trap_SendConsoleCommand(EXEC_APPEND, "fraglimit 20\n");
03281 }
03282 }
03283 }
03284
03285 level.votingGametype = qfalse;
03286 level.votingGametypeTo = 0;
03287 }
03288 }
03289 if ( !level.voteTime ) {
03290 return;
03291 }
03292 if ( level.time - level.voteTime >= VOTE_TIME ) {
03293 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "VOTEFAILED")) );
03294 } else {
03295 if ( level.voteYes > level.numVotingClients/2 ) {
03296
03297 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "VOTEPASSED")) );
03298 level.voteExecuteTime = level.time + 3000;
03299 } else if ( level.voteNo >= level.numVotingClients/2 ) {
03300
03301 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "VOTEFAILED")) );
03302 } else {
03303
03304 return;
03305 }
03306 }
03307 level.voteTime = 0;
03308 trap_SetConfigstring( CS_VOTE_TIME, "" );
03309
03310 }
03311
03312
03313
03314
03315
03316
03317 void PrintTeam(int team, char *message) {
03318 int i;
03319
03320 for ( i = 0 ; i < level.maxclients ; i++ ) {
03321 if (level.clients[i].sess.sessionTeam != team)
03322 continue;
03323 trap_SendServerCommand( i, message );
03324 }
03325 }
03326
03327
03328
03329
03330
03331
03332 void SetLeader(int team, int client) {
03333 int i;
03334
03335 if ( level.clients[client].pers.connected == CON_DISCONNECTED ) {
03336 PrintTeam(team, va("print \"%s is not connected\n\"", level.clients[client].pers.netname) );
03337 return;
03338 }
03339 if (level.clients[client].sess.sessionTeam != team) {
03340 PrintTeam(team, va("print \"%s is not on the team anymore\n\"", level.clients[client].pers.netname) );
03341 return;
03342 }
03343 for ( i = 0 ; i < level.maxclients ; i++ ) {
03344 if (level.clients[i].sess.sessionTeam != team)
03345 continue;
03346 if (level.clients[i].sess.teamLeader) {
03347 level.clients[i].sess.teamLeader = qfalse;
03348 ClientUserinfoChanged(i);
03349 }
03350 }
03351 level.clients[client].sess.teamLeader = qtrue;
03352 ClientUserinfoChanged( client );
03353 PrintTeam(team, va("print \"%s %s\n\"", level.clients[client].pers.netname, G_GetStringEdString("MP_SVGAME", "NEWTEAMLEADER")) );
03354 }
03355
03356
03357
03358
03359
03360
03361 void CheckTeamLeader( int team ) {
03362 int i;
03363
03364 for ( i = 0 ; i < level.maxclients ; i++ ) {
03365 if (level.clients[i].sess.sessionTeam != team)
03366 continue;
03367 if (level.clients[i].sess.teamLeader)
03368 break;
03369 }
03370 if (i >= level.maxclients) {
03371 for ( i = 0 ; i < level.maxclients ; i++ ) {
03372 if (level.clients[i].sess.sessionTeam != team)
03373 continue;
03374 if (!(g_entities[i].r.svFlags & SVF_BOT)) {
03375 level.clients[i].sess.teamLeader = qtrue;
03376 break;
03377 }
03378 }
03379 for ( i = 0 ; i < level.maxclients ; i++ ) {
03380 if (level.clients[i].sess.sessionTeam != team)
03381 continue;
03382 level.clients[i].sess.teamLeader = qtrue;
03383 break;
03384 }
03385 }
03386 }
03387
03388
03389
03390
03391
03392
03393 void CheckTeamVote( int team ) {
03394 int cs_offset;
03395
03396 if ( team == TEAM_RED )
03397 cs_offset = 0;
03398 else if ( team == TEAM_BLUE )
03399 cs_offset = 1;
03400 else
03401 return;
03402
03403 if ( !level.teamVoteTime[cs_offset] ) {
03404 return;
03405 }
03406 if ( level.time - level.teamVoteTime[cs_offset] >= VOTE_TIME ) {
03407 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "TEAMVOTEFAILED")) );
03408 } else {
03409 if ( level.teamVoteYes[cs_offset] > level.numteamVotingClients[cs_offset]/2 ) {
03410
03411 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "TEAMVOTEPASSED")) );
03412
03413 if ( !Q_strncmp( "leader", level.teamVoteString[cs_offset], 6) ) {
03414
03415
03416 }
03417 else {
03418 trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.teamVoteString[cs_offset] ) );
03419 }
03420 } else if ( level.teamVoteNo[cs_offset] >= level.numteamVotingClients[cs_offset]/2 ) {
03421
03422 trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "TEAMVOTEFAILED")) );
03423 } else {
03424
03425 return;
03426 }
03427 }
03428 level.teamVoteTime[cs_offset] = 0;
03429 trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" );
03430
03431 }
03432
03433
03434
03435
03436
03437
03438
03439 void CheckCvars( void ) {
03440 static int lastMod = -1;
03441
03442 if ( g_password.modificationCount != lastMod ) {
03443 char password[MAX_INFO_STRING];
03444 char *c = password;
03445 lastMod = g_password.modificationCount;
03446
03447 strcpy( password, g_password.string );
03448 while( *c )
03449 {
03450 if ( *c == '%' )
03451 {
03452 *c = '.';
03453 }
03454 c++;
03455 }
03456 trap_Cvar_Set("g_password", password );
03457
03458 if ( *g_password.string && Q_stricmp( g_password.string, "none" ) ) {
03459 trap_Cvar_Set( "g_needpass", "1" );
03460 } else {
03461 trap_Cvar_Set( "g_needpass", "0" );
03462 }
03463 }
03464 }
03465
03466
03467
03468
03469
03470
03471
03472
03473 void G_RunThink (gentity_t *ent) {
03474 float thinktime;
03475
03476 thinktime = ent->nextthink;
03477 if (thinktime <= 0) {
03478 goto runicarus;
03479 }
03480 if (thinktime > level.time) {
03481 goto runicarus;
03482 }
03483
03484 ent->nextthink = 0;
03485 if (!ent->think) {
03486
03487 goto runicarus;
03488 }
03489 ent->think (ent);
03490
03491 runicarus:
03492 if ( ent->inuse )
03493 {
03494 trap_ICARUS_MaintainTaskManager(ent->s.number);
03495 }
03496 }
03497
03498 int g_LastFrameTime = 0;
03499 int g_TimeSinceLastFrame = 0;
03500
03501 qboolean gDoSlowMoDuel = qfalse;
03502 int gSlowMoDuelTime = 0;
03503
03504
03505
03506 void NAV_CheckCalcPaths( void )
03507 {
03508 if ( navCalcPathTime && navCalcPathTime < level.time )
03509 {
03510 vmCvar_t mapname;
03511 vmCvar_t ckSum;
03512
03513 trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
03514 trap_Cvar_Register( &ckSum, "sv_mapChecksum", "", CVAR_ROM );
03515
03516
03517 trap_Nav_ClearAllFailedEdges();
03518
03519
03520 NAV_CalculatePaths( mapname.string, ckSum.integer );
03521
03522 trap_Nav_CalculatePaths(qfalse);
03523
03524 #ifndef FINAL_BUILD
03525 if ( fatalErrors )
03526 {
03527 Com_Printf( S_COLOR_RED"Not saving .nav file due to fatal nav errors\n" );
03528 }
03529 else
03530 #endif
03531 #ifndef _XBOX
03532 if ( trap_Nav_Save( mapname.string, ckSum.integer ) == qfalse )
03533 {
03534 Com_Printf("Unable to save navigations data for map \"%s\" (checksum:%d)\n", mapname.string, ckSum.integer );
03535 }
03536 #endif
03537 navCalcPathTime = 0;
03538 }
03539 }
03540
03541
03542 #include "../namespace_begin.h"
03543 int BG_GetTime(void)
03544 {
03545 return level.time;
03546 }
03547 #include "../namespace_end.h"
03548
03549
03550
03551
03552
03553
03554
03555
03556 void ClearNPCGlobals( void );
03557 void AI_UpdateGroups( void );
03558 void ClearPlayerAlertEvents( void );
03559 void SiegeCheckTimers(void);
03560 void WP_SaberStartMissileBlockCheck( gentity_t *self, usercmd_t *ucmd );
03561 extern void Jedi_Decloak( gentity_t *self );
03562 qboolean G_PointInBounds( vec3_t point, vec3_t mins, vec3_t maxs );
03563
03564 int g_siegeRespawnCheck = 0;
03565
03566 void G_RunFrame( int levelTime ) {
03567 int i;
03568 gentity_t *ent;
03569 int msec;
03570 #ifdef _G_FRAME_PERFANAL
03571 int iTimer_ItemRun = 0;
03572 int iTimer_ROFF = 0;
03573 int iTimer_ClientEndframe = 0;
03574 int iTimer_GameChecks = 0;
03575 int iTimer_Queues = 0;
03576 void *timer_ItemRun;
03577 void *timer_ROFF;
03578 void *timer_ClientEndframe;
03579 void *timer_GameChecks;
03580 void *timer_Queues;
03581 #endif
03582
03583 if (g_gametype.integer == GT_SIEGE &&
03584 g_siegeRespawn.integer &&
03585 g_siegeRespawnCheck < level.time)
03586 {
03587 int i = 0;
03588 gentity_t *clEnt;
03589 while (i < MAX_CLIENTS)
03590 {
03591 clEnt = &g_entities[i];
03592
03593 if (clEnt->inuse && clEnt->client &&
03594 clEnt->client->tempSpectate > level.time &&
03595 clEnt->client->sess.sessionTeam != TEAM_SPECTATOR)
03596 {
03597 respawn(clEnt);
03598 clEnt->client->tempSpectate = 0;
03599 }
03600 i++;
03601 }
03602
03603 g_siegeRespawnCheck = level.time + g_siegeRespawn.integer * 1000;
03604 }
03605
03606 if (gDoSlowMoDuel)
03607 {
03608 if (level.restarted)
03609 {
03610 char buf[128];
03611 float tFVal = 0;
03612
03613 trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf));
03614
03615 tFVal = atof(buf);
03616
03617 trap_Cvar_Set("timescale", "1");
03618 if (tFVal == 1.0f)
03619 {
03620 gDoSlowMoDuel = qfalse;
03621 }
03622 }
03623 else
03624 {
03625 float timeDif = (level.time - gSlowMoDuelTime);
03626 float useDif = 0;
03627
03628 if (timeDif < 150)
03629 {
03630 trap_Cvar_Set("timescale", "0.1f");
03631 }
03632 else if (timeDif < 1150)
03633 {
03634 useDif = (timeDif/1000);
03635 if (useDif < 0.1)
03636 {
03637 useDif = 0.1;
03638 }
03639 if (useDif > 1.0)
03640 {
03641 useDif = 1.0;
03642 }
03643 trap_Cvar_Set("timescale", va("%f", useDif));
03644 }
03645 else
03646 {
03647 char buf[128];
03648 float tFVal = 0;
03649
03650 trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf));
03651
03652 tFVal = atof(buf);
03653
03654 trap_Cvar_Set("timescale", "1");
03655 if (timeDif > 1500 && tFVal == 1.0f)
03656 {
03657 gDoSlowMoDuel = qfalse;
03658 }
03659 }
03660 }
03661 }
03662
03663
03664 if ( level.restarted ) {
03665 return;
03666 }
03667
03668 level.framenum++;
03669 level.previousTime = level.time;
03670 level.time = levelTime;
03671 msec = level.time - level.previousTime;
03672
03673 if (g_allowNPC.integer)
03674 {
03675 NAV_CheckCalcPaths();
03676 }
03677
03678 AI_UpdateGroups();
03679
03680 if (g_allowNPC.integer)
03681 {
03682 if ( d_altRoutes.integer )
03683 {
03684 trap_Nav_CheckAllFailedEdges();
03685 }
03686 trap_Nav_ClearCheckedNodes();
03687
03688
03689 for ( i = 0; i < level.num_entities ; i++)
03690 {
03691 ent = &g_entities[i];
03692
03693 if ( !ent->inuse )
03694 continue;
03695
03696 if ( ent->waypoint != WAYPOINT_NONE
03697 && ent->noWaypointTime < level.time )
03698 {
03699 ent->lastWaypoint = ent->waypoint;
03700 ent->waypoint = WAYPOINT_NONE;
03701 }
03702 if ( d_altRoutes.integer )
03703 {
03704 trap_Nav_CheckFailedNodes( ent );
03705 }
03706 }
03707
03708
03709 ClearPlayerAlertEvents();
03710 }
03711
03712 g_TimeSinceLastFrame = (level.time - g_LastFrameTime);
03713
03714
03715 G_UpdateCvars();
03716
03717
03718
03719 #ifdef _G_FRAME_PERFANAL
03720 trap_PrecisionTimer_Start(&timer_ItemRun);
03721 #endif
03722
03723
03724
03725 ent = &g_entities[0];
03726 for (i=0 ; i<level.num_entities ; i++, ent++) {
03727 if ( !ent->inuse ) {
03728 continue;
03729 }
03730
03731
03732 if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
03733 if ( ent->s.event ) {
03734 ent->s.event = 0;
03735 if ( ent->client ) {
03736 ent->client->ps.externalEvent = 0;
03737
03738
03739
03740 }
03741 }
03742 if ( ent->freeAfterEvent ) {
03743
03744 if (ent->s.eFlags & EF_SOUNDTRACKER)
03745 {
03746 ent->s.event = 0;
03747 ent->s.eventParm = 0;
03748 ent->s.eType = 0;
03749 ent->eventTime = 0;
03750 }
03751 else
03752 {
03753 G_FreeEntity( ent );
03754 continue;
03755 }
03756 } else if ( ent->unlinkAfterEvent ) {
03757
03758 ent->unlinkAfterEvent = qfalse;
03759 trap_UnlinkEntity( ent );
03760 }
03761 }
03762
03763
03764 if ( ent->freeAfterEvent ) {
03765 continue;
03766 }
03767
03768 if ( !ent->r.linked && ent->neverFree ) {
03769 continue;
03770 }
03771
03772 if ( ent->s.eType == ET_MISSILE ) {
03773 G_RunMissile( ent );
03774 continue;
03775 }
03776
03777 if ( ent->s.eType == ET_ITEM || ent->physicsObject ) {
03778 #if 0 //use if body dragging enabled?
03779 if (ent->s.eType == ET_BODY)
03780 {
03781 float grav = 3.0f;
03782 float mass = 0.14f;
03783 float bounce = 1.15f;
03784
03785 G_RunExPhys(ent, grav, mass, bounce, qfalse, NULL, 0);
03786 }
03787 else
03788 {
03789 G_RunItem( ent );
03790 }
03791 #else
03792 G_RunItem( ent );
03793 #endif
03794 continue;
03795 }
03796
03797 if ( ent->s.eType == ET_MOVER ) {
03798 G_RunMover( ent );
03799 continue;
03800 }
03801
03802 if ( i < MAX_CLIENTS )
03803 {
03804 G_CheckClientTimeouts ( ent );
03805
03806 if (ent->client->inSpaceIndex && ent->client->inSpaceIndex != ENTITYNUM_NONE)
03807 {
03808 gentity_t *spacetrigger = &g_entities[ent->client->inSpaceIndex];
03809
03810 if (!spacetrigger->inuse ||
03811 !G_PointInBounds(ent->client->ps.origin, spacetrigger->r.absmin, spacetrigger->r.absmax))
03812 {
03813 ent->client->inSpaceIndex = 0;
03814 }
03815 else
03816 {
03817 if (ent->client->inSpaceSuffocation < level.time)
03818 {
03819 if (ent->health > 0 && ent->takedamage)
03820 {
03821 G_Damage(ent, spacetrigger, spacetrigger, NULL, ent->client->ps.origin, Q_irand(50, 70), DAMAGE_NO_ARMOR, MOD_SUICIDE);
03822
03823 if (ent->health > 0)
03824 {
03825
03826 G_EntitySound(ent, CHAN_VOICE, G_SoundIndex(va( "*choke%d.wav", Q_irand( 1, 3 ) )));
03827
03828
03829 ent->client->ps.forceHandExtend = HANDEXTEND_CHOKE;
03830 ent->client->ps.forceHandExtendTime = level.time + 2000;
03831 }
03832 }
03833
03834 ent->client->inSpaceSuffocation = level.time + Q_irand(100, 200);
03835 }
03836 }
03837 }
03838
03839 if (ent->client->isHacking)
03840 {
03841 gentity_t *hacked = &g_entities[ent->client->isHacking];
03842 vec3_t angDif;
03843
03844 VectorSubtract(ent->client->ps.viewangles, ent->client->hackingAngles, angDif);
03845
03846
03847 if (ent->client->ps.torsoAnim != BOTH_CONSOLE1)
03848 {
03849 G_SetAnim( ent, NULL, SETANIM_TORSO, BOTH_CONSOLE1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
03850 }
03851 else
03852 {
03853 ent->client->ps.torsoTimer = 500;
03854 }
03855 ent->client->ps.weaponTime = ent->client->ps.torsoTimer;
03856
03857 if (!(ent->client->pers.cmd.buttons & BUTTON_USE))
03858 {
03859 ent->client->isHacking = 0;
03860 ent->client->ps.hackingTime = 0;
03861 }
03862 else if (!hacked || !hacked->inuse)
03863 {
03864 ent->client->isHacking = 0;
03865 ent->client->ps.hackingTime = 0;
03866 }
03867 else if (!G_PointInBounds( ent->client->ps.origin, hacked->r.absmin, hacked->r.absmax ))
03868 {
03869 ent->client->isHacking = 0;
03870 ent->client->ps.hackingTime = 0;
03871 }
03872 else if (VectorLength(angDif) > 10.0f)
03873 {
03874 ent->client->isHacking = 0;
03875 ent->client->ps.hackingTime = 0;
03876 }
03877 }
03878
03879 #define JETPACK_DEFUEL_RATE 200 //approx. 20 seconds of idle use from a fully charged fuel amt
03880 #define JETPACK_REFUEL_RATE 150 //seems fair
03881 if (ent->client->jetPackOn)
03882 {
03883 if (ent->client->jetPackDebReduce < level.time)
03884 {
03885 if (ent->client->pers.cmd.upmove > 0)
03886 {
03887 ent->client->ps.jetpackFuel -= 2;
03888 }
03889 else
03890 {
03891 ent->client->ps.jetpackFuel--;
03892 }
03893
03894 if (ent->client->ps.jetpackFuel <= 0)
03895 {
03896 ent->client->ps.jetpackFuel = 0;
03897 Jetpack_Off(ent);
03898 }
03899 ent->client->jetPackDebReduce = level.time + JETPACK_DEFUEL_RATE;
03900 }
03901 }
03902 else if (ent->client->ps.jetpackFuel < 100)
03903 {
03904 if (ent->client->jetPackDebRecharge < level.time)
03905 {
03906 ent->client->ps.jetpackFuel++;
03907 ent->client->jetPackDebRecharge = level.time + JETPACK_REFUEL_RATE;
03908 }
03909 }
03910
03911 #define CLOAK_DEFUEL_RATE 200 //approx. 20 seconds of idle use from a fully charged fuel amt
03912 #define CLOAK_REFUEL_RATE 150 //seems fair
03913 if (ent->client->ps.powerups[PW_CLOAKED])
03914 {
03915 if (ent->client->cloakDebReduce < level.time)
03916 {
03917 ent->client->ps.cloakFuel--;
03918
03919 if (ent->client->ps.cloakFuel <= 0)
03920 {
03921 ent->client->ps.cloakFuel = 0;
03922 Jedi_Decloak(ent);
03923 }
03924 ent->client->cloakDebReduce = level.time + CLOAK_DEFUEL_RATE;
03925 }
03926 }
03927 else if (ent->client->ps.cloakFuel < 100)
03928 {
03929 if (ent->client->cloakDebRecharge < level.time)
03930 {
03931 ent->client->ps.cloakFuel++;
03932 ent->client->cloakDebRecharge = level.time + CLOAK_REFUEL_RATE;
03933 }
03934 }
03935
03936 if (g_gametype.integer == GT_SIEGE &&
03937 ent->client->siegeClass != -1 &&
03938 (bgSiegeClasses[ent->client->siegeClass].classflags & (1<<CFL_STATVIEWER)))
03939 {
03940 if (ent->client->siegeEDataSend < level.time)
03941 {
03942 G_SiegeClientExData(ent);
03943 ent->client->siegeEDataSend = level.time + 1000;
03944 }
03945 }
03946
03947 if((!level.intermissiontime)&&!(ent->client->ps.pm_flags&PMF_FOLLOW) && ent->client->sess.sessionTeam != TEAM_SPECTATOR)
03948 {
03949 WP_ForcePowersUpdate(ent, &ent->client->pers.cmd );
03950 WP_SaberPositionUpdate(ent, &ent->client->pers.cmd);
03951 WP_SaberStartMissileBlockCheck(ent, &ent->client->pers.cmd);
03952 }
03953
03954 if (g_allowNPC.integer)
03955 {
03956
03957
03958 NAV_FindPlayerWaypoint(i);
03959 }
03960
03961 trap_ICARUS_MaintainTaskManager(ent->s.number);
03962
03963 G_RunClient( ent );
03964 continue;
03965 }
03966 else if (ent->s.eType == ET_NPC)
03967 {
03968 int j;
03969
03970 for ( j = 0 ; j < MAX_POWERUPS ; j++ ) {
03971 if ( ent->client->ps.powerups[ j ] < level.time ) {
03972 ent->client->ps.powerups[ j ] = 0;
03973 }
03974 }
03975
03976 WP_ForcePowersUpdate(ent, &ent->client->pers.cmd );
03977 WP_SaberPositionUpdate(ent, &ent->client->pers.cmd);
03978 WP_SaberStartMissileBlockCheck(ent, &ent->client->pers.cmd);
03979 }
03980
03981 G_RunThink( ent );
03982
03983 if (g_allowNPC.integer)
03984 {
03985 ClearNPCGlobals();
03986 }
03987 }
03988 #ifdef _G_FRAME_PERFANAL
03989 iTimer_ItemRun = trap_PrecisionTimer_End(timer_ItemRun);
03990 #endif
03991
03992 SiegeCheckTimers();
03993
03994 #ifdef _G_FRAME_PERFANAL
03995 trap_PrecisionTimer_Start(&timer_ROFF);
03996 #endif
03997 trap_ROFF_UpdateEntities();
03998 #ifdef _G_FRAME_PERFANAL
03999 iTimer_ROFF = trap_PrecisionTimer_End(timer_ROFF);
04000 #endif
04001
04002
04003
04004 #ifdef _G_FRAME_PERFANAL
04005 trap_PrecisionTimer_Start(&timer_ClientEndframe);
04006 #endif
04007
04008 ent = &g_entities[0];
04009 for (i=0 ; i < level.maxclients ; i++, ent++ ) {
04010 if ( ent->inuse ) {
04011 ClientEndFrame( ent );
04012 }
04013 }
04014 #ifdef _G_FRAME_PERFANAL
04015 iTimer_ClientEndframe = trap_PrecisionTimer_End(timer_ClientEndframe);
04016 #endif
04017
04018
04019
04020 #ifdef _G_FRAME_PERFANAL
04021 trap_PrecisionTimer_Start(&timer_GameChecks);
04022 #endif
04023
04024 CheckTournament();
04025
04026
04027 CheckExitRules();
04028
04029
04030 CheckTeamStatus();
04031
04032
04033 CheckVote();
04034
04035
04036 CheckTeamVote( TEAM_RED );
04037 CheckTeamVote( TEAM_BLUE );
04038
04039
04040 CheckCvars();
04041
04042 if (g_listEntity.integer) {
04043 for (i = 0; i < MAX_GENTITIES; i++) {
04044 G_Printf("%4i: %s\n", i, g_entities[i].classname);
04045 }
04046 trap_Cvar_Set("g_listEntity", "0");
04047 }
04048 #ifdef _G_FRAME_PERFANAL
04049 iTimer_GameChecks = trap_PrecisionTimer_End(timer_GameChecks);
04050 #endif
04051
04052
04053
04054 #ifdef _G_FRAME_PERFANAL
04055 trap_PrecisionTimer_Start(&timer_Queues);
04056 #endif
04057
04058 G_SendG2KillQueue();
04059
04060 if (gQueueScoreMessage)
04061 {
04062 if (gQueueScoreMessageTime < level.time)
04063 {
04064 SendScoreboardMessageToAllClients();
04065
04066 gQueueScoreMessageTime = 0;
04067 gQueueScoreMessage = 0;
04068 }
04069 }
04070 #ifdef _G_FRAME_PERFANAL
04071 iTimer_Queues = trap_PrecisionTimer_End(timer_Queues);
04072 #endif
04073
04074
04075
04076 #ifdef _G_FRAME_PERFANAL
04077 Com_Printf("---------------\nItemRun: %i\nROFF: %i\nClientEndframe: %i\nGameChecks: %i\nQueues: %i\n---------------\n",
04078 iTimer_ItemRun,
04079 iTimer_ROFF,
04080 iTimer_ClientEndframe,
04081 iTimer_GameChecks,
04082 iTimer_Queues);
04083 #endif
04084
04085 g_LastFrameTime = level.time;
04086 }
04087
04088 const char *G_GetStringEdString(char *refSection, char *refName)
04089 {
04090
04091
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101 static char text[1024]={0};
04102 Com_sprintf(text, sizeof(text), "@@@%s", refName);
04103 return text;
04104 }