g_main.c

Go to the documentation of this file.
00001 
00006 /*
00007 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 Original file from Quake 2 v3.21: quake2-2.31/game/g_main.c
00010 Copyright (C) 1997-2001 Id Software, Inc.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00026 
00027 */
00028 
00029 #include "g_local.h"
00030 #include "g_ai.h"
00031 
00032 game_locals_t game;
00033 level_locals_t level;
00034 game_import_t gi;
00035 game_export_t globals;
00036 
00037 cvar_t *password;
00038 
00039 cvar_t *sv_needpass;
00040 cvar_t *sv_maxplayersperteam;
00041 cvar_t *sv_maxsoldiersperteam;
00042 cvar_t *sv_maxsoldiersperplayer;
00043 cvar_t *sv_enablemorale;
00044 cvar_t *sv_roundtimelimit;
00045 cvar_t *sv_maxentities;
00046 cvar_t *sv_dedicated;
00047 cvar_t *developer;
00048 
00049 cvar_t *logstats;
00050 FILE *logstatsfile;
00051 
00052 cvar_t *sv_filterban;
00053 
00054 static cvar_t *sv_cheats;
00055 
00056 cvar_t *sv_maxteams;
00057 
00058 cvar_t *sv_ai;
00059 cvar_t *sv_teamplay;
00060 cvar_t *sv_maxclients;
00061 cvar_t *sv_hurtaliens;
00062 cvar_t *sv_shot_origin;
00063 static cvar_t *sv_send_edicts;
00064 
00065 cvar_t *ai_alien;
00066 cvar_t *ai_civilian;
00067 cvar_t *ai_equipment;
00068 cvar_t *ai_numaliens;
00069 cvar_t *ai_numcivilians;
00070 cvar_t *ai_numactors;
00071 
00072 /* morale cvars */
00073 cvar_t *mob_death;
00074 cvar_t *mob_wound;
00075 cvar_t *mof_watching;
00076 cvar_t *mof_teamkill;
00077 cvar_t *mof_civilian;
00078 cvar_t *mof_enemy;
00079 cvar_t *mor_pain;
00080 
00081 /*everyone gets this times morale damage */
00082 cvar_t *mor_default;
00083 
00084 /*at this distance the following two get halfed (exponential scale) */
00085 cvar_t *mor_distance;
00086 
00087 /*at this distance the following two get halfed (exponential scale) */
00088 cvar_t *mor_victim;
00089 
00090 /*at this distance the following two get halfed (exponential scale) */
00091 cvar_t *mor_attacker;
00092 
00093 /* how much the morale depends on the size of the damaged team */
00094 cvar_t *mon_teamfactor;
00095 
00096 cvar_t *mor_regeneration;
00097 cvar_t *mor_shaken;
00098 cvar_t *mor_panic;
00099 cvar_t *mor_brave;
00100 
00101 cvar_t *m_sanity;
00102 cvar_t *m_rage;
00103 cvar_t *m_rage_stop;
00104 cvar_t *m_panic_stop;
00105 
00106 cvar_t *g_reaction_fair;
00107 cvar_t *g_ailua;
00108 cvar_t *g_aidebug;
00109 cvar_t *g_drawtraces;
00110 cvar_t *g_nodamage;
00111 cvar_t *g_notu;
00112 cvar_t *g_nospawn;
00113 cvar_t *g_actorspeed;
00114 cvar_t *flood_msgs;
00115 cvar_t *flood_persecond;
00116 cvar_t *flood_waitdelay;
00117 
00118 cvar_t *difficulty;
00119 
00120 static const int TAG_INVENTORY = 2389;
00121 
00122 static void G_FreeInventory (void *data)
00123 {
00124     G_MemFree(data);
00125 }
00126 
00127 static void *G_AllocInventoryMemory (size_t size)
00128 {
00129     return G_TagMalloc(size, TAG_INVENTORY);
00130 }
00131 
00132 static void G_FreeAllInventory (void)
00133 {
00134     G_FreeTags(TAG_INVENTORY);
00135 }
00136 
00137 static const inventoryImport_t inventoryImport = { G_FreeInventory, G_FreeAllInventory, G_AllocInventoryMemory };
00138 
00139 
00144 static void G_Init (void)
00145 {
00146     gi.DPrintf("==== InitGame ====\n");
00147 
00148     /* noset vars */
00149     sv_dedicated = gi.Cvar_Get("sv_dedicated", "0", CVAR_SERVERINFO | CVAR_NOSET, "Is this a dedicated server?");
00150 
00151     /* latched vars */
00152     sv_cheats = gi.Cvar_Get("sv_cheats", "0", CVAR_SERVERINFO | CVAR_LATCH, "Activate cheats");
00153     gi.Cvar_Get("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH, NULL);
00154     gi.Cvar_Get("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH, NULL);
00155     developer = gi.Cvar_Get("developer", "0", 0, "Print out a lot of developer debug messages - useful to track down bugs");
00156     logstats = gi.Cvar_Get("logstats", "1", CVAR_ARCHIVE, "Server logfile output for kills");
00157 
00158     /* max. players per team (original quake) */
00159     sv_maxplayersperteam = gi.Cvar_Get("sv_maxplayersperteam", "8", CVAR_SERVERINFO | CVAR_LATCH, "How many players (humans) may a team have");
00160     /* max. soldiers per team */
00161     sv_maxsoldiersperteam = gi.Cvar_Get("sv_maxsoldiersperteam", "4", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, "How many soldiers may one team have");
00162     /* max soldiers per player */
00163     sv_maxsoldiersperplayer = gi.Cvar_Get("sv_maxsoldiersperplayer", "8", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, "How many soldiers one player is able to control in a given team");
00164     /* enable moralestates in multiplayer */
00165     sv_enablemorale = gi.Cvar_Get("sv_enablemorale", "1", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, "Enable morale behaviour for actors");
00166     sv_roundtimelimit = gi.Cvar_Get("sv_roundtimelimit", "0", CVAR_SERVERINFO, "Timelimit in seconds for multiplayer rounds");
00167     sv_roundtimelimit->modified = qfalse;
00168     sv_maxentities = gi.Cvar_Get("sv_maxentities", "1024", CVAR_LATCH, NULL);
00169 
00170     sv_maxteams = gi.Cvar_Get("sv_maxteams", "2", CVAR_SERVERINFO, "How many teams for current running map");
00171     sv_maxteams->modified = qfalse;
00172 
00173     /* change anytime vars */
00174     password = gi.Cvar_Get("password", "", CVAR_USERINFO, NULL);
00175     sv_needpass = gi.Cvar_Get("sv_needpass", "0", CVAR_SERVERINFO, NULL);
00176     sv_filterban = gi.Cvar_Get("sv_filterban", "1", 0, NULL);
00177     sv_ai = gi.Cvar_Get("sv_ai", "1", 0, "Activate or deativate the ai");
00178     sv_teamplay = gi.Cvar_Get("sv_teamplay", "0", CVAR_ARCHIVE | CVAR_LATCH | CVAR_SERVERINFO, "Is teamplay activated? see sv_maxclients, sv_maxplayersperteam, sv_maxsoldiersperteam and sv_maxsoldiersperplayer");
00179     /* how many connected clients */
00180     sv_maxclients = gi.Cvar_Get("sv_maxclients", "1", CVAR_SERVERINFO, "If sv_maxclients is 1 we are in singleplayer - otherwise we are mutliplayer mode (see sv_teamplay)");
00181     sv_shot_origin = gi.Cvar_Get("sv_shot_origin", "8", 0, "Assumed distance of muzzle from model");
00182     sv_send_edicts = gi.Cvar_Get("sv_send_edicts", "0", CVAR_ARCHIVE | CVAR_CHEAT, "Send server side edicts for client display like triggers");
00183     sv_hurtaliens = gi.Cvar_Get("sv_hurtaliens", "0", CVAR_SERVERINFO, "Spawn hurt aliens");
00184 
00185     ai_alien = gi.Cvar_Get("ai_alien", "ortnok", 0, "Alien team");
00186     ai_civilian = gi.Cvar_Get("ai_civilian", "europe", 0, "Civilian team");
00187     /* this cvar is set in singleplayer via campaign definition */
00188     ai_equipment = gi.Cvar_Get("ai_equipment", "multiplayer_alien", 0, "Initial equipment definition for aliens");
00189     /* aliens in singleplayer (can differ each mission) */
00190     ai_numaliens = gi.Cvar_Get("ai_numaliens", "30", 0, "How many aliens in this battle (singleplayer)");
00191     /* civilians for singleplayer */
00192     ai_numcivilians = gi.Cvar_Get("ai_numcivilians", "10", 0, "How many civilians in this battle");
00193     /* aliens in multiplayer */
00194     ai_numactors = gi.Cvar_Get("ai_numactors", "8", CVAR_ARCHIVE, "How many (ai controlled) actors in this battle (multiplayer)");
00195 
00196     mob_death = gi.Cvar_Get("mob_death", "10", CVAR_LATCH|CVAR_NOSET, NULL);
00197     mob_wound = gi.Cvar_Get("mob_wound", "0.1", CVAR_LATCH|CVAR_NOSET, NULL);
00198     mof_watching = gi.Cvar_Get("mof_watching", "1.7", CVAR_LATCH|CVAR_NOSET, NULL);
00199     mof_teamkill = gi.Cvar_Get("mof_teamkill", "2.0", CVAR_LATCH|CVAR_NOSET, NULL);
00200     mof_civilian = gi.Cvar_Get("mof_civilian", "0.3", CVAR_LATCH|CVAR_NOSET, NULL);
00201     mof_enemy = gi.Cvar_Get("mof_ememy", "0.5", CVAR_LATCH|CVAR_NOSET, NULL);
00202     mor_pain = gi.Cvar_Get("mof_pain", "3.6", CVAR_LATCH|CVAR_NOSET, NULL);
00203     /* everyone gets this times morale damage */
00204     mor_default = gi.Cvar_Get("mor_default", "0.3", CVAR_LATCH|CVAR_NOSET, "Everyone gets this times morale damage");
00205     /* at this distance the following two get halved (exponential scale) */
00206     mor_distance = gi.Cvar_Get("mor_distance", "120", CVAR_LATCH|CVAR_NOSET, "At this distance the following two get halved (exponential scale)");
00207     /* at this distance the following two get halved (exponential scale) */
00208     mor_victim = gi.Cvar_Get("mor_victim", "0.7", CVAR_LATCH|CVAR_NOSET, "At this distance the following two get halved (exponential scale)");
00209     /* at this distance the following two get halved (exponential scale) */
00210     mor_attacker = gi.Cvar_Get("mor_attacker", "0.3", CVAR_LATCH|CVAR_NOSET, "At this distance the following two get halved (exponential scale)");
00211     /* how much the morale depends on the size of the damaged team */
00212     mon_teamfactor = gi.Cvar_Get("mon_teamfactor", "0.6", CVAR_LATCH|CVAR_NOSET, "How much the morale depends on the size of the damaged team");
00213 
00214     mor_regeneration = gi.Cvar_Get("mor_regeneration", "15", CVAR_LATCH|CVAR_NOSET, NULL);
00215     mor_shaken = gi.Cvar_Get("mor_shaken", "50", CVAR_LATCH|CVAR_NOSET, NULL);
00216     mor_panic = gi.Cvar_Get("mor_panic", "30", CVAR_LATCH|CVAR_NOSET, NULL);
00217     mor_brave = gi.Cvar_Get("mor_panic", "85", CVAR_LATCH|CVAR_NOSET, NULL);
00218 
00219     m_sanity = gi.Cvar_Get("m_sanity", "1.0", CVAR_LATCH|CVAR_NOSET, NULL);
00220     m_rage = gi.Cvar_Get("m_rage", "0.6", CVAR_LATCH|CVAR_NOSET, NULL);
00221     m_rage_stop = gi.Cvar_Get("m_rage_stop", "2.0", CVAR_LATCH|CVAR_NOSET, NULL);
00222     m_panic_stop = gi.Cvar_Get("m_panic_stop", "1.0", CVAR_LATCH|CVAR_NOSET, NULL);
00223 
00224     g_reaction_fair = gi.Cvar_Get("g_reaction_fair", "1", CVAR_LATCH | CVAR_SERVERINFO, "Enable or disable fair reaction fire mode");
00225     g_ailua = gi.Cvar_Get("g_ailua", "0", 0, "Activate or deactivate the LUA AI");
00226     g_aidebug = gi.Cvar_Get("g_aidebug", "0", CVAR_DEVELOPER, "All AI actors are visible");
00227     g_drawtraces = gi.Cvar_Get("g_drawtraces", "0", CVAR_DEVELOPER, "All traces will be rendered");
00228     g_nodamage = gi.Cvar_Get("g_nodamage", "0", CVAR_DEVELOPER|CVAR_CHEAT, "No damage in developer mode");
00229     g_notu = gi.Cvar_Get("g_notu", "0", CVAR_DEVELOPER|CVAR_CHEAT, "No TU costs while moving around (e.g. for map testing)");
00230     g_actorspeed = gi.Cvar_Get("g_actorspeed", "1.0", CVAR_ARCHIVE|CVAR_SERVERINFO, "Moving speed of the actor");
00231     g_nospawn = gi.Cvar_Get("g_nospawn", "0", CVAR_DEVELOPER|CVAR_CHEAT, "Do not spawn a soldier");
00232 
00233     /* flood control */
00234     flood_msgs = gi.Cvar_Get("flood_msgs", "4", 0, NULL);
00235     flood_persecond = gi.Cvar_Get("flood_persecond", "4", 0, NULL);
00236     flood_waitdelay = gi.Cvar_Get("flood_waitdelay", "10", 0, "Delay until someone is unlocked from talking again");
00237 
00238     difficulty = gi.Cvar_Get("difficulty", "0", CVAR_NOSET, "Difficulty level");
00239 
00240     game.sv_maxentities = sv_maxentities->integer;
00241     game.sv_maxplayersperteam = sv_maxplayersperteam->integer;
00242 
00243     /* initialize the entity storage */
00244     globals.edicts = G_EdictsInit();
00245     globals.max_edicts = game.sv_maxentities;
00246     globals.num_edicts = game.sv_maxplayersperteam;
00247 
00248     /* initialize all players for this game */
00249     /* game.sv_maxplayersperteam for human controlled players
00250      * + game.sv_maxplayer for ai */
00251     game.players = (player_t *)G_TagMalloc(game.sv_maxplayersperteam * 2 * sizeof(game.players[0]), TAG_GAME);
00252     globals.players = game.players;
00253     globals.maxplayersperteam = game.sv_maxplayersperteam;
00254 
00255     /* init csi and inventory */
00256     INVSH_InitCSI(gi.csi);
00257     INV_InitInventory("game", &game.i, gi.csi, &inventoryImport);
00258 
00259     if (logstats->integer)
00260         logstatsfile = fopen(va("%s/stats.log", gi.FS_Gamedir()), "a");
00261     else
00262         logstatsfile = NULL;
00263 
00264     AIL_Init();
00265 }
00266 
00271 static void G_Shutdown (void)
00272 {
00273     gi.DPrintf("==== ShutdownGame ====\n");
00274 
00275     AIL_Shutdown();
00276 
00277     if (logstatsfile)
00278         fclose(logstatsfile);
00279     logstatsfile = NULL;
00280 
00281     G_FreeTags(TAG_LEVEL);
00282     G_FreeTags(TAG_GAME);
00283     G_FreeAllInventory();
00284 
00285     Com_Printf("Free inventory slots in game on shutdown: %i\n", game.i.GetUsedSlots(&game.i));
00286 }
00287 
00288 
00292 game_export_t *GetGameAPI (game_import_t * import)
00293 {
00294     gi = *import;
00295     srand(gi.seed);
00296 
00297     globals.apiversion = GAME_API_VERSION;
00298     globals.Init = G_Init;
00299     globals.Shutdown = G_Shutdown;
00300     globals.SpawnEntities = G_SpawnEntities;
00301 
00302     globals.ClientConnect = G_ClientConnect;
00303     globals.ClientUserinfoChanged = G_ClientUserinfoChanged;
00304     globals.ClientDisconnect = G_ClientDisconnect;
00305     globals.ClientBegin = G_ClientBegin;
00306     globals.ClientSpawn = G_ClientSpawn;
00307     globals.ClientCommand = G_ClientCommand;
00308     globals.ClientAction = G_ClientAction;
00309     globals.ClientEndRound = G_ClientEndRound;
00310     globals.ClientTeamInfo = G_ClientTeamInfo;
00311     globals.ClientInitActorStates = G_ClientInitActorStates;
00312     globals.ClientGetTeamNum = G_ClientGetTeamNum;
00313     globals.ClientGetTeamNumPref = G_ClientGetTeamNumPref;
00314     globals.ClientIsReady = G_ClientIsReady;
00315     globals.ClientGetName = G_GetPlayerName;
00316     globals.ClientGetActiveTeam = G_GetActiveTeam;
00317 
00318     globals.RunFrame = G_RunFrame;
00319 
00320     globals.ServerCommand = G_ServerCommand;
00321 
00322     globals.edict_size = sizeof(edict_t);
00323     globals.player_size = sizeof(player_t);
00324 
00325     return &globals;
00326 }
00327 
00328 #ifndef HARD_LINKED_GAME
00329 /* this is only here so the functions in the shared code can link */
00330 void Sys_Error (const char *error, ...)
00331 {
00332     va_list argptr;
00333     char text[1024];
00334 
00335     va_start(argptr, error);
00336     Q_vsnprintf(text, sizeof(text), error, argptr);
00337     va_end(argptr);
00338 
00339     gi.Error("%s", text);
00340 }
00341 
00342 void Com_Printf (const char *msg, ...)
00343 {
00344     va_list argptr;
00345     char text[1024];
00346 
00347     va_start(argptr, msg);
00348     Q_vsnprintf(text, sizeof(text), msg, argptr);
00349     va_end(argptr);
00350 
00351     gi.DPrintf("%s", text);
00352 }
00353 
00354 void Com_DPrintf (int level, const char *msg, ...)
00355 {
00356     va_list argptr;
00357     char text[1024];
00358 
00359     /* don't confuse non-developers with techie stuff... */
00360     if (!developer || developer->integer == 0)
00361         return;
00362 
00363     if (!(developer->integer & level))
00364         return;
00365 
00366     va_start(argptr, msg);
00367     Q_vsnprintf(text, sizeof(text), msg, argptr);
00368     va_end(argptr);
00369 
00370     gi.DPrintf("%s", text);
00371 }
00372 #endif
00373 
00377 static void CheckNeedPass (void)
00378 {
00379     if (password->modified) {
00380         const char *need = "0";
00381         password->modified = qfalse;
00382 
00383         if (password->string[0] != '\0' && Q_strcasecmp(password->string, "none"))
00384             need = "1";
00385 
00386         gi.Cvar_Set("sv_needpass", need);
00387     }
00388 }
00389 
00390 static void G_SendBoundingBoxes (void)
00391 {
00392     if (sv_send_edicts->integer) {
00393         edict_t *ent = G_EdictsGetFirst();  /* skip the world */
00394         while ((ent = G_EdictsGetNextInUse(ent)))
00395             G_EventSendEdict(ent);
00396     }
00397 }
00398 
00405 qboolean G_RunFrame (void)
00406 {
00407     level.framenum++;
00408     /* server is running at 10 fps */
00409     level.time = level.framenum * SERVER_FRAME_SECONDS;
00410 
00411     /* this doesn't belong here, but it works */
00412     if (!level.routed) {
00413         level.routed = qtrue;
00414         G_CompleteRecalcRouting();
00415     }
00416 
00417     /* still waiting for other players */
00418     if (!G_MatchIsRunning()) {
00419         if (sv_maxteams->modified) {
00420             /* inform the client */
00421             gi.ConfigString(CS_MAXTEAMS, "%i", sv_maxteams->integer);
00422             sv_maxteams->modified = qfalse;
00423         }
00424     }
00425 
00426     if (sv_maxclients->integer > 1) {
00427         if (sv_roundtimelimit->modified) {
00428             /* some played around here - restart the count down */
00429             level.roundstartTime = level.time;
00430             /* don't allow smaller values here */
00431             if (sv_roundtimelimit->integer < 30 && sv_roundtimelimit->integer > 0) {
00432                 gi.DPrintf("The minimum value for sv_roundtimelimit is 30\n");
00433                 gi.Cvar_Set("sv_roundtimelimit", "30");
00434             }
00435             sv_roundtimelimit->modified = qfalse;
00436         }
00437         G_CheckForceEndRound();
00438     }
00439 
00440     /* end this game? */
00441     if (G_MatchDoEnd())
00442         return qtrue;
00443 
00444     CheckNeedPass();
00445 
00446     /* run ai */
00447     AI_Run();
00448     G_PhysicsRun();
00449 
00450     G_SendBoundingBoxes();
00451 
00452     return qfalse;
00453 }

Generated by  doxygen 1.6.2