// Copyright (C) 1999-2000 Id Software, Inc. // #include "g_main.h" #include "g_local.h" #include "g_groups.h" #include "bg_lex.h" #include "g_cmds.h" extern void BG_LoadItemNames(void); extern qboolean BG_ParseRankNames ( char* fileName, rankNames_t rankNames[] ); //RPG-X: RedTechie int RPGEntityCount; //Global entity count varible level_locals_t level; extern char races[256]; //this is evil! group_list_t group_list[MAX_GROUP_MEMBERS]; int group_count; int numKilled; typedef struct { vmCvar_t *vmCvar; char *cvarName; char *defaultString; int cvarFlags; int modificationCount; // for tracking changes qboolean trackChange; // track this variable, and announce if changed } cvarTable_t; gentity_t g_entities[MAX_GENTITIES]; static gclient_t g_clients[MAX_CLIENTS]; rankNames_t g_rankNames[MAX_RANKS]; g_classData_t g_classData[MAX_CLASSES]; vmCvar_t g_gametype; vmCvar_t g_dmflags; vmCvar_t g_password; vmCvar_t g_needpass; vmCvar_t g_maxclients; vmCvar_t g_maxGameClients; vmCvar_t g_dedicated; vmCvar_t g_speed; vmCvar_t g_gravity; vmCvar_t g_cheats; vmCvar_t g_knockback; vmCvar_t g_dmgmult; vmCvar_t g_forcerespawn; vmCvar_t g_inactivity; vmCvar_t g_debugMove; vmCvar_t g_debugDamage; vmCvar_t g_debugAlloc; vmCvar_t g_weaponRespawn; vmCvar_t g_adaptRespawn; vmCvar_t g_motd; vmCvar_t g_synchronousClients; vmCvar_t g_restarted; static vmCvar_t g_log; static vmCvar_t g_logSync; vmCvar_t g_allowVote; vmCvar_t g_banIPs; vmCvar_t g_filterBan; vmCvar_t g_banIDs; //TiM - Security ban system vmCvar_t g_debugForward; vmCvar_t g_debugRight; vmCvar_t g_debugUp; vmCvar_t g_language; vmCvar_t g_holoIntro; vmCvar_t g_team_group_red; vmCvar_t g_team_group_blue; vmCvar_t g_random_skin_limit; vmCvar_t g_classChangeDebounceTime; //RPG-X: - RedTechie More CVAR INFO vmCvar_t rpg_allowvote; vmCvar_t rpg_chatsallowed; vmCvar_t rpg_allowsuicide; vmCvar_t rpg_selfdamage; vmCvar_t rpg_rpg; vmCvar_t rpg_kickspammers; //!< Specifies whether player that spam get kicked automatically. vmCvar_t rpg_kicksuiciders; //!< Specifies whether player that sucide get kicked automatically. vmCvar_t rpg_allowspmaps; //!< Specifies whether singleplayer maps can be loaded vmCvar_t rpg_rangetricorder; //!< Maximum range the Tricorder can scan. vmCvar_t rpg_rangehypo; //!< Maximum range of the Hypospray. vmCvar_t rpg_norpgclasses; vmCvar_t rpg_forceclasscolor; //!< Specifies whether class colors specified in the *.class file are enforced. /* * Ristrictions: nocloak = 1, noflight = 2 * Default value: 0 */ vmCvar_t rpg_restrictions; /* * Which weapons do damage? * Phaser = 1 * Crifle = 2 * TR116 = 4 * Grenade Laucher = 8 * Quantum Burst = 16 * Disruptor = 32 * Default value: 63 */ vmCvar_t rpg_dmgFlags; vmCvar_t rpg_noweapons; //!< Can be used to disable all weapons. vmCvar_t rpg_welcomemessage; //!< Welcome message displayed when a player joins the server. vmCvar_t rpg_timedmessagetime; //!< Delay between timed mesagges vmCvar_t rpg_forcekillradius; //!< Specifies whether the forcekillradius command is avaible. vmCvar_t rpg_forcekillradiuswaittime; //!< forcekillradius delay vmCvar_t rpg_noclipspectating; //!< Specifies whether spectators uses clipping. vmCvar_t rpg_chatarearange; //!< Maximumrange for area chat. vmCvar_t rpg_forcefielddamage; //!< Damage a player takes when touching an admin force field vmCvar_t rpg_invisibletripmines; //!< Specifies whether invisible tripmines are enabled. vmCvar_t rpg_medicsrevive; //!< Are medics allowed to revive other players vmCvar_t rpg_effectsgun; //!< Can be used to enable/disable the effects gun vmCvar_t rpg_phaserdisintegrates; //!< If enabled phasers disintegrate players instead ob incapacitating them. //! Kick player for n00bing after this ammount of kills vmCvar_t rpg_kickAfterXkills; //RPG-X | Phenix | 06/04/2005 vmCvar_t rpg_rankSet; //!< Rankset to use vmCvar_t rpg_passMessage; //RPG-X | TiM | 2/2/2006 //! If enabled the previous name of a player is displayed if the reconnects with a different one. vmCvar_t rpg_renamedPlayers; //RPG-X | TiM | For players that disconnect, reconnect with dif names to try and be sneaky... //! If enabled only one player can have a name at the same time. vmCvar_t rpg_uniqueNames; //RPG-X | TiM | When active, only one player can have the same name on a server //RPG-X | TiM | Cvars to make the rank system more controllable vmCvar_t rpg_startingRank; //!< The rank players will start as, regardless vmCvar_t rpg_maxRank; //!< Absolute rank players can set themselves to vmCvar_t rpg_changeRanks; //!< If players are allowed to change ranks themselves //TiM - height paramters vmCvar_t rpg_maxHeight; vmCvar_t rpg_minHeight; vmCvar_t rpg_maxWeight; vmCvar_t rpg_minWeight; //! Classet to use vmCvar_t rpg_classSet; //TiM: current server class configuration vmCvar_t rpg_mapGiveFlags; vmCvar_t rpg_scannablePanels; //!< Scan consoles and doors be scanned with the Tricorder // Drop stuff //! Enables weapon dropping vmCvar_t rpg_allowWeaponDrop; //RPG-X | Marcin | 03/12/2008 //! Do weapons stay in inventory when a player drops them vmCvar_t rpg_weaponsStay; //RPG-X | Marcin | 04/12/2008 //! Does a player drop his weapons when he dies vmCvar_t rpg_dropOnDeath; //RPG-X | Marcin | 30/12/2008 //vmCvar_t rpg_flushDroppedOnDisconnect; //RPG-X | GSIO01 | 08/05/2009 // Weapon speeds //! Speed for compression riffle projectiles vmCvar_t rpg_rifleSpeed; //RPG-X | Marcin | 04/12/2008 //! Speed for disruptor projectiles vmCvar_t rpg_disruptorSpeed; //RPG-X | Marcin | 04/12/2008 //! Speed for photon burst projectiles vmCvar_t rpg_photonSpeed; //RPG-X | Marcin | 05/12/2008 //! Speed for altfire photon burst projectiles vmCvar_t rpg_altPhotonSpeed; //RPG-X | Marcin | 06/12/2008 // Weapon delays vmCvar_t rpg_rifleDelay; //RPG-X | Marcin | 06/12/2008 vmCvar_t rpg_disruptorDelay; //RPG-X | Marcin | 06/12/2008 vmCvar_t rpg_photonDelay; //RPG-X | Marcin | 06/12/2008 vmCvar_t rpg_altPhotonDelay; //RPG-X | Marcin | 06/12/2008 vmCvar_t rpg_TR116Delay; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_altTricorderDelay; //RPG-X | GSIO01 | 14/05/2009 // Weapon Damage vmCvar_t rpg_rifleDamage; vmCvar_t rpg_rifleAltDamage; vmCvar_t rpg_phaserDamage; vmCvar_t rpg_disruptorDamage; vmCvar_t rpg_grenadeDamage; vmCvar_t rpg_grenadeAltDamage; vmCvar_t rpg_tr116Damage; vmCvar_t rpg_photonDamage; vmCvar_t rpg_photonAltDamage; // Motd //! Specifies the message of the day file vmCvar_t rpg_motdFile; //RPG-X | Marcin | 23/12/2008 // Privacy //! If enabled admins can the private chat messages vmCvar_t rpg_respectPrivacy; //RPG-X | Marcin | 24/12/2008 // Weaps vmCvar_t rpg_maxTricorders; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxPADDs; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxCups; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxPhasers; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxRifles; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxTR116s; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxAdminguns; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxPhotonbursts; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxDisruptors; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxMedkits; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxHyposprays; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxRegenerators; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxToolkits; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_maxHyperSpanners;//RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minTricorders; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minPADDs; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minCups; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minPhasers; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minRifles; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minTR116s; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minAdminguns; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minPhotonbursts; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minDisruptors; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minMedkits; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minHyposprays; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minRegenerators; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minToolkits; //RPG-X | Marcin | 30/12/2008 vmCvar_t rpg_minHyperSpanners;//RPG-X | Marcin | 30/12/2008 // respawn delay //! Delay for respawn function vmCvar_t rpg_fraggerSpawnDelay; //RPG-X | Marcin | 03/01/2009 // borg adaption //! If enabled borg get immune to weapons after some time vmCvar_t rpg_borgAdapt; //RPG-X | GSIO01 | 08/05/2009 //! Borg shield plays sound if hit? vmCvar_t rpg_adaptUseSound; //RPG-X | GSIO01 | 08/05/2009 //! Number of hits before borg adapt to this weapon vmCvar_t rpg_adaptPhaserHits; //RPG-X | GSIO01 | 08/05/2009 //! Number of hits before borg adapt to this weapon vmCvar_t rpg_adaptPhotonHits; //RPG-X | GSIO01 | 08/05/2009 //! Number of hits before borg adapt to this weapon vmCvar_t rpg_adaptCrifleHits; //RPG-X | GSIO01 | 08/05/2009 //! Number of hits before borg adapt to this weapon vmCvar_t rpg_adaptDisruptorHits; //RPG-X | GSIO01 | 08/05/2009 //! Number of hits before borg adapt to this weapon vmCvar_t rpg_adaptTR116Hits; //RPG-X | GSIO01 | 08/05/2009 //! Number of hits before borg adapt to this weapon vmCvar_t rpg_adaptGrenadeLauncherHits; //RPG-X | GSIO01 | 08/05/2009 //! Are player allowed to remodulate their weapons vmCvar_t rpg_allowRemodulation; //RPG-X | GSIO01 | 10/05/2009 //! Can borg move through admin force fields vmCvar_t rpg_borgMoveThroughFields; //RPG-X | GSIO01 | 19/05/2009 //! Delay for modulation vmCvar_t rpg_RemodulationDelay; // hypo melee //! Can the hypospray be used as weapons vmCvar_t rpg_hypoMelee; // repairing breakables //! Can be used to modify repairspeed vmCvar_t rpg_repairModifier; //RPG-X | GSIO01 | 09/05/2009 // force field colors //! Current force field color vmCvar_t rpg_forceFieldColor; //RPG-X | GSIO01 | 09/05/2009 // modulation thingies //RPG-X | GSIO01 | 12/05/2009 vmCvar_t rpg_forceFieldFreq; // calc lif travel duration by dec distance //! Calculathe the travel durration of the turbolift by the difference between the deck numbers? vmCvar_t rpg_calcLiftTravelDuration; //! Can be used to modify the lift speed vmCvar_t rpg_liftDurationModifier; // admin vote override //! Admins can override votes vmCvar_t rpg_adminVoteOverride; // server change //! Enables/disables target_serverchange vmCvar_t rpg_serverchange; // SP level change //! Allow target_levelchange to change the current level? vmCvar_t rpg_allowSPLevelChange; /* SQL Database */ vmCvar_t sql_use; //!< Use SQL? 1 = mysql, 2 = sqlite // developer tools vmCvar_t dev_showTriggers; #ifdef G_LUA // Print Lua debugging information into the game console? vmCvar_t g_debugLua; vmCvar_t lua_modules; vmCvar_t lua_allowedModules; #endif vmCvar_t g_developer; vmCvar_t rpg_spEasterEggs; static cvarTable_t gameCvarTable[] = { // don't override the cheat state set by the system { &g_cheats, "sv_cheats", "", 0, 0, qfalse }, // noset vars { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse }, { NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse }, { &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse }, { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse }, // latched vars { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_INIT | CVAR_ROM, 0, qfalse }, { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, // change anytime vars { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse }, { &g_log, "g_log", "", CVAR_ARCHIVE, 0, qfalse }, { &g_logSync, "g_logSync", "0", CVAR_ARCHIVE, 0, qfalse }, { &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse }, { &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse }, { &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse }, { &g_banIDs, "g_banIDs", "", CVAR_ARCHIVE, 0, qfalse }, { &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse }, { &g_dedicated, "dedicated", "0", 0, 0, qfalse }, { &g_speed, "g_speed", "250", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, // Quake 3 default was 320. { &g_gravity, "g_gravity", "800", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_knockback, "g_knockback", "500", 0, 0, qtrue }, { &g_dmgmult, "g_dmgmult", "1", 0, 0, qtrue }, { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue }, // Quake 3 default (with 1 ammo weapons) was 5. { &g_adaptRespawn, "g_adaptrespawn", "1", 0, 0, qtrue }, // Make weapons respawn faster with a lot of players. { &g_forcerespawn, "g_forcerespawn", "0", 0, 0, qtrue }, // Quake 3 default was 20. This is more "user friendly". { &g_inactivity, "g_inactivity", "0", 0, 0, qtrue }, { &g_debugMove, "g_debugMove", "0", 0, 0, qfalse }, { &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse }, { &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse }, { &g_motd, "g_motd", "", 0, 0, qfalse }, { &g_allowVote, "g_allowVote", "1", CVAR_SERVERINFO, 0, qfalse }, #if 0 { &g_debugForward, "g_debugForward", "0", 0, 0, qfalse }, { &g_debugRight, "g_debugRight", "0", 0, 0, qfalse }, { &g_debugUp, "g_debugUp", "0", 0, 0, qfalse }, #endif { &g_language, "g_language", "", CVAR_ARCHIVE, 0, qfalse }, { &g_holoIntro, "g_holoIntro", "1", CVAR_ARCHIVE, 0, qfalse }, { &g_team_group_red, "g_team_group_red", "", CVAR_LATCH, 0, qfalse }, // Used to have CVAR_ARCHIVE { &g_team_group_blue, "g_team_group_blue", "", CVAR_LATCH, 0, qfalse }, // Used to have CVAR_ARCHIVE { &g_random_skin_limit, "g_random_skin_limit", "4", CVAR_ARCHIVE, 0, qfalse }, { &g_classChangeDebounceTime, "g_classChangeDebounceTime", "180", CVAR_ARCHIVE, 0, qfalse }, //RPG-X: RedTechie - RPG-X CVARS....duh....just for the slow ones { &rpg_allowvote, "rpg_allowVote", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_chatsallowed, "rpg_chatsAllowed", "10", CVAR_ARCHIVE, 0, qfalse }, { &rpg_allowsuicide, "rpg_allowSuicide", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_selfdamage, "rpg_selfDamage", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_rpg, "rpg_rpg", "1", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &rpg_kickspammers, "rpg_kickSpammers", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_kicksuiciders, "rpg_kickSuiciders", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_allowspmaps, "rpg_allowSPMaps", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_rangetricorder, "rpg_rangeTricorder", "128", CVAR_ARCHIVE, 0, qfalse }, { &rpg_rangehypo, "rpg_rangeHypo", "32", CVAR_ARCHIVE, 0, qfalse }, { &rpg_norpgclasses, "rpg_noRPGClasses", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &rpg_forceclasscolor, "rpg_forceClassColor", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &rpg_restrictions, "rpg_restrictions", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_dmgFlags, "rpg_dmgFlags", "63", CVAR_ARCHIVE, 0, qfalse }, { &rpg_noweapons, "rpg_noWeapons", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &rpg_welcomemessage, "rpg_welcomeMessage", "Welcome to the RPG-X Mod", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &rpg_timedmessagetime, "rpg_timedMessageTime", "0", CVAR_ARCHIVE, 0, qfalse }, //TiM : LATCH Not necessary here. { &rpg_forcekillradius, "rpg_forceKillRadius", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &rpg_forcekillradiuswaittime, "rpg_forceKillRadiusWaitTime", "45000", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &rpg_chatarearange, "rpg_chatAreaRange", "200", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, //Not latched (ie doesnt need server restart) { &rpg_forcefielddamage, "rpg_forcefieldDamage", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_invisibletripmines, "rpg_invisibleTripmines", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse }, { &rpg_medicsrevive, "rpg_medicsRevive", "1", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse }, { &rpg_effectsgun, "rpg_effectsGun", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse }, { &rpg_phaserdisintegrates, "rpg_phaserDisintegrates", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_kickAfterXkills, "rpg_kickAfterNumkills", "2", CVAR_ARCHIVE, 0, qfalse }, //RPG-X | Phenix | 06/04/2005 { &rpg_rankSet, "rpg_rankSet", RANKSET_DEFAULT, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, { &rpg_passMessage, "rpg_passMessage", "", CVAR_ARCHIVE, 0, qfalse }, { &rpg_renamedPlayers, "rpg_renamedPlayers", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_uniqueNames, "rpg_uniqueNames", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_startingRank, "rpg_startingRank", "", CVAR_ARCHIVE, 0, qfalse }, { &rpg_maxRank, "rpg_maxRank", "", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse }, { &rpg_changeRanks, "rpg_changeRanks", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_classSet, "rpg_classSet", "rpgx_default", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, { &rpg_maxHeight, "rpg_maxHeight", "1.15", CVAR_ARCHIVE, 0, qfalse }, { &rpg_minHeight, "rpg_minHeight", "0.90", CVAR_ARCHIVE, 0, qfalse }, { &rpg_maxWeight, "rpg_maxWeight", "1.10", CVAR_ARCHIVE, 0, qfalse }, { &rpg_minWeight, "rpg_minWeight", "0.90", CVAR_ARCHIVE, 0, qfalse }, { &rpg_mapGiveFlags, "rpg_mapGiveFlags", "0", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse }, //TiM - maybe we can fix it later, but for now, disable it { &rpg_scannablePanels, "rpg_scannablePanels", "1", CVAR_ARCHIVE | CVAR_LATCH | CVAR_SERVERINFO, 0, qfalse }, { &rpg_allowWeaponDrop, "rpg_allowWeaponDrop", "1", CVAR_ARCHIVE, 0, qfalse }, // RPG-X | Marcin | 03/12/2008 { &rpg_weaponsStay, "rpg_weaponsStay", "0", CVAR_ARCHIVE, 0, qfalse }, // RPG-X | Marcin | 04/12/2008 { &rpg_rifleSpeed, "rpg_rifleSpeed", "2700", 0, 0, qtrue }, // RPG-X | Marcin | 04/12/2008 { &rpg_disruptorSpeed, "rpg_disruptorSpeed", "3000", 0, 0, qtrue },// RPG-X | Marcin | 04/12/2008 { &rpg_photonSpeed, "rpg_photonSpeed", "1300", 0, 0, qtrue }, // RPG-X | Marcin | 05/12/2008 { &rpg_altPhotonSpeed, "rpg_altPhotonSpeed", "650", 0, 0, qtrue }, // RPG-X | Marcin | 06/12/2008 { &rpg_rifleDelay, "rpg_rifleDelay", "250", 0, 0, qtrue }, // RPG-X | Marcin | 06/12/2008 { &rpg_disruptorDelay, "rpg_disruptorDelay", "700", 0, 0, qtrue }, // RPG-X | Marcin | 06/12/2008 { &rpg_photonDelay, "rpg_photonDelay", "1200", 0, 0, qtrue }, // RPG-X | Marcin | 06/12/2008 { &rpg_altPhotonDelay, "rpg_altPhotonDelay", "1600", 0, 0, qtrue },// RPG-X | Marcin | 06/12/2008 { &rpg_TR116Delay, "rpg_TR116Delay", "500", 0, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_motdFile, "rpg_motdFile", "RPG-X_Motd.txt", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse }, // RPG-X | Marcin | 23/12/2008 { &rpg_respectPrivacy, "rpg_respectPrivacy", "0", CVAR_ARCHIVE | CVAR_SERVERINFO , 0, qfalse }, // RPG-X | Marcin | 24/12/2008 { &rpg_maxTricorders, "rpg_maxTricorders", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxPADDs, "rpg_maxPADDs", "10", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxCups, "rpg_maxCups", "2", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxPhasers, "rpg_maxPhasers", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxRifles, "rpg_maxRifles", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxTR116s, "rpg_maxTR116s", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxAdminguns, "rpg_maxAdminguns", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxPhotonbursts, "rpg_maxPhotonbursts", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxDisruptors, "rpg_maxDisruptors", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxMedkits, "rpg_maxMedkits", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxHyposprays, "rpg_maxHyposprays", "2", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxRegenerators, "rpg_maxRegenerators", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxToolkits, "rpg_maxToolkits", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_maxHyperSpanners, "rpg_maxHyperSpanners", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minTricorders, "rpg_minTricorders", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minPADDs, "rpg_minPADDs", "5", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minCups, "rpg_minCups", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minPhasers, "rpg_minPhasers", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minRifles, "rpg_minRifles", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minTR116s, "rpg_minTR116s", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minAdminguns, "rpg_minAdminguns", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minPhotonbursts, "rpg_minPhotonbursts", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minDisruptors, "rpg_minDisruptors", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minMedkits, "rpg_minMedkits", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minHyposprays, "rpg_minHyposprays", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minRegenerators, "rpg_minRegenerators", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minToolkits, "rpg_minToolkits", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_minHyperSpanners, "rpg_minHyperSpanners", "1", CVAR_ARCHIVE, 0, qtrue }, // RPG-X | Marcin | 30/12/2008 { &rpg_dropOnDeath, "rpg_dropItemsOnDeath", "1", CVAR_ARCHIVE, 0, qfalse }, // RPG-X | Marcin | 30/12/2008 { &rpg_fraggerSpawnDelay, "rpg_fraggerSpawnDelay", "100", CVAR_ARCHIVE, 0, qfalse }, { &rpg_borgAdapt, "rpg_borgAdapt", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_hypoMelee, "rpg_hypoMelee", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptUseSound, "rpg_adaptUseSound", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptCrifleHits, "rpg_adaptCrifleHits", "6", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptDisruptorHits, "rpg_adaptDisruptorHits", "6", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptPhaserHits, "rpg_adaptPhaserHits", "6", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptPhotonHits, "rpg_adaptPhotonHits", "6", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptTR116Hits, "rpg_adaptTR116Hits", "6", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adaptGrenadeLauncherHits,"rpg_adaptGrenadeLauncherHits", "6", CVAR_ARCHIVE, 0, qfalse }, { &rpg_repairModifier, "rpg_repairModifier", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_forceFieldColor, "rpg_forceFieldColor", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_allowRemodulation, "rpg_allowRemodulation", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_forceFieldFreq, "rpg_forceFieldFreq", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_calcLiftTravelDuration, "rpg_calcLiftTravelDuration", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_liftDurationModifier, "rpg_liftDurationModifier" , "0.5", CVAR_ARCHIVE, 0, qfalse }, { &rpg_altTricorderDelay, "rpg_altTricorderDelay", "1000", CVAR_ARCHIVE, 0, qfalse }, { &rpg_borgMoveThroughFields, "rpg_borgMoveThroughFields", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_RemodulationDelay, "rpg_RemodulationDelay", "5000", CVAR_ARCHIVE, 0, qfalse }, { &rpg_adminVoteOverride, "rpg_adminVoteOverride", "1", CVAR_ARCHIVE, 0, qfalse }, { &rpg_serverchange, "rpg_serverchange", "0", CVAR_ARCHIVE, 0, qfalse }, { &rpg_allowSPLevelChange, "rpg_allowSPLevelChange", "1", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse }, { &rpg_spEasterEggs, "rpg_spEasterEggs", "0", CVAR_ARCHIVE, 0, qfalse }, { &dev_showTriggers, "dev_showTriggers", "0", CVAR_ARCHIVE, 0, qfalse }, { &sql_use, "sql_use", "0", CVAR_ARCHIVE, 0, qfalse }, #ifdef G_LUA { &g_debugLua, "g_debugLua", "0", 0, 0, qfalse }, { &lua_allowedModules, "lua_allowedModules", "", 0, 0, qfalse }, { &lua_modules, "lua_modules", "", 0, 0, qfalse }, #endif { &rpg_rifleDamage, "rpg_rifleDamage", "75", CVAR_ARCHIVE, 0, qfalse }, { &rpg_rifleAltDamage, "rpg_rifleAltDamage", "16", CVAR_ARCHIVE, 0, qfalse }, { &rpg_phaserDamage, "rpg_phaserDamage", "55", CVAR_ARCHIVE, 0, qfalse }, { &rpg_disruptorDamage, "rpg_disruptorDamage", "80", CVAR_ARCHIVE, 0, qfalse }, { &rpg_grenadeDamage, "rpg_grenadeDamage", "75", CVAR_ARCHIVE, 0, qfalse }, { &rpg_grenadeAltDamage, "rpg_grenadeAltDamage", "80", CVAR_ARCHIVE, 0, qfalse }, { &rpg_tr116Damage, "rpg_tr116Damage", "150", CVAR_ARCHIVE, 0, qfalse }, { &rpg_photonDamage, "rpg_photonDamage", "140", CVAR_ARCHIVE, 0, qfalse }, { &rpg_photonAltDamage, "rpg_photonAltDamage", "140", CVAR_ARCHIVE, 0, qfalse }, { &g_developer, "g_developer", "0", CVAR_ARCHIVE, 0, qfalse } }; static int gameCvarTableSize = (int)(sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] )); static void G_InitGame( int levelTime, int randomSeed, int restart ); static void G_RunFrame( int levelTime ); void G_ShutdownGame( int restart ); static void CheckExitRules( void ); //============================= // begin code /* ================ vmMain This is the only way control passes into the module. This MUST be the very first function compiled into the .q3vm file ================ */ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, /*@unused@*/ int arg3, /*@unused@*/ int arg4, /*@unused@*/ int arg5, /*@unused@*/ int arg6 ) { switch ( command ) { case GAME_INIT: G_InitGame( arg0, arg1, arg2 ); return 0; case GAME_SHUTDOWN: G_ShutdownGame( arg0 ); return 0; case GAME_CLIENT_CONNECT: return (intptr_t)G_Client_Connect( arg0, (qboolean)arg1, (qboolean)arg2 ); case GAME_CLIENT_THINK: ClientThink( arg0 ); return 0; case GAME_CLIENT_USERINFO_CHANGED: G_Client_UserinfoChanged( arg0 ); //TiM - this means a user just tried to change it return 0; case GAME_CLIENT_DISCONNECT: G_Client_Disconnect( arg0 ); return 0; case GAME_CLIENT_BEGIN: G_Client_Begin( arg0, qtrue, qfalse, qtrue ); return 0; case GAME_CLIENT_COMMAND: G_Client_Command( arg0 ); return 0; case GAME_RUN_FRAME: G_RunFrame( arg0 ); return 0; case GAME_CONSOLE_COMMAND: //RPG-X : TiM - plagiarised Red's logic from SFEFMOD here lol return ConsoleCommand(); case BOTAI_START_FRAME: return (intptr_t)BotAIStartFrame( arg0 ); } return -1; } void QDECL G_PrintfClientAll(const char *fmt, ...) { va_list argptr; char text[1024]; va_start (argptr, fmt); vsprintf (text, fmt, argptr); va_end (argptr); trap_SendServerCommand(-1, va("print \"%s\n\"", text)); } void QDECL G_PrintfClient(gentity_t *ent, const char *fmt, ...) { va_list argptr; char text[1024]; va_start (argptr, fmt); vsprintf (text, fmt, argptr); va_end (argptr); #ifdef G_LUA LuaHook_G_ClientPrint(text, ent-g_entities); #endif trap_SendServerCommand(ent-g_entities, va("print \"%s\n\"", text)); } void QDECL G_Printf( const char *fmt, ... ) { va_list argptr; char text[1024]; va_start (argptr, fmt); vsprintf (text, fmt, argptr); va_end (argptr); if(trap_Cvar_VariableIntegerValue("developer")) { } #ifdef G_LUA // Lua API callbacks LuaHook_G_Print(text); #endif trap_Printf( text ); } void QDECL G_Error( const char *fmt, ... ) { va_list argptr; char text[1024]; va_start (argptr, fmt); vsprintf (text, fmt, argptr); va_end (argptr); #ifdef G_LUA G_LuaShutdown(); #endif trap_Error( text ); } stringID_table_t WeaponTable[] = { { ENUM2STRING(WP_2) }, { ENUM2STRING(WP_3) }, { ENUM2STRING(WP_4) }, { ENUM2STRING(WP_5) }, { ENUM2STRING(WP_6) }, { ENUM2STRING(WP_7) }, { ENUM2STRING(WP_8) }, { ENUM2STRING(WP_9) }, { ENUM2STRING(WP_10) }, { ENUM2STRING(WP_11) }, { ENUM2STRING(WP_12) }, { ENUM2STRING(WP_13) }, { ENUM2STRING(WP_14) }, { ENUM2STRING(WP_15) }, { "WP_TRICORDER", WP_2 }, { "WP_PADD", WP_3 }, { "WP_COFFEE", WP_4 }, { "WP_PHASER", WP_5 }, { "WP_COMPRESSION_RIFLE", WP_6 }, { "WP_TR116", WP_7 }, { "WP_GRENADE_LAUNCHER", WP_8 }, { "WP_QUANTUM_BURST", WP_9 }, { "WP_DISRUPTOR", WP_10 }, { "WP_MEDKIT", WP_11 }, { "WP_VOYAGER_HYPO", WP_12 }, { "WP_DERMAL_REGEN", WP_13 }, { "WP_TOOLKIT", WP_14 }, { "WP_HYPERSPANNER", WP_15 }, { NULL, -1 } }; /************************** G_LoadClassData TiM: Loads a ".class" file and parses the class data for utilization on the server and transfer to clients **************************/ static qboolean G_LoadClassData( char* fileName ) { char *buffer; char *textPtr, *token; int fileLen; fileHandle_t f; qboolean classValid=qfalse; int classIndex=0; int weapon; int i; //Init the storage place memset( &g_classData, 0, sizeof ( g_classData ) ); fileLen = trap_FS_FOpenFile( fileName, &f, FS_READ ); if ( !f ) { G_Printf( S_COLOR_RED "ERROR: File %s not found.\n", fileName ); return qfalse; } buffer = (char *)malloc((fileLen+1) * sizeof(char)); if(!buffer) { G_Printf( S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", (fileLen+1) * sizeof(char) ); trap_FS_FCloseFile( f ); return qfalse; } trap_FS_Read( buffer, fileLen, f ); buffer[fileLen] = 0; trap_FS_FCloseFile( f ); COM_BeginParseSession(); textPtr = buffer; token = COM_Parse( &textPtr ); if ( !token[0] ) { G_Printf( S_COLOR_RED "ERROR: No data was found when going to parse the file!\n" ); free(buffer); return qfalse; } if ( Q_stricmpn( token, "{", 1 ) ) { G_Printf( S_COLOR_RED "ERROR: File did not start with a '{' symbol!\n" ); free(buffer); return qfalse; } while ( 1 ) { if ( classIndex >= MAX_CLASSES ) break; if ( !Q_stricmpn( token, "{", 1 ) ) { while ( 1 ) { token = COM_Parse( &textPtr ); if (!token[0]) { break; } if ( !Q_stricmpn( token, "consoleName", 11 ) ) { if ( COM_ParseString( &textPtr, &token ) ) { G_Printf( S_COLOR_RED "ERROR: Invalid class console name in class index: %i.\n", classIndex ); SkipBracedSection( &textPtr ); continue; } Q_strncpyz( g_classData[classIndex].consoleName, token, sizeof( g_classData[classIndex].consoleName ) ); classValid = qtrue; continue; } if ( !Q_stricmpn( token, "formalName", 11 ) ) { if ( COM_ParseString( &textPtr, &token ) ) { G_Printf( S_COLOR_RED "ERROR: Invalid class formal name in class index: %i.\n", classIndex ); SkipBracedSection( &textPtr ); continue; } Q_strncpyz( g_classData[classIndex].formalName, token, sizeof( g_classData[classIndex].formalName ) ); classValid = qtrue; continue; } if ( !Q_stricmpn( token, "message", 7 ) ) { if ( COM_ParseString( &textPtr, &token ) ) { G_Printf( S_COLOR_RED "ERROR: Invalid class message in class index: %i.\n", classIndex ); continue; } Q_strncpyz( g_classData[classIndex].message, token, sizeof( g_classData[classIndex].message ) ); continue; } if ( !Q_stricmpn( token, "modelSkin", 9 ) ) { if ( COM_ParseString( &textPtr, &token ) ) { G_Printf( S_COLOR_RED "ERROR: Invalid class skin color in class index: %i.\n", classIndex ); continue; } Q_strncpyz( g_classData[classIndex].modelSkin, token, sizeof( g_classData[classIndex].modelSkin ) ); continue; } if ( !Q_stricmpn( token, "weapons", 7) ) { token = COM_Parse( &textPtr ); if ( Q_stricmpn( token, "{", 1 ) ) { G_Printf( S_COLOR_RED "No opening bracket found for weapons field in class: %i.\n", classIndex ); SkipRestOfLine( &textPtr ); continue; } //sub loop while ( 1 ) { token = COM_Parse( &textPtr ); if ( !token[0] ) break; if ( !Q_stricmpn( token, "|", 1 ) ) continue; if ( !Q_stricmpn( token, "}", 1 ) ) break; if( !Q_stricmpn( token, "WP_", 3 ) ) { weapon = GetIDForString( WeaponTable, token ); if ( weapon >= 0 ) { g_classData[classIndex].weaponsFlags |= ( 1 << weapon ); continue; } } } continue; } if ( !Q_stricmpn( token, "admin", 5 ) ) { if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isAdmin ) ) { G_Printf( S_COLOR_RED "ERROR: Class admin check for class %i was invalid.\n", classIndex ); continue; } continue; } if ( !Q_stricmpn( token, "marine", 6 ) ) { if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isMarine ) ) { G_Printf( S_COLOR_RED "ERROR: Class marine check for class %i was invalid.\n", classIndex ); continue; } continue; } if ( !Q_stricmpn( token, "medical", 7 ) ) { if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isMedical ) ) { G_Printf( S_COLOR_RED "ERROR: Class medic check for class %i was invalid.\n", classIndex ); continue; } continue; } if( !Q_stricmpn( token, "isBorg", 6 ) ) { if( COM_ParseInt( &textPtr, &g_classData[classIndex].isBorg ) ) { G_Printf( S_COLOR_RED "ERROR: Class borg check for class %i was invalid.\n", classIndex ); continue; } continue; } if ( !Q_stricmpn( token, "n00b", 4 ) ) { if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isn00b ) ) { G_Printf( S_COLOR_RED "ERROR: Class n00b check for class %i was invalid.\n", classIndex ); continue; } continue; } //skip the client-side specific entries since they interfere with the parsing if ( !Q_stricmpn( token, "radarColor", 10 ) || !Q_stricmpn( token, "iconColor", 9 ) || !Q_stricmpn( token, "hasRanks", 8 ) || !Q_stricmpn( token, "noShow", 6 ) ) { SkipRestOfLine( &textPtr ); continue; } if ( !Q_stricmpn( token, "}", 1 ) ) { break; } } if ( classValid ) { classIndex++; classValid = qfalse; } } token = COM_Parse( &textPtr ); if (!token[0]) { break; } } free(buffer); //build ourselves custom CVARs for each class for ( i=0; g_classData[i].consoleName[0] && i < MAX_CLASSES; i++ ) { trap_Cvar_Register( NULL, va("rpg_%sPass", g_classData[i].consoleName ), g_classData[i].consoleName, CVAR_ARCHIVE ); trap_Cvar_Register( NULL, va("rpg_%sFlags", g_classData[i].consoleName ), va("%i", g_classData[i].weaponsFlags), CVAR_ARCHIVE ); } if ( classIndex > 0 ) { return qtrue; } else { G_Printf( S_COLOR_RED "ERROR: No valid classes were found.\n"); return qfalse; } } void BG_LanguageFilename(char *baseName,char *baseExtension,char *finalName); void SP_target_location (gentity_t *ent); static void G_LoadTimedMessages(void) { fileHandle_t f; bgLex* lexer; char* buffer; int len; len = trap_FS_FOpenFile("timedmessages.cfg", &f, FS_READ); if(!len) return; buffer = (char *)malloc(sizeof(char) * (len+1)); if(!buffer) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i byte.\n", (len+1) * sizeof(char) ); trap_FS_FCloseFile(f); return; } memset(buffer, 0, len+1); level.timedMessages = create_list(); if(level.timedMessages == NULL) { G_Printf(S_COLOR_RED "ERROR: Could not create list for timed messages.\n"); trap_FS_FCloseFile(f); free(buffer); return; } trap_FS_Read(buffer, len, f); trap_FS_FCloseFile(f); lexer = bgLex_create(buffer); if(lexer == NULL) { G_Printf(S_COLOR_RED "ERROR: Could not create new bgLex to lex timed messages.\n"); free(buffer); return; } while(bgLex_lex(lexer)) { if(lexer->morphem->type == LMT_STRING) { level.timedMessages->append(level.timedMessages, lexer->morphem->data.str, LT_STRING, strlen(lexer->morphem->data.str)); } else { G_Printf(S_COLOR_YELLOW "WARNING: Unexpected token in timedmessages.cfg:%d:%d!\n", lexer->morphem->line, lexer->morphem->column); } } G_Printf("Loaded %d timed messages.\n", level.timedMessages->length); bgLex_destroy(lexer); free(buffer); } holoData_t holoData; static void G_LoadHolodeckFile(void) { char fileRoute[MAX_QPATH]; char mapRoute[MAX_QPATH]; char *info; fileHandle_t f; char *buffer; int file_len; char *txtPtr, *token; int numProgs = 0; info = (char *)malloc(MAX_INFO_STRING * sizeof(char)); if(!info) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i byte.\n", MAX_INFO_STRING * sizeof(char) ); return; } //get the map name out of the server data trap_GetServerinfo( info, MAX_INFO_STRING * sizeof(char) ); //setup the file route Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s", Info_ValueForKey( info, "mapname" ) ); BG_LanguageFilename( mapRoute, "holodeck", fileRoute ); file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ ); free(info); if ( !file_len ) return; buffer = (char *)malloc(32000 * sizeof(char)); if(!buffer) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char) ); trap_FS_FCloseFile(f); return; } trap_FS_Read( buffer, file_len, f ); if ( !buffer[0] ) { G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute ); trap_FS_FCloseFile( f ); free(buffer); return; } buffer[file_len] = '\0'; trap_FS_FCloseFile( f ); memset(&holoData, 0, sizeof(holoData)); COM_BeginParseSession(); txtPtr = buffer; while(1) { token = COM_Parse(&txtPtr); if(!token[0]) break; if(!Q_stricmpn(token, "HolodeckData", 12)) { token = COM_Parse(&txtPtr); if(Q_stricmpn(token, "{", 1)) { G_Printf( S_COLOR_RED "ERROR: HolodeckData had no opening brace ( { )!\n"); continue; } while(Q_stricmpn(token, "}", 1)) { token = COM_Parse(&txtPtr); if(!token[0]) break; if(!Q_stricmpn(token, "Program", 7)) { token = COM_Parse(&txtPtr); if(Q_stricmpn(token, "[", 1)) { G_Printf( S_COLOR_RED "ERROR: Program had no opening brace ( [ )!\n"); continue; } // expected format: // - target notnull // - name // - desc1 // - desc2 // - image while(Q_stricmpn(token, "]", 1)) { if(!token[0]) break; if(numProgs >= 5) { free(buffer); return; } // targetname of info_notnull token = COM_Parse(&txtPtr); Q_strncpyz(holoData.target[numProgs], token, sizeof(holoData.target[numProgs])); // parse name token = COM_Parse(&txtPtr); Q_strncpyz(holoData.name[numProgs], token, sizeof(holoData.name[numProgs])); // parse desc1 token = COM_Parse(&txtPtr); Q_strncpyz(holoData.desc1[numProgs], token, sizeof(holoData.desc1[numProgs])); // parse desc2 token = COM_Parse(&txtPtr); Q_strncpyz(holoData.desc2[numProgs], token, sizeof(holoData.desc2[numProgs])); // parse image token = COM_Parse(&txtPtr); Q_strncpyz(holoData.image[numProgs], token, sizeof(holoData.image[numProgs])); holoData.active = -1; numProgs++; token = COM_Parse(&txtPtr); } } } } } holoData.numProgs = numProgs; free(buffer); } static void G_LoadServerChangeFile(void) { char fileRoute[MAX_QPATH]; fileHandle_t f; bgLex* lex; char* buffer; int file_len; BG_LanguageFilename("serverchange", "cfg", fileRoute); file_len = trap_FS_FOpenFile(fileRoute, &f, FS_READ); if(!file_len) { return; } // TODO dynamic buffer size buffer = (char *)malloc((file_len + 1) * sizeof(char)); if(!buffer) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", (file_len + 1) * sizeof(char) ); trap_FS_FCloseFile(f); return; } trap_FS_Read(buffer, file_len, f); if ( !buffer[0] ) { G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute ); trap_FS_FCloseFile( f ); free(buffer); return; } buffer[file_len] = '\0'; trap_FS_FCloseFile(f); memset(&level.srvChangeData, 0, sizeof(&level.srvChangeData)); G_Printf("Loading ServerChangeConfig '%s'.\n", fileRoute); lex = bgLex_create(buffer); if(lex == NULL) { G_Printf(S_COLOR_RED "ERROR: Could not create bgLex to lex ServerChangeConfig.\n"); free(buffer); return; } if(bgLex_lex(lex) != LMT_SYMBOL || lex->morphem->data.symbol != LSYM_SERVER_CHANGE_CONFIG) { G_Printf(S_COLOR_RED "ERROR: Expected 'ServerChangeConfig' at beginning of %s.\n", fileRoute); free(buffer); bgLex_destroy(lex); return; } if(bgLex_lex(lex) != LMT_SYMBOL || lex->morphem->data.symbol != LSYM_OBRACEC) { G_Printf(S_COLOR_RED "ERROR: Missing '{' at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } while(bgLex_lex(lex)) { if(lex->morphem->type == LMT_SYMBOL && lex->morphem->data.symbol == LSYM_CBRACEC) { break; } if(lex->morphem->type == LMT_SYMBOL && lex->morphem->data.symbol == LSYM_SERVER) { if(bgLex_lex(lex) != LMT_SYMBOL || lex->morphem->data.symbol != LSYM_OBRACESQ) { G_Printf(S_COLOR_RED "ERROR: Missing '[' at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } if(bgLex_lex(lex) == LMT_STRING) { strncpy(level.srvChangeData.ip[level.srvChangeData.count], lex->morphem->data.str, sizeof(level.srvChangeData.ip[level.srvChangeData.count])); } else { G_Printf(S_COLOR_RED "ERROR: Unexpected token at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } if(bgLex_lex(lex) == LMT_STRING) { strncpy(level.srvChangeData.name[level.srvChangeData.count], lex->morphem->data.str, sizeof(level.srvChangeData.name[level.srvChangeData.count])); } else { G_Printf(S_COLOR_RED "ERROR: Unexpected token at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); memset(level.srvChangeData.ip[level.srvChangeData.count], 0, sizeof(level.srvChangeData.ip[level.srvChangeData.count])); return; } level.srvChangeData.count++; if(bgLex_lex(lex) != LMT_SYMBOL || lex->morphem->data.symbol != LSYM_CBRACESQ) { G_Printf(S_COLOR_RED "ERROR: Missing ']' at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } } else { G_Printf(S_COLOR_RED "ERROR: Unexpected token at %d:%d. Expected '}' or 'Server'\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } } bgLex_destroy(lex); free(buffer); } static mapChangeData_t mapChangeData; static void G_LoadMapChangeFile(void) { char fileRoute[MAX_QPATH]; fileHandle_t f; char *buffer; int file_len; char *txtPtr, *token; int cnt = 0; int i = 0; BG_LanguageFilename("mapchange", "cfg", fileRoute); file_len = trap_FS_FOpenFile(fileRoute, &f, FS_READ); if(!file_len) return; buffer = (char *)malloc(32000 * sizeof(char)); if(!buffer) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char) ); trap_FS_FCloseFile(f); return; } trap_FS_Read(buffer, file_len, f); if ( !buffer[0] ) { G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute ); trap_FS_FCloseFile( f ); free(buffer); return; } buffer[file_len] = '\0'; trap_FS_FCloseFile(f); memset(&mapChangeData, 0, sizeof(mapChangeData)); COM_BeginParseSession(); txtPtr = buffer; while(1) { token = COM_Parse(&txtPtr); if(!token[0]) break; if(!Q_stricmp(token, "MapChangeConfig")) { token = COM_Parse( &txtPtr ); if ( Q_strncmp( token, "{", 1 ) != 0 ) { G_Printf( S_COLOR_RED "ERROR: MapChangeConfig had no opening brace ( { )!\n" ); continue; } while(Q_strncmp(token, "}", 1)) { token = COM_Parse(&txtPtr); if(!token[0]) break; if(!Q_stricmp(token, "Map")) { token = COM_Parse(&txtPtr); if ( Q_strncmp( token, "[", 1 ) != 0 ) { G_Printf( S_COLOR_RED "ERROR: Server had no opening brace ( [ )!\n" ); continue; } token = COM_Parse(&txtPtr); while(Q_strncmp(token, "]", 1)) { if(!token[0]) break; if(cnt > 12) break; if(cnt % 2 == 0) Q_strncpyz(mapChangeData.name[i], token, sizeof(mapChangeData.name[i])); else Q_strncpyz(mapChangeData.bspname[i], token, sizeof(mapChangeData.bspname[i])); cnt++; if(cnt % 2 == 0) i++; token = COM_Parse(&txtPtr); } } } } } free(buffer); } static void G_LoadLocationsFile( void ) { char fileRoute[MAX_QPATH]; char mapRoute[MAX_QPATH]; char *serverInfo; fileHandle_t f; bgLex* lex; char *buffer; int file_len; vec3_t origin, angles; gentity_t *ent; char *desc; int rest = 0; serverInfo = (char *)malloc(MAX_INFO_STRING * sizeof(char)); if(!serverInfo) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", MAX_INFO_STRING * sizeof(char)); return; } //get the map name out of the server data trap_GetServerinfo( serverInfo, MAX_INFO_STRING * sizeof(char) ); //setup the file route Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s", Info_ValueForKey( serverInfo, "mapname" ) ); BG_LanguageFilename( mapRoute, "locations", fileRoute ); file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ ); free(serverInfo); if ( !file_len ) return; buffer = (char *)malloc((file_len+1) * sizeof(char)); if(!buffer) { G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", (file_len+1) * sizeof(char)); trap_FS_FCloseFile(f); return; } trap_FS_Read( buffer, file_len, f ); if ( !buffer[0] ) { G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute ); trap_FS_FCloseFile( f ); free(buffer); return; } buffer[file_len] = '\0'; trap_FS_FCloseFile( f ); G_Printf( "Locations file %s located. Proceeding to load scan data.\n", fileRoute ); //GSIO01: why did this say "Usables file ..."? lol ;) lex = bgLex_create(buffer); if(lex == NULL) { G_Printf(S_COLOR_RED "ERROR: Could not create bgLex to lex locations file.\n"); free(buffer); return; } if(bgLex_lex(lex) != LMT_SYMBOL) { G_Printf(S_COLOR_RED "ERROR: Expected locations file to begin with 'LocationsList' or 'LocationsList2'.\n"); free(buffer); bgLex_destroy(lex); return; } if(lex->morphem->data.symbol == LSYM_LOCATIONS_LIST || lex->morphem->data.symbol == LSYM_LOCATIONS_LIST_2) { if(bgLex_lex(lex) == LMT_SYMBOL && lex->morphem->data.symbol == LSYM_OBRACEC) { if(!bgLex_lex(lex)) { G_Printf(S_COLOR_RED "ERROR: Unexpected end of file.\n"); free(buffer); bgLex_destroy(lex); return; } } else { G_Printf(S_COLOR_YELLOW "WARNING: LocationsList2 had no opening brace '{'!\n"); } while(1) { if(lex->morphem->type == LMT_SYMBOL && lex->morphem->data.symbol == LSYM_CBRACEC) { break; } if(lex->morphem->type == LMT_VECTOR3) { VectorCopy(lex->morphem->data.vector3, origin); } else { G_Printf(S_COLOR_RED "ERROR: Expected vector at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } if(bgLex_lex(lex) == LMT_VECTOR3) { VectorCopy(lex->morphem->data.vector3, angles); } else { G_Printf(S_COLOR_RED "ERROR: Expected vector at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } if(bgLex_lex(lex) == LMT_STRING) { int result; desc = G_NewString(lex->morphem->data.str); if((result = bgLex_lex(lex)) == LMT_STRING) { rest = atoi(desc); desc = G_NewString(lex->morphem->data.str); if(!bgLex_lex(lex)) { G_Printf(S_COLOR_RED "ERROR: Unexpected end of file.\n"); free(buffer); bgLex_destroy(lex); return; } } else { if(!result) { G_Printf(S_COLOR_RED "ERROR: Unexpected end of file.\n"); free(buffer); bgLex_destroy(lex); return; } } } else { G_Printf(S_COLOR_RED "ERROR: Expected string at %d:%d.\n", lex->morphem->line, lex->morphem->column); free(buffer); bgLex_destroy(lex); return; } //create a new entity ent = G_Spawn(); if ( !ent ) { G_Printf( S_COLOR_RED "Couldn't create entity in %s!\n", fileRoute ); free(buffer); bgLex_destroy(lex); return; } ent->classname = "target_location"; //copy position data VectorCopy( origin, ent->s.origin ); VectorCopy( angles, ent->s.angles ); //copy string ent->message = G_NewString( desc ); //copy desc into target as well ent->target = ent->targetname = G_NewString( desc ); // copy restriction value ent->sound1to2 = rest; //initiate it as a location ent SP_target_location( ent ); //reset the ent ent = NULL; rest = 0; if(lex->morphem->type == LMT_SYMBOL && lex->morphem->data.symbol == LSYM_SEMICOLON) { if(!bgLex_lex(lex)) { G_Printf(S_COLOR_RED "ERROR: Unexpected end of file.\n"); free(buffer); bgLex_destroy(lex); return; } } else { G_Printf(S_COLOR_YELLOW "WARNING: Missing ';' at %d:%d.\n", lex->morphem->line, lex->morphem->column); } } } else { G_Printf(S_COLOR_RED "ERROR: Unexpected token at %s:%d:%d. ", fileRoute, lex->morphem->line, lex->morphem->column); G_Printf(S_COLOR_RED "Expected 'LocationsList' or 'LocationsList2'.\n"); free(buffer); bgLex_destroy(lex); return; } if(lex->morphem->type != LMT_SYMBOL || lex->morphem->data.symbol != LSYM_CBRACEC) { G_Printf(S_COLOR_YELLOW "WARNING: Missing closing brace '}'!\n"); } free(buffer); bgLex_destroy(lex); } #define MAX_GROUP_FILE_SIZE 5000 char *G_searchGroupList(const char *name) { char *text_p = NULL, *slash = NULL; char text[MAX_GROUP_FILE_SIZE]; int i; char mod_name[200]; memset (races, 0, sizeof(races)); memset (text, 0, sizeof(text)); // check to see if there is a '/' in the name Q_strncpyz(mod_name, name, sizeof(mod_name)); slash = strstr( mod_name, "/" ); if ( slash != NULL ) {//drop the slash and everything after it for the purpose of finding the model name in th group *slash = 0; } // find the name in the group list for (i=0; iinuse) continue; if (!e->team) continue; if (e->flags & FL_TEAMSLAVE) continue; if ( e->classname && Q_stricmp( "func_door", e->classname ) != 0 ) {//not a door if ( Q_stricmp( "1", e->team ) == 0 || Q_stricmp( "2", e->team ) == 0 ) {//is trying to tell us it belongs to the TEAM_RED or TEAM_BLUE continue; } } e->teammaster = e; c++; c2++; for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++) { if (!e2->inuse) continue; if (!e2->team) continue; if (e2->flags & FL_TEAMSLAVE) continue; if (!strcmp(e->team, e2->team)) { c2++; e2->teamchain = e->teamchain; e->teamchain = e2; e2->teammaster = e; e2->flags |= FL_TEAMSLAVE; // make sure that targets only point at the master if ( e2->targetname ) { e->targetname = e2->targetname; e2->targetname = NULL; } } } } G_Printf ("%i teams with %i entities\n", c, c2); } /* ================= G_RegisterCvars ================= */ static void G_RegisterCvars( void ) { int i; cvarTable_t *cv; for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) { if ( rpg_rpg.integer != 0 ) { trap_Cvar_Set( "g_gametype", "0" );//RPG-X: RedTechie - Make sure we keep gametype at 0 } trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags ); if ( cv->vmCvar ) { cv->modificationCount = cv->vmCvar->modificationCount; } } // check some things if ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) { G_Printf( "g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer ); trap_Cvar_Set( "g_gametype", "0" ); } } /* ================= G_UpdateCvars ================= */ static void G_UpdateCvars( void ) { int i; cvarTable_t *cv; for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) { if ( cv->vmCvar ) { trap_Cvar_Update( cv->vmCvar ); if ( cv->modificationCount != cv->vmCvar->modificationCount ) { cv->modificationCount = cv->vmCvar->modificationCount; if ( cv->trackChange ) { if ( !levelExiting ) {//no need to do this during level changes //RPG-X: J2J - Don't show gravity changed messages any more (for the gravity target ents) if(Q_stricmp(cv->cvarName,"g_gravity") != 0) { trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"", cv->cvarName, cv->vmCvar->string ) ); } } } } } } } extern int altAmmoUsage[]; static void G_InitModRules( void ) { numKilled = 0; } static void Dev_ShowTriggers(gentity_t *ent) { int i; gentity_t *tar; ent->nextthink = level.time + 9500; for(i = 0; i < MAX_GENTITIES; i++) { if((tar = &g_entities[i]) == NULL) continue; if(!Q_stricmpn(tar->classname, "trigger_", 8)) { if(!Q_stricmp(tar->classname, "trigger_always")) continue; if(tar->r.svFlags & SVF_NOCLIENT) tar->r.svFlags ^= SVF_NOCLIENT; trap_LinkEntity(ent); if(!Q_stricmpn(tar->classname, "trigger_push", 13)) G_AddEvent(tar, EV_TRIGGER_SHOW, 1); else G_AddEvent(tar, EV_TRIGGER_SHOW, 0); } } } /* ============ G_InitGame ============ */ extern int lastKillTime[]; extern int LastFKRadius[]; //(RPG-X J2J) added so array can be initialised to 0 first. extern RPGX_SiteTOSiteData TransDat[]; //(RPG-X J2J) added for tricorder transporter extern RPGX_DragData DragDat[]; void G_InitGame( int levelTime, int randomSeed, int restart ) { int i; char fileName[MAX_QPATH]; float messageTime; G_Printf ("------- Game Initialization -------\n"); G_Printf ("gamename: %s\n", GAMEVERSION); G_Printf ("gamedate: %s\n", __DATE__); level.overrideCalcLiftTravelDuration = 0; init_tonextint(qtrue); srand( randomSeed ); numKilled = 0; level.numObjectives = 0;//no objectives by default G_RegisterCvars(); G_ProcessIPBans(); G_ProcessIDBans(); G_InitMemory(); //G_initGroupsList(); BG_LoadItemNames(); // set some level globals memset( &level, 0, sizeof( level ) ); //Class loader memset( fileName, 0, sizeof( fileName ) ); Com_sprintf( fileName, sizeof( fileName ), "ext_data/classes/%s.classes", rpg_classSet.string ); if ( !G_LoadClassData( fileName ) ) { G_Printf( S_COLOR_RED "ERROR: Could not load class set %s. Reverting to default.\n", fileName ); trap_Cvar_Set( "rpg_classSet", CLASS_DEFAULT ); if ( !G_LoadClassData( va( "ext_data/classes/%s.classes", CLASS_DEFAULT ) ) ) { G_Error( "Could not load default class set: %s", CLASS_DEFAULT ); } } //Rank Loader memset( fileName, 0, sizeof( fileName ) ); Com_sprintf( fileName, sizeof( fileName ), "ext_data/ranksets/%s.ranks", rpg_rankSet.string ); if ( !BG_ParseRankNames( fileName, g_rankNames ) ) { G_Printf( S_COLOR_RED "ERROR: Could not load rankset %s. Reverting to default.\n", fileName ); trap_Cvar_Set( "rpg_rankSet", RANKSET_DEFAULT ); if ( !BG_ParseRankNames( va( "ext_data/ranksets/%s.ranks", RANKSET_DEFAULT ), g_rankNames ) ) { G_Error( "Could not load default rankset: %s", RANKSET_DEFAULT ); } } level.time = levelTime; level.startTime = levelTime; level.restarted = (qboolean)restart; //level.message = levelTime - (int)(rpg_timedmessagetime.value * 60000) + 30000; if ( rpg_timedmessagetime.value < 0.2 ) { messageTime = 0.2; } else { messageTime = rpg_timedmessagetime.value; } level.message = levelTime + (messageTime * 60000); level.snd_fry = G_SoundIndex("sound/player/fry.wav"); // FIXME standing in lava / slime if ( g_gametype.integer != GT_SINGLE_PLAYER && g_log.string[0] ) { if ( g_logSync.integer ) { trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_SYNC ); } else { trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND ); } if ( !level.logFile ) { G_Printf( "WARNING: Couldn't open logfile: %s\n", g_log.string ); } else { char serverinfo[MAX_INFO_STRING]; trap_GetServerinfo( serverinfo, sizeof( serverinfo ) ); G_LogPrintf("------------------------------------------------------------\n" ); G_LogPrintf("InitGame: %s\n", serverinfo ); } } else { G_Printf( "Not logging to disk.\n" ); } #ifdef G_LUA G_LuaInit(); #endif G_LogWeaponInit(); G_InitWorldSession(); // initialize all entities for this game memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) ); level.gentities = g_entities; // initialize all clients for this game level.maxclients = g_maxclients.integer; memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) ); level.clients = g_clients; // set client fields on player ents for ( i=0 ; i= GT_TEAM || trap_Cvar_VariableIntegerValue( "com_buildScript" ) != 0) { G_ModelIndex( TEAM_PODIUM_MODEL ); } if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) != 0 ) { BotAISetup( restart ); BotAILoadMap( restart ); G_InitBots( (qboolean)restart ); } G_InitModRules(); levelExiting = qfalse; /*RPG-X J2J************************************************************************************/ G_Printf ("Initializing RPG-X Globals..."); //WARNING - used hard coded number to shut up compiler, 1023 is MAX_ENTITIES (which apperently cant be increased without substansial exe recoding) //TiM : NB Ents 0 -> 128 are clients only. cyclicng thru all ents here is not needed. for(i = 0; i < MAX_CLIENTS; i++) { //RPG-X: Redtechie - Make sure score cant be chnaged unless other wise told to if(g_entities[i].client){ g_entities[i].client->UpdateScore = qfalse; g_entities[i].client->AdminFailed = 0; // RPG-X | Phenix | 21/11/2004 | Init Admin Failed Integer g_entities[i].client->LoggedAsAdmin = qfalse; g_entities[i].client->LoggedAsDeveloper = qfalse; } } for ( i = 0; i < MAX_CLIENTS; i++ ) { lastKillTime[i] = level.time-30000; //FKR LastFKRadius[i] = level.time - rpg_forcekillradiuswaittime.integer; //Transporter memset( &TransDat[i], 0, sizeof( TransDat[i] ) ); TransDat[i].LastClick = level.time-5000; //Make last click current time less 5 seconds. //Drag Data DragDat[i].AdminId = -1; } G_Printf( "%i entities loaded.\n", level.num_entities ); G_Printf ("COMPLETED\n"); #ifdef G_LUA LuaHook_G_InitGame(levelTime, randomSeed, restart); #endif if(dev_showTriggers.integer != 0 && restart == 0) { gentity_t *t; t = G_Spawn(); if(t) { t->think = Dev_ShowTriggers; t->nextthink = level.time + 1000; } } #ifdef SQL if(G_Sql_Init()) { G_Printf("SQL initialization successful.\n"); } else { G_Printf(S_COLOR_RED "Error: SQL initialization failed!\n"); } #endif /*************************************************************************************************/ G_Printf(" ,. \n"); G_Printf(" ..:, :Xt. ,:. \n"); G_Printf(" ,=+t: .IRX= :++=. \n"); G_Printf(" .=iVt:. :RYYI. .itt+ \n"); G_Printf(" .:tXI=;. tRtiV; ,IYY:. \n"); G_Printf(" .+;ii=;. ,XVi+Vt. :tIi+ \n"); G_Printf(" .;ti;;:. +RI++IY, ,+tt=. \n"); G_Printf(" ,++YY;. ,XXi+++X= ;IYI=. \n"); G_Printf(" ;ttY+;. .,=iVRI++++YX+;. ;VYt; \n"); G_Printf(" .;ii+=, .;IXRRXVi++++iVRXVi:. ,=iii. \n"); G_Printf(" .==;ti, .;YRRVVXYii+++++IVIVRXt, ,+=tI= \n"); G_Printf(" .iitY=, .tRRVXXVRV+++ii++YRXVIYXV; :tYti, \n"); G_Printf(" .+iii=,,IBVVXYiiXViiiiiiitVtIXViVR= ,+t+I: \n"); G_Printf(" =+=I:.tBVXVt=;tRIiiiiiiiiXi:=YXiIX; :+=It; \n"); G_Printf(" .;;tYt:;RVVV+=:,YRiiiiiiiiiYI,.:IXiVY..+IYi= \n"); G_Printf(" .ti=t+;tRIXi;, :XViiiiiiiiiIV: ,YViX=.:titt. \n"); G_Printf(" iY++I;YVYY=: +BIiiiiiiiiiiX= +XiVi;i++Vi, \n"); G_Printf(" ,+YYYI:VYYY;. .YRiiiiiiiiiiiVt. ;RIYt:IIVVi: \n"); G_Printf(" ,+tYXi;YVIX; ;RVtiiiiIXXtiiVI, iRIVt,=XVit: \n"); G_Printf(" .+iiti++XiXI. iBIiiiiYXIIXtiIV: :XXIV++;i+iI;.\n"); G_Printf(" ;Ii=ii:VYtRi,VRtiiiVVi=;IXitX=;VBYXI=i+;iV+;.\n"); G_Printf(" ;tYtVt;;XYIRXBVttiVV+;:.:VYiXVRBVXY+;+IYVt+, \n"); G_Printf(" =iiItii,=XVIRRIttXV+=:..,tRtVBXVRI+=i:iIit+. \n"); G_Printf(" :t==++I:.=YXYIIiYBXYIttIVRBYtVXXI+;;t+;;+Y=, \n"); G_Printf(" +I=;+Y= .:IRItYIVXRRRBBRXXVIRY+=;.:i=;iVi;. \n"); G_Printf(" .+IYVV+: +BYXXVXXXXXXXXXVRVVi;:.:;tVYY+=: \n"); G_Printf(" .+ttii+ .IBXY++ittIIIti++tXXi, .++=tI+;: \n"); G_Printf(" ;YYtIY;;VBI+;:,::;;;;;:,:IBt,::tItYV=. \n"); G_Printf(" =IYYI++ti+;, ....... :Xt;i=iYYI+;. \n"); G_Printf(" .:+i++ii;;. .=i=+i=t+;;:. \n"); G_Printf(" ,tYIVI==:,.. ..,;=+iYIVt:.. \n"); G_Printf(" ,itt+iIYYti;. ,;itYIIt:iIi=;. \n"); G_Printf(" .:;;:+tIIVIi:.;iYYIii+=:,;;:. \n"); G_Printf(" . ,:=itIXi.tXYit=;::, . \n"); G_Printf(" .+tti=,,iIt+;. \n"); G_Printf(" .:;;:. ,;;;:. \n"); } extern list_iter_p iterTimedMessages; /* list iterator for timed messages */ void G_ShutdownGame( int restart ) { G_Printf ("==== ShutdownGame ====\n"); #ifdef G_LUA LuaHook_G_Shutdown(restart); G_LuaShutdown(); #endif #if 0 // kef -- Pat sez this is causing some trouble these days G_LogWeaponOutput(); #endif if ( level.logFile != 0) { G_LogPrintf("ShutdownGame:\n" ); G_LogPrintf("------------------------------------------------------------\n" ); trap_FS_FCloseFile( level.logFile ); } // write all the client session data so we can get it back G_WriteSessionData(); if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) != 0 ) { BotAIShutdown( restart ); } if(level.timedMessages != NULL) { destroy_list(level.timedMessages); } destroy_iterator(iterTimedMessages); #ifdef SQL G_Sql_Shutdown(); #endif } //=================================================================== #ifndef GAME_HARD_LINKED // this is only here so the functions in q_shared.c and bg_*.c can link void QDECL Com_Error ( int errlevel, const char *error, ... ) { va_list argptr; char text[1024]; UNUSED(errlevel); va_start (argptr, error); vsnprintf(text, sizeof(text), error, argptr); va_end (argptr); G_Error( "%s", text); } void QDECL Com_Printf( const char *msg, ... ) { va_list argptr; char text[1024]; va_start (argptr, msg); vsnprintf(text, sizeof(text), msg, argptr); va_end (argptr); G_Printf ("%s", text); } #endif /* ======================================================================== PLAYER COUNTING / SCORE SORTING ======================================================================== */ /* ======================= RemoveTournamentLoser Make the loser a spectator at the back of the line ======================= */ static void RemoveTournamentLoser( void ) { int clientNum; if ( level.numPlayingClients != 2 ) { return; } clientNum = level.sortedClients[1]; if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) { return; } // make them a spectator SetTeam( &g_entities[ clientNum ], "s" ); } /* ======================= AdjustTournamentScores ======================= */ static void AdjustTournamentScores( void ) { int clientNum; clientNum = level.sortedClients[0]; if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { level.clients[ clientNum ].sess.wins++; G_Client_UserinfoChanged( clientNum ); } clientNum = level.sortedClients[1]; if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { level.clients[ clientNum ].sess.losses++; G_Client_UserinfoChanged( clientNum ); } } /* ============= SortRanks ============= */ static int QDECL SortRanks( const void *a, const void *b ) { gclient_t *ca, *cb; ca = &level.clients[*(int *)a]; cb = &level.clients[*(int *)b]; // sort special clients last if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) { return 1; } if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0 ) { return -1; } // then connecting clients if ( ca->pers.connected == CON_CONNECTING ) { return 1; } if ( cb->pers.connected == CON_CONNECTING ) { return -1; } // then spectators if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) { if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) { return -1; } if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) { return 1; } return 0; } if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) { return 1; } if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) { return -1; } // then sort by score & number of times killed if ( ca->ps.persistant[PERS_SCORE] > cb->ps.persistant[PERS_SCORE] ) { return -1; } if ((ca->ps.persistant[PERS_SCORE] == cb->ps.persistant[PERS_SCORE]) && (ca->ps.persistant[PERS_KILLED] < cb->ps.persistant[PERS_KILLED]) ) { return -1;} if ( ca->ps.persistant[PERS_SCORE] < cb->ps.persistant[PERS_SCORE] ) { return 1; } if ((ca->ps.persistant[PERS_SCORE] == cb->ps.persistant[PERS_SCORE]) && (ca->ps.persistant[PERS_KILLED] > cb->ps.persistant[PERS_KILLED]) ) { return 1;} return 0; } /* ============ G_Client_CalculateRanks Recalculates the score ranks of all players This will be called on every client connect, begin, disconnect, death, and team change. FIXME: for elimination, the last man standing must be ranked first ============ */ void G_Client_CalculateRanks( qboolean fromExit ) { int i; int rank; int score; int newScore; gclient_t *cl; level.follow1 = -1; level.follow2 = -1; level.numConnectedClients = 0; level.numNonSpectatorClients = 0; level.numPlayingClients = 0; level.numVotingClients = 0; // don't count bots for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[i].pers.connected != CON_DISCONNECTED ) { level.sortedClients[level.numConnectedClients] = i; level.numConnectedClients++; if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) { level.numNonSpectatorClients++; // decide if this should be auto-followed if ( level.clients[i].pers.connected == CON_CONNECTED ) { level.numPlayingClients++; if ( (g_entities[i].r.svFlags & SVF_BOT) == 0 ) { level.numVotingClients++; } if ( level.follow1 == -1 ) { level.follow1 = i; } else if ( level.follow2 == -1 ) { level.follow2 = i; } } } } } qsort( level.sortedClients, (size_t)level.numConnectedClients, sizeof(level.sortedClients[0]), SortRanks ); // set the rank value for all clients that are connected and not spectators if ( g_gametype.integer >= GT_TEAM ) { // in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied for ( i = 0; i < level.numConnectedClients; i++ ) { cl = &level.clients[ level.sortedClients[i] ]; if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) { cl->ps.persistant[PERS_RANK] = 2; } else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) { cl->ps.persistant[PERS_RANK] = 0; } else { cl->ps.persistant[PERS_RANK] = 1; } } } else { rank = -1; score = 0; for ( i = 0; i < level.numPlayingClients; i++ ) { cl = &level.clients[ level.sortedClients[i] ]; newScore = cl->ps.persistant[PERS_SCORE]; if ( i == 0 || newScore != score ) { rank = i; // assume we aren't tied until the next client is checked level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank; } else { // we are tied with the previous client level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG; level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG; } score = newScore; if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) { level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG; } } } // set the CS_SCORES1/2 configstrings, which will be visible to everyone if ( g_gametype.integer >= GT_TEAM ) { trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) ); trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) ); } else { if ( level.numConnectedClients == 0 ) { trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) ); trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) ); } else if ( level.numConnectedClients == 1 ) { trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) ); trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) ); } else { trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) ); trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) ); } } // see if it is time to end the level if ( !fromExit ) {//not coming this from the CheckExitRules func CheckExitRules(); } // if we are at the intermission, send the new info to everyone if ( level.intermissiontime != 0 ) { SendScoreboardMessageToAllClients(); } } /* ======================================================================== MAP CHANGING ======================================================================== */ /* ======================== SendScoreboardMessageToAllClients Do this at G_Client_BeginIntermission time and whenever ranks are recalculated due to enters/exits/forced team changes ======================== */ void SendScoreboardMessageToAllClients( void ) { int i; for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[ i ].pers.connected == CON_CONNECTED ) { DeathmatchScoreboardMessage( g_entities + i ); } } } void MoveClientToIntermission( gentity_t *ent ) { entityState_t *es = &ent->s; playerState_t *ps = &ent->client->ps; // take out of follow mode if needed if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { StopFollowing( ent ); } // move to the spot VectorCopy( level.intermission_origin, es->origin ); VectorCopy( level.intermission_origin, ps->origin ); VectorCopy (level.intermission_angle, ps->viewangles); ps->pm_type = PM_INTERMISSION; ps->eFlags ^= EF_TELEPORT_BIT; // clean up powerup info memset( ps->powerups, 0, sizeof(ps->powerups) ); ps->eFlags = 0; es->eFlags = 0; es->eType = ET_GENERAL; es->modelindex = 0; es->loopSound = 0; es->event = 0; ent->r.contents = 0; } void FindIntermissionPoint( void ) { gentity_t *ent, *target; vec3_t dir; // find the intermission spot ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); if ( ent == NULL ) { // the map creator forgot to put in an intermission point... G_Client_SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle ); } else { VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.angles, level.intermission_angle); // if it has a target, look towards it if ( ent->target ) { target = G_PickTarget( ent->target ); if ( target ) { VectorSubtract( target->s.origin, level.intermission_origin, dir ); vectoangles( dir, level.intermission_angle ); } } } } /* ================== ClearFiringFlags ================== */ static void ClearFiringFlags(void) { int i = 0; gentity_t *ent = NULL; for (i=0 ; i< level.maxclients ; i++) { ent = g_entities + i; if (!ent->inuse) continue; // clear the firing flag if (ent->client) { ent->client->ps.eFlags &= ~EF_FIRING; } } } /* ================== G_Client_BeginIntermission ================== */ void G_Client_BeginIntermission( void ) { int i; gentity_t *client; qboolean doingLevelshot; if (level.intermissiontime == -1) doingLevelshot = qtrue; else doingLevelshot = qfalse; if ( level.intermissiontime != 0 && level.intermissiontime != -1 ) { return; // already active } // if in tournament mode, change the wins / losses if ( g_gametype.integer == GT_TOURNAMENT ) { AdjustTournamentScores(); } level.intermissiontime = level.time; FindIntermissionPoint(); // kef -- make sure none of the players are still firing (cuz we don't want weapons fx going off while //they're on the podium) ClearFiringFlags(); // cdr - Want to generate victory pads for all game types - except level shots (gametype 10) UpdateTournamentInfo(); if (!doingLevelshot) SpawnModelsOnVictoryPads(); // move all clients to the intermission point for (i=0 ; i< level.maxclients ; i++) { client = g_entities + i; if (!client->inuse) continue; if (client->health <= 0) { G_Client_Respawn(client); } MoveClientToIntermission( client ); } // send the current scoring to all clients SendScoreboardMessageToAllClients(); } static void G_ClearObjectives( void ) { gentity_t *tent; tent = G_TempEntity( vec3_origin, EV_OBJECTIVE_COMPLETE ); //Be sure to send the event to everyone tent->r.svFlags |= SVF_BROADCAST; tent->s.eventParm = 0;//tells it to clear all } /* ============= ExitLevel When the intermission has been exited, the server is either killed or moved to a new level based on the "nextmap" cvar ============= */ qboolean levelExiting = qfalse; void ExitLevel (void) { int i; levelExiting = qtrue; //bot interbreeding BotInterbreedEndMatch(); G_ClearObjectives(); // if we are running a tournement map, kick the loser to spectator status, // which will automatically grab the next spectator and restart if ( g_gametype.integer == GT_TOURNAMENT ) { if ( !level.restarted ) { RemoveTournamentLoser(); trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" ); level.restarted = qtrue; level.intermissiontime = 0; } return; } trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" ); level.intermissiontime = 0; // we need to do this here before chaning to CON_CONNECTING G_WriteSessionData(); // change all client states to connecting, so the early players into the // next level will know the others aren't done reconnecting for (i=0 ; i< g_maxclients.integer ; i++) { if ( level.clients[i].pers.connected == CON_CONNECTED ) { level.clients[i].pers.connected = CON_CONNECTING; } } } /* ================= CheckExitRules There will be a delay between the time the exit is qualified for and the time everyone is moved to the intermission spot, so you can see the last frag. ================= */ void CheckExitRules( void ) { //RPG-X: RedTechie - No exit in RPG Your TRAPED! MHAHAHA return; } /* ======================================================================== FUNCTIONS CALLED EVERY FRAME ======================================================================== */ /* ============= CheckTournement Once a frame, check for changes in tournement player state ============= */ static void CheckTournement( void ) { if ( level.numPlayingClients == 0 ) { return; } if ( g_gametype.integer == GT_TOURNAMENT ) { if ( level.warmupTime == 0 || level.warmupTime != 0) {//RPG-X: RedTechie - No warmup Fail safe return; } } else if ( g_gametype.integer != GT_SINGLE_PLAYER ) { if ( level.warmupTime == 0) { return; } } } /* ================== CheckVote ================== */ static void CheckVote( void ) { if ( level.voteTime == 0 ) { return; } if ( level.time - level.voteTime >= VOTE_TIME ) { trap_SendServerCommand( -1, "print \"Vote failed.\n\"" ); } else { if ( level.voteYes > level.numVotingClients/2 ) { // execute the command, then remove the vote char message[1024] = ""; trap_SendServerCommand( -1, "print \"Vote passed.\n\"" ); Com_sprintf(message, 1024, "%s\n", level.voteString); trap_SendConsoleCommand( EXEC_APPEND, message ); } else if ( level.voteNo >= level.numVotingClients/2 ) { // same behavior as a timeout trap_SendServerCommand( -1, "print \"Vote failed.\n\"" ); } else { // still waiting for a majority return; } } level.voteTime = 0; trap_SetConfigstring( CS_VOTE_TIME, "" ); } /* ================== CheckCvars ================== */ static void CheckCvars( void ) { static int lastMod = -1; if ( g_password.modificationCount != lastMod ) { lastMod = g_password.modificationCount; if ( g_password.string[0] != 0 && Q_stricmp( g_password.string, "none" ) != 0 ) { trap_Cvar_Set( "g_needpass", "1" ); } else { trap_Cvar_Set( "g_needpass", "0" ); } } } /* ============= G_RunThink Runs thinking code for this frame if necessary ============= */ void G_RunThink (gentity_t *ent) { int thinktime; if(ent == NULL) { return; } thinktime = ent->nextthink; if (thinktime <= 0) { return; } if (thinktime > level.time) { return; } ent->nextthink = 0; if (ent->think == NULL) { G_Error ( "NULL ent->think"); return; } #ifdef G_LUA if(ent->luaThink != NULL && ent->client == NULL) { LuaHook_G_EntityThink(ent->luaThink, ent->s.number); } #endif ent->think (ent); } /* ================ G_RunFrame Advances the non-player objects in the world ================ */ void CheckHealthInfoMessage( void ); void G_RunFrame( int levelTime ) { int i; gentity_t *ent; gclient_t *client; playerState_t *ps; entityState_t *es; // if we are waiting for the level to restart, do nothing if ( level.restarted ) { return; } level.framenum++; level.previousTime = level.time; level.time = levelTime; // get any cvar changes G_UpdateCvars(); // // go through all allocated objects // ent = &g_entities[0]; for (i=0 ; iinuse ) { continue; } es = &ent->s; ps = &ent->client->ps; // clear events that are too old if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) { if ( es->event != 0 ) { es->event = 0; if ( ent->client ) { ps->externalEvent = 0; ps->events[0] = 0; ps->events[1] = 0; ps->events[2] = 0; ps->events[3] = 0; } } if ( ent->freeAfterEvent ) { // tempEntities or dropped items completely go away after their event G_FreeEntity( ent ); continue; } else if ( ent->unlinkAfterEvent ) { // items that will respawn will hide themselves after their pickup event ent->unlinkAfterEvent = qfalse; trap_UnlinkEntity( ent ); } } // temporary entities don't think if ( ent->freeAfterEvent ) { continue; } if ( !ent->r.linked && ent->neverFree ) { continue; } if ( !ent->client ) { if ( (es->eFlags & EF_ANIM_ONCE) == EF_ANIM_ONCE ) {//this must be capped render-side es->frame++; } } if ( (es->eType == ET_MISSILE) || (es->eType == ET_ALT_MISSILE) ) { G_Missile_Run( ent ); continue; } if ( es->eType == ET_ITEM || ent->physicsObject ) { G_RunItem( ent ); continue; } if ( es->eType == ET_MOVER || es->eType == ET_MOVER_STR ) { //RPG-X | GSIO01 | 13/05/2009 G_Mover_Run( ent ); continue; } if ( i < MAX_CLIENTS ) { G_RunClient( ent ); continue; } G_RunThink( ent ); } // perform final fixups on the players ent = &g_entities[0]; for (i=0 ; i < level.maxclients ; i++, ent++ ) { if ( ent->inuse ) { ClientEndFrame( ent ); } } // see if it is time to do a tournement restart CheckTournement(); // see if it is time to end the level CheckExitRules(); // update to client status? G_Client_CheckClientStatus(); // cancel vote if timed out CheckVote(); // for tracking changes CheckCvars(); //RPG-X: J2J - This will check for drag movements that need to be calculated. DragCheck(); for ( i = 0; i < MAX_CLIENTS; i++ ) { ent = &g_entities[i]; if(!ent || !ent->client) continue; client = ent->client; if ((client->pers.cmd.buttons & BUTTON_USE) == 0) { client->pressedUse = qfalse; } if (g_classData[client->sess.sessionClass].isn00b != 0) { if ((client->n00bTime != -1) && (client->n00bTime <= level.time) && client->origClass[0] != 0) { if(SetClass( ent, client->origClass, NULL, qtrue ) == qfalse) { DEVELOPER(G_Printf(S_COLOR_YELLOW "G_RunFrame - Warning: SetClass failed!\n");); } } } } //RPG-X: Marcin: To clear pressedUse. - 30/12/2008 #ifdef G_LUA LuaHook_G_RunFrame(levelTime); #endif }