/* * @brief Shuts down the game module. This is called when the game is unloaded * (complements G_Init). */ void G_Shutdown(void) { gi.Print(" Game shutdown...\n"); #ifdef HAVE_MYSQL if(mysql != NULL) mysql_close(mysql); // and db #endif gi.FreeTag(MEM_TAG_GAME_LEVEL); gi.FreeTag(MEM_TAG_GAME); }
/* * G_ResetTeams */ void G_ResetTeams(void) { memset(&g_team_good, 0, sizeof(g_team_good)); memset(&g_team_evil, 0, sizeof(g_team_evil)); strcpy(g_team_good.name, "Good"); gi.ConfigString(CS_TEAM_GOOD, g_team_good.name); strcpy(g_team_evil.name, "Evil"); gi.ConfigString(CS_TEAM_EVIL, g_team_evil.name); strcpy(g_team_good.skin, "qforcer/blue"); strcpy(g_team_evil.skin, "qforcer/red"); }
/* * G_BeginIntermission */ static void G_BeginIntermission(const char *map) { int i; g_edict_t *ent, *client; if (g_level.intermission_time) return; // already activated g_level.intermission_time = g_level.time; // respawn any dead clients for (i = 0; i < sv_max_clients->integer; i++) { client = g_game.edicts + 1 + i; if (!client->in_use) continue; if (client->health <= 0) G_ClientRespawn(client, false); } // find an intermission spot ent = G_Find(NULL, FOFS(class_name), "info_player_intermission"); if (!ent) { // map does not have an intermission point ent = G_Find(NULL, FOFS(class_name), "info_player_start"); if (!ent) ent = G_Find(NULL, FOFS(class_name), "info_player_deathmatch"); } VectorCopy(ent->s.origin, g_level.intermission_origin); VectorCopy(ent->s.angles, g_level.intermission_angle); // move all clients to the intermission point for (i = 0; i < sv_max_clients->integer; i++) { client = g_game.edicts + 1 + i; if (!client->in_use) continue; G_ClientToIntermission(client); } // play a dramatic sound effect gi.PositionedSound(g_level.intermission_origin, g_game.edicts, gi.SoundIndex("weapons/bfg/hit"), ATTN_NORM); // stay on same level if not provided g_level.changemap = map && *map ? map : g_level.name; }
/* * G_CheckRoundLimit */ static void G_CheckRoundLimit() { int i; g_edict_t *ent; g_client_t *cl; if (g_level.round_num >= (unsigned int) g_level.round_limit) { // enforce round_limit gi.BroadcastPrint(PRINT_HIGH, "Roundlimit hit\n"); G_EndLevel(); return; } // or attempt to re-join previously active players for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; ent = &g_game.edicts[i + 1]; cl = ent->client; if (cl->persistent.round_num != g_level.round_num) continue; // they were intentionally spectating, skip them if (g_level.teams || g_level.ctf) { // rejoin a team if (cl->persistent.team) G_AddClientToTeam(ent, cl->persistent.team->name); else G_AddClientToTeam(ent, G_SmallestTeam()->name); } else // just rejoin the game cl->persistent.spectator = false; G_ClientRespawn(ent, false); } }
/* * G_CheckRoundStart */ static void G_CheckRoundStart(void) { int i, g, e, clients; g_client_t *cl; if (!g_level.rounds) return; if (g_level.round_time) return; clients = g = e = 0; for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; cl = g_game.edicts[i + 1].client; if (cl->persistent.spectator) continue; clients++; if (g_level.teams) cl->persistent.team == &g_team_good ? g++ : e++; } if (clients < 2) // need at least 2 clients to trigger countdown return; if (g_level.teams && (!g || !e)) // need at least 1 player per team return; if ((int) g_level.teams == 2 && (g != e)) { // balanced teams required if (g_level.frame_num % 100 == 0) gi.BroadcastPrint(PRINT_HIGH, "Teams must be balanced for round to start\n"); return; } gi.BroadcastPrint(PRINT_HIGH, "Round starting in 10 seconds...\n"); g_level.round_time = g_level.time + 10.0; g_level.start_round = true; }
/* * G_ExitLevel */ static void G_ExitLevel(void) { gi.AddCommandString(va("map %s\n", g_level.changemap)); g_level.changemap = NULL; g_level.intermission_time = 0; G_EndClientFrames(); }
/* * Frees tags and closes frag_log. This is called when the game is unloaded * (complements G_Init). */ void G_Shutdown(void) { gi.Print(" Game shutdown...\n"); if (frag_log != NULL) gi.CloseFile(frag_log); // close frag_log if (chat_log != NULL) gi.CloseFile(chat_log); // and chat_log #ifdef HAVE_MYSQL if(mysql != NULL) mysql_close(mysql); // and db #endif gi.FreeTags(TAG_LEVEL); gi.FreeTags(TAG_GAME); }
/* * G_CheckVote */ static void G_CheckVote(void) { int i, count = 0; if (!g_voting->value) return; if (g_level.vote_time == 0) return; if (g_level.time - g_level.vote_time > MAX_VOTE_TIME) { gi.BroadcastPrint(PRINT_HIGH, "Vote \"%s\" expired\n", g_level.vote_cmd); G_ResetVote(); return; } for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; count++; } if (g_level.votes[VOTE_YES] >= count * VOTE_MAJORITY) { // vote passed gi.BroadcastPrint(PRINT_HIGH, "Vote \"%s\" passed\n", g_level.vote_cmd); if (!strncmp(g_level.vote_cmd, "map ", 4)) { // special case for map G_BeginIntermission(g_level.vote_cmd + 4); } else if (!strcmp(g_level.vote_cmd, "restart")) { // and restart G_RestartGame(false); } else if (!strncmp(g_level.vote_cmd, "mute ", 5)) { // and mute G_MuteClient(g_level.vote_cmd + 5, true); } else if (!strncmp(g_level.vote_cmd, "unmute ", 7)) { G_MuteClient(g_level.vote_cmd + 7, false); } else { // general case, just execute the command gi.AddCommandString(g_level.vote_cmd); } G_ResetVote(); } else if (g_level.votes[VOTE_NO] >= count * VOTE_MAJORITY) { // vote failed gi.BroadcastPrint(PRINT_HIGH, "Vote \"%s\" failed\n", g_level.vote_cmd); G_ResetVote(); } }
/* * G_CheckMatchEnd */ static void G_CheckMatchEnd(void) { int i, g, e, clients; g_client_t *cl; if (!g_level.match) return; if (!g_level.match_time || g_level.match_time > g_level.time) return; // no match currently running g = e = clients = 0; for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; cl = g_game.edicts[i + 1].client; if (cl->persistent.spectator) continue; if (g_level.teams || g_level.ctf) cl->persistent.team == &g_team_good ? g++ : e++; clients++; } if (clients == 0) { // everyone left gi.BroadcastPrint(PRINT_HIGH, "No players left\n"); g_level.match_time = 0; return; } if ((g_level.teams || g_level.ctf) && (!g || !e)) { gi.BroadcastPrint(PRINT_HIGH, "Not enough players left\n"); g_level.match_time = 0; return; } }
/* * G_ResetVote */ void G_ResetVote(void) { int i; for (i = 0; i < sv_max_clients->integer; i++) { //reset vote flags if (!g_game.edicts[i + 1].in_use) continue; g_game.edicts[i + 1].client->persistent.vote = VOTE_NO_OP; } gi.ConfigString(CS_VOTE, NULL); g_level.votes[0] = g_level.votes[1] = g_level.votes[2] = 0; g_level.vote_cmd[0] = 0; g_level.vote_time = 0; }
/* * G_ParseMapList * * Populates a g_map_list_t from a text file. See default/maps.lst */ static void G_ParseMapList(const char *file_name) { void *buf; const char *buffer; unsigned int i, j, k, l; const char *c; boolean_t map; g_map_list_elt_t *elt; G_InitMapList(); if (gi.LoadFile(file_name, &buf) == -1) { gi.Print("Couldn't open %s\n", file_name); return; } buffer = (char *) buf; i = 0; map = false; while (true) { c = ParseToken(&buffer); if (*c == '\0') break; if (*c == '{') map = true; if (!map) // skip any whitespace between maps continue; elt = &g_map_list.maps[i]; if (!strcmp(c, "name")) { strncpy(elt->name, ParseToken(&buffer), sizeof(elt->name) - 1); continue; } if (!strcmp(c, "title")) { strncpy(elt->title, ParseToken(&buffer), sizeof(elt->title) - 1); continue; } if (!strcmp(c, "sky")) { strncpy(elt->sky, ParseToken(&buffer), sizeof(elt->sky) - 1); continue; } if (!strcmp(c, "weather")) { strncpy(elt->weather, ParseToken(&buffer), sizeof(elt->weather) - 1); continue; } if (!strcmp(c, "gravity")) { elt->gravity = atoi(ParseToken(&buffer)); continue; } if (!strcmp(c, "gameplay")) { elt->gameplay = G_GameplayByName(ParseToken(&buffer)); continue; } if (!strcmp(c, "teams")) { elt->teams = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "ctf")) { elt->ctf = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "match")) { elt->match = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "rounds")) { elt->rounds = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "frag_limit")) { elt->frag_limit = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "round_limit")) { elt->round_limit = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "capture_limit")) { elt->capture_limit = strtoul(ParseToken(&buffer), NULL, 0); continue; } if (!strcmp(c, "time_limit")) { elt->time_limit = atof(ParseToken(&buffer)); continue; } if (!strcmp(c, "give")) { strncpy(elt->give, ParseToken(&buffer), sizeof(elt->give) - 1); continue; } if (!strcmp(c, "music")) { strncpy(elt->music, ParseToken(&buffer), sizeof(elt->music) - 1); continue; } if (!strcmp(c, "weight")) { elt->weight = atof(ParseToken(&buffer)); continue; } if (*c == '}') { // close it out map = false; /*printf("Loaded map %s:\n" "title: %s\n" "sky: %s\n" "weather: %s\n" "gravity: %d\n" "gameplay: %ud\n" "teams: %ud\n" "ctf: %ud\n" "match: %ud\n" "rounds: %ud\n" "frag_limit: %ud\n" "round_limit: %ud\n" "capture_limit: %ud\n" "time_limit: %f\n" "give: %s\n" "music: %s\n" "weight: %f\n", map->name, map->title, map->sky, map->weather, map->gravity, map->gameplay, map->teams, map->ctf, map->match, map->rounds, map->frag_limit, map->round_limit, map->capture_limit, map->time_limit, map->give, map->music, map->weight);*/ // accumulate total weight g_map_list.total_weight += elt->weight; if (++i == MAX_MAP_LIST_ELTS) break; } } g_map_list.count = i; g_map_list.index = 0; gi.TagFree(buf); // thou shalt not divide by zero if (!g_map_list.total_weight) g_map_list.total_weight = 1.0; // compute the weighted index list for (i = 0, l = 0; i < g_map_list.count; i++) { elt = &g_map_list.maps[i]; k = (elt->weight / g_map_list.total_weight) * MAP_LIST_WEIGHT; for (j = 0; j < k; j++) g_map_list.weighted_index[l++] = i; } }
/* * G_CheckRules */ static void G_CheckRules(void) { int i, seconds; g_client_t *cl; if (g_level.intermission_time) return; // match mode, no match, or countdown underway g_level.warmup = g_level.match && (!g_level.match_time || g_level.match_time > g_level.time); // arena mode, no round, or countdown underway g_level.warmup |= g_level.rounds && (!g_level.round_time || g_level.round_time > g_level.time); if (g_level.start_match && g_level.time >= g_level.match_time) { // players have readied, begin match g_level.start_match = false; g_level.warmup = false; for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; G_ClientRespawn(&g_game.edicts[i + 1], false); } gi.Sound(&g_game.edicts[0], gi.SoundIndex("world/teleport"), ATTN_NONE); gi.BroadcastPrint(PRINT_HIGH, "Match has started\n"); } if (g_level.start_round && g_level.time >= g_level.round_time) { // pre-game expired, begin round g_level.start_round = false; g_level.warmup = false; for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; G_ClientRespawn(&g_game.edicts[i + 1], false); } gi.Sound(&g_game.edicts[0], gi.SoundIndex("world/teleport"), ATTN_NONE); gi.BroadcastPrint(PRINT_HIGH, "Round has started\n"); } seconds = g_level.time; if (g_level.rounds) { if (g_level.round_time > g_level.time) // round about to start, show pre-game countdown seconds = g_level.round_time - g_level.time; else if (g_level.round_time) seconds = g_level.time - g_level.round_time; // round started, count up else seconds = -1; } else if (g_level.match) { if (g_level.match_time > g_level.time) // match about to start, show pre-game countdown seconds = g_level.match_time - g_level.time; else if (g_level.match_time) { if (g_level.time_limit) // count down to time_limit seconds = g_level.match_time + g_level.time_limit * 60 - g_level.time; else seconds = g_level.time - g_level.match_time; // count up } else seconds = -1; } if (g_level.time_limit) { // check time_limit float t = g_level.time; if (g_level.match) // for matches t = g_level.time - g_level.match_time; else if (g_level.rounds) // and for rounds t = g_level.time - g_level.round_time; if (t >= g_level.time_limit * 60) { gi.BroadcastPrint(PRINT_HIGH, "Timelimit hit\n"); G_EndLevel(); return; } seconds = g_level.time_limit * 60 - t; // count down } if (g_level.frame_num % gi.frame_rate == 0) // send time updates once per second gi.ConfigString(CS_TIME, (g_level.warmup ? "Warmup" : G_FormatTime(seconds))); if (!g_level.ctf && g_level.frag_limit) { // check frag_limit if (g_level.teams) { // check team scores if (g_team_good.score >= g_level.frag_limit || g_team_evil.score >= g_level.frag_limit) { gi.BroadcastPrint(PRINT_HIGH, "Fraglimit hit\n"); G_EndLevel(); return; } } else { // or individual scores for (i = 0; i < sv_max_clients->integer; i++) { cl = g_game.clients + i; if (!g_game.edicts[i + 1].in_use) continue; if (cl->persistent.score >= g_level.frag_limit) { gi.BroadcastPrint(PRINT_HIGH, "Fraglimit hit\n"); G_EndLevel(); return; } } } } if (g_level.ctf && g_level.capture_limit) { // check capture limit if (g_team_good.captures >= g_level.capture_limit || g_team_evil.captures >= g_level.capture_limit) { gi.BroadcastPrint(PRINT_HIGH, "Capturelimit hit\n"); G_EndLevel(); return; } } if (g_gameplay->modified) { // change gameplay, fix items, respawn clients g_gameplay->modified = false; g_level.gameplay = G_GameplayByName(g_gameplay->string); gi.ConfigString(CS_GAMEPLAY, va("%d", g_level.gameplay)); G_RestartGame(false); // reset all clients gi.BroadcastPrint(PRINT_HIGH, "Gameplay has changed to %s\n", G_GameplayName(g_level.gameplay)); } if (g_gravity->modified) { // send gravity config string g_gravity->modified = false; g_level.gravity = g_gravity->integer; gi.ConfigString(CS_GRAVITY, va("%d", g_level.gravity)); } if (g_teams->modified) { // reset teams, scores g_teams->modified = false; g_level.teams = g_teams->integer; gi.ConfigString(CS_TEAMS, va("%d", g_level.teams)); gi.BroadcastPrint(PRINT_HIGH, "Teams have been %s\n", g_level.teams ? "enabled" : "disabled"); G_RestartGame(true); } if (g_ctf->modified) { // reset teams, scores g_ctf->modified = false; g_level.ctf = g_ctf->integer; gi.ConfigString(CS_CTF, va("%d", g_level.ctf)); gi.BroadcastPrint(PRINT_HIGH, "CTF has been %s\n", g_level.ctf ? "enabled" : "disabled"); G_RestartGame(true); } if (g_match->modified) { // reset scores g_match->modified = false; g_level.match = g_match->integer; gi.ConfigString(CS_MATCH, va("%d", g_level.match)); g_level.warmup = g_level.match; // toggle warmup gi.BroadcastPrint(PRINT_HIGH, "Match has been %s\n", g_level.match ? "enabled" : "disabled"); G_RestartGame(false); } if (g_rounds->modified) { // reset scores g_rounds->modified = false; g_level.rounds = g_rounds->integer; gi.ConfigString(CS_ROUNDS, va("%d", g_level.rounds)); g_level.warmup = g_level.rounds; // toggle warmup gi.BroadcastPrint(PRINT_HIGH, "Rounds have been %s\n", g_level.rounds ? "enabled" : "disabled"); G_RestartGame(false); } if (g_cheats->modified) { // notify when cheats changes g_cheats->modified = false; gi.BroadcastPrint(PRINT_HIGH, "Cheats have been %s\n", g_cheats->integer ? "enabled" : "disabled"); } if (g_frag_limit->modified) { g_frag_limit->modified = false; g_level.frag_limit = g_frag_limit->integer; gi.BroadcastPrint(PRINT_HIGH, "Fraglimit has been changed to %d\n", g_level.frag_limit); } if (g_round_limit->modified) { g_round_limit->modified = false; g_level.round_limit = g_round_limit->integer; gi.BroadcastPrint(PRINT_HIGH, "Roundlimit has been changed to %d\n", g_level.round_limit); } if (g_capture_limit->modified) { g_capture_limit->modified = false; g_level.capture_limit = g_capture_limit->integer; gi.BroadcastPrint(PRINT_HIGH, "Capturelimit has been changed to %d\n", g_level.capture_limit); } if (g_time_limit->modified) { g_time_limit->modified = false; g_level.time_limit = g_time_limit->value; gi.BroadcastPrint(PRINT_HIGH, "Timelimit has been changed to %d\n", (int) g_level.time_limit); } }
/* * G_CheckRoundEnd */ static void G_CheckRoundEnd(void) { unsigned int i, g, e, clients; int j; g_edict_t *winner; g_client_t *cl; if (!g_level.rounds) return; if (!g_level.round_time || g_level.round_time > g_level.time) return; // no round currently running winner = NULL; g = e = clients = 0; for (j = 0; j < sv_max_clients->integer; j++) { if (!g_game.edicts[j + 1].in_use) continue; cl = g_game.edicts[j + 1].client; if (cl->persistent.spectator) // true spectator, or dead continue; winner = &g_game.edicts[j + 1]; if (g_level.teams) cl->persistent.team == &g_team_good ? g++ : e++; clients++; } if (clients == 0) { // corner case where everyone was fragged gi.BroadcastPrint(PRINT_HIGH, "Tie!\n"); g_level.round_time = 0; G_CheckRoundLimit(); return; } if (g_level.teams || g_level.ctf) { // teams rounds continue if each team has a player if (g > 0 && e > 0) return; } else if (clients > 1) // ffa continues if two players are alive return; // allow enemy projectiles to expire before declaring a winner for (i = 0; i < ge.num_edicts; i++) { if (!g_game.edicts[i + 1].in_use) continue; if (!g_game.edicts[i + 1].owner) continue; if (!(cl = g_game.edicts[i + 1].owner->client)) continue; if (g_level.teams || g_level.ctf) { if (cl->persistent.team != winner->client->persistent.team) return; } else { if (g_game.edicts[i + 1].owner != winner) return; } } // we have a winner gi.BroadcastPrint( PRINT_HIGH, "%s wins!\n", (g_level.teams || g_level.ctf ? winner->client->persistent.team->name : winner->client->persistent.net_name)); g_level.round_time = 0; G_CheckRoundLimit(); }
/* * G_RestartGame * * For normal games, this just means reset scores and respawn. * For match games, this means cancel the match and force everyone * to ready again. Teams are only reset when teamz is true. */ static void G_RestartGame(boolean_t teamz) { int i; g_edict_t *ent; g_client_t *cl; if (g_level.match_time) g_level.match_num++; if (g_level.round_time) g_level.round_num++; for (i = 0; i < sv_max_clients->integer; i++) { // reset clients if (!g_game.edicts[i + 1].in_use) continue; ent = &g_game.edicts[i + 1]; cl = ent->client; cl->persistent.ready = false; // back to warmup cl->persistent.score = 0; cl->persistent.captures = 0; if (teamz) // reset teams cl->persistent.team = NULL; // determine spectator or team affiliations if (g_level.match) { if (cl->persistent.match_num == g_level.match_num) cl->persistent.spectator = false; else cl->persistent.spectator = true; } else if (g_level.rounds) { if (cl->persistent.round_num == g_level.round_num) cl->persistent.spectator = false; else cl->persistent.spectator = true; } if (g_level.teams || g_level.ctf) { if (!cl->persistent.team) { if (g_auto_join->value) G_AddClientToTeam(ent, G_SmallestTeam()->name); else cl->persistent.spectator = true; } } G_ClientRespawn(ent, false); } G_ResetItems(); g_level.match_time = g_level.round_time = 0; g_team_good.score = g_team_evil.score = 0; g_team_good.captures = g_team_evil.captures = 0; gi.BroadcastPrint(PRINT_HIGH, "Game restarted\n"); gi.Sound(&g_game.edicts[0], gi.SoundIndex("world/teleport"), ATTN_NONE); }
/* * G_Init * * This will be called when the game module is first loaded. */ void G_Init(void) { gi.Print(" Game initialization...\n"); memset(&g_game, 0, sizeof(g_game)); gi.Cvar("game_name", GAME_NAME, CVAR_SERVER_INFO | CVAR_NO_SET, NULL); gi.Cvar("game_date", __DATE__, CVAR_SERVER_INFO | CVAR_NO_SET, NULL); g_auto_join = gi.Cvar("g_auto_join", "1", CVAR_SERVER_INFO, NULL); g_capture_limit = gi.Cvar("g_capture_limit", "8", CVAR_SERVER_INFO, NULL); g_chat_log = gi.Cvar("g_chat_log", "0", 0, NULL); g_cheats = gi.Cvar("g_cheats", "0", CVAR_SERVER_INFO, NULL); g_ctf = gi.Cvar("g_ctf", "0", CVAR_SERVER_INFO, NULL); g_frag_limit = gi.Cvar("g_frag_limit", "30", CVAR_SERVER_INFO, NULL); g_frag_log = gi.Cvar("g_frag_log", "0", 0, NULL); g_friendly_fire = gi.Cvar("g_friendly_fire", "1", CVAR_SERVER_INFO, NULL); g_gameplay = gi.Cvar("g_gameplay", "0", CVAR_SERVER_INFO, NULL); g_gravity = gi.Cvar("g_gravity", "800", CVAR_SERVER_INFO, NULL); g_match = gi.Cvar("g_match", "0", CVAR_SERVER_INFO, NULL); g_max_entities = gi.Cvar("g_max_entities", "1024", CVAR_LATCH, NULL); g_mysql = gi.Cvar("g_mysql", "0", 0, NULL); g_mysql_db = gi.Cvar("g_mysql_db", "quake2world", 0, NULL); g_mysql_host = gi.Cvar("g_mysql_host", "localhost", 0, NULL); g_mysql_password = gi.Cvar("g_mysql_password", "", 0, NULL); g_mysql_user = gi.Cvar("g_mysql_user", "quake2world", 0, NULL); g_player_projectile = gi.Cvar("g_player_projectile", "1", CVAR_SERVER_INFO, NULL); g_random_map = gi.Cvar("g_random_map", "0", 0, NULL); g_round_limit = gi.Cvar("g_round_limit", "30", CVAR_SERVER_INFO, NULL); g_rounds = gi.Cvar("g_rounds", "0", CVAR_SERVER_INFO, NULL); g_spawn_farthest = gi.Cvar("g_spawn_farthest", "0", CVAR_SERVER_INFO, NULL); g_teams = gi.Cvar("g_teams", "0", CVAR_SERVER_INFO, NULL); g_time_limit = gi.Cvar("g_time_limit", "20", CVAR_SERVER_INFO, NULL); g_voting = gi.Cvar("g_voting", "1", CVAR_SERVER_INFO, "Activates voting"); password = gi.Cvar("password", "", CVAR_USER_INFO, NULL); sv_max_clients = gi.Cvar("sv_max_clients", "8", CVAR_SERVER_INFO | CVAR_LATCH, NULL); dedicated = gi.Cvar("dedicated", "0", CVAR_NO_SET, NULL); if (g_frag_log->value) gi.OpenFile("frag_log.log", &frag_log, FILE_APPEND); if (g_chat_log->value) gi.OpenFile("chat_log.log", &chat_log, FILE_APPEND); #ifdef HAVE_MYSQL if(g_mysql->value) { //init database mysql = mysql_init(NULL); mysql_real_connect(mysql, g_mysql_host->string, g_mysql_user->string, g_mysql_password->string, g_mysql_db->string, 0, NULL, 0 ); if(mysql != NULL) gi.Print(" MySQL connection to %s/%s", g_mysql_host->string, g_mysql_user->string); } #endif G_ParseMapList("maps.lst"); G_InitItems(); // initialize entities and clients for this game g_game.edicts = gi.TagMalloc(g_max_entities->integer * sizeof(g_edict_t), TAG_GAME); g_game.clients = gi.TagMalloc(sv_max_clients->integer * sizeof(g_client_t), TAG_GAME); ge.edicts = g_game.edicts; ge.max_edicts = g_max_entities->integer; ge.num_edicts = sv_max_clients->integer + 1; // set these to false to avoid spurious game restarts and alerts on init g_gameplay->modified = g_teams->modified = g_match->modified = g_rounds->modified = g_ctf->modified = g_cheats->modified = g_frag_limit->modified = g_round_limit->modified = g_capture_limit->modified = g_time_limit->modified = false; gi.Print(" Game initialized.\n"); }
/* * @brief This will be called when the game module is first loaded. */ void G_Init(void) { gi.Print(" Game initialization...\n"); memset(&g_game, 0, sizeof(g_game)); gi.Cvar("game_name", GAME_NAME, CVAR_SERVER_INFO | CVAR_NO_SET, NULL); gi.Cvar("game_date", __DATE__, CVAR_SERVER_INFO | CVAR_NO_SET, NULL); g_ammo_respawn_time = gi.Cvar("g_ammo_respawn_time", "20.0", CVAR_SERVER_INFO, "Ammo respawn interval in seconds"); g_auto_join = gi.Cvar("g_auto_join", "1", CVAR_SERVER_INFO, "Automatically assigns players to teams"); g_capture_limit = gi.Cvar("g_capture_limit", "8", CVAR_SERVER_INFO, "The capture limit per level"); g_cheats = gi.Cvar("g_cheats", "0", CVAR_SERVER_INFO, NULL); g_ctf = gi.Cvar("g_ctf", "0", CVAR_SERVER_INFO, "Enables capture the flag gameplay"); g_frag_limit = gi.Cvar("g_frag_limit", "30", CVAR_SERVER_INFO, "The frag limit per level"); g_friendly_fire = gi.Cvar("g_friendly_fire", "1", CVAR_SERVER_INFO, "Enables friendly fire"); g_gameplay = gi.Cvar("g_gameplay", "0", CVAR_SERVER_INFO, "Selects deathmatch, arena, or instagib combat"); g_gravity = gi.Cvar("g_gravity", "800", CVAR_SERVER_INFO, NULL); g_match = gi.Cvar("g_match", "0", CVAR_SERVER_INFO, "Enables match play requiring players to ready"); g_max_entities = gi.Cvar("g_max_entities", "1024", CVAR_LATCH, NULL); g_motd = gi.Cvar("g_motd", "", CVAR_SERVER_INFO, "Message of the day, shown to clients on initial connect"); g_mysql = gi.Cvar("g_mysql", "0", 0, NULL); g_mysql_db = gi.Cvar("g_mysql_db", "quake2world", 0, NULL); g_mysql_host = gi.Cvar("g_mysql_host", "localhost", 0, NULL); g_mysql_password = gi.Cvar("g_mysql_password", "", 0, NULL); g_mysql_user = gi.Cvar("g_mysql_user", "quake2world", 0, NULL); g_password = gi.Cvar("g_password", "", CVAR_USER_INFO, "The server password"); g_player_projectile = gi.Cvar("g_player_projectile", "1.0", CVAR_SERVER_INFO, "Scales player velocity to projectiles"); g_random_map = gi.Cvar("g_random_map", "0", 0, "Enables map shuffling"); g_respawn_protection = gi.Cvar("g_respawn_protection", "0.0", 0, "Respawn protection in seconds"); g_round_limit = gi.Cvar("g_round_limit", "30", CVAR_SERVER_INFO, "The number of rounds to run per level"); g_rounds = gi.Cvar("g_rounds", "0", CVAR_SERVER_INFO, "Enables rounds-based play, where last player standing wins"); g_show_attacker_stats = gi.Cvar("g_show_attacker_stats", "1", CVAR_SERVER_INFO, NULL); g_spawn_farthest = gi.Cvar("g_spawn_farthest", "1", CVAR_SERVER_INFO, NULL); g_spectator_chat = gi.Cvar("g_spectator_chat", "1", CVAR_SERVER_INFO, "If enabled, spectators can only talk to other spectators"); g_teams = gi.Cvar("g_teams", "0", CVAR_SERVER_INFO, "Enables teams-based play"); g_time_limit = gi.Cvar("g_time_limit", "20.0", CVAR_SERVER_INFO, "The time limit per level in minutes"); g_voting = gi.Cvar("g_voting", "1", CVAR_SERVER_INFO, "Activates voting"); g_weapon_respawn_time = gi.Cvar("g_weapon_respawn_time", "5.0", CVAR_SERVER_INFO, "Weapon respawn interval in seconds"); sv_max_clients = gi.Cvar("sv_max_clients", "8", CVAR_SERVER_INFO | CVAR_LATCH, NULL); sv_hostname = gi.Cvar("sv_hostname", "Quake2World", CVAR_SERVER_INFO, NULL); dedicated = gi.Cvar("dedicated", "0", CVAR_NO_SET, NULL); #ifdef HAVE_MYSQL if(g_mysql->value) { //init database mysql = mysql_init(NULL); mysql_real_connect(mysql, g_mysql_host->string, g_mysql_user->string, g_mysql_password->string, g_mysql_db->string, 0, NULL, 0 ); if(mysql != NULL) gi.Print(" MySQL connection to %s/%s", g_mysql_host->string, g_mysql_user->string); } #endif G_ParseMapList("maps.lst"); // initialize entities and clients for this game g_game.edicts = gi.Malloc(g_max_entities->integer * sizeof(g_edict_t), MEM_TAG_GAME); g_game.clients = gi.Malloc(sv_max_clients->integer * sizeof(g_client_t), MEM_TAG_GAME); ge.edicts = g_game.edicts; ge.max_edicts = g_max_entities->integer; ge.num_edicts = sv_max_clients->integer + 1; G_Ai_Init(); // initialize the AI // set these to false to avoid spurious game restarts and alerts on init g_gameplay->modified = g_teams->modified = g_match->modified = g_rounds->modified = g_ctf->modified = g_cheats->modified = g_frag_limit->modified = g_round_limit->modified = g_capture_limit->modified = g_time_limit->modified = false; gi.Print(" Game initialized\n"); }