void PMenu_Close(edict_t *ent) { pmenuhnd_t *hnd; int i; if (!ent->client->menu) return; hnd = ent->client->menu; if (hnd->entries) { for (i = 0; i < hnd->num; i++) { if (hnd->entries[i].text) { G_Free(hnd->entries[i].text); hnd->entries[i].text = NULL; } } G_Free(hnd->entries); hnd->entries = NULL; } if (hnd->arg) { G_Free(hnd->arg); hnd->arg = NULL; } G_Free(ent->client->menu); ent->client->menu = NULL; ent->client->showscores = false; }
/* * G_Shutdown */ void G_Shutdown( void ) { int i; G_Printf( "==== G_Shutdown ====\n" ); GT_asCallShutdown(); G_asCallMapExit(); G_asShutdownMapScript(); GT_asShutdownScript(); G_asShutdownGameModuleEngine(); SV_WriteIPList (); trap_Cvar_ForceSet( "nextmap", va( "map \"%s\"", G_SelectNextMapName() ) ); AI_Shutdown(); G_RemoveCommands(); G_FreeCallvotes(); G_LevelFreePool(); for( i = 0; i < game.numentities; i++ ) { if( game.edicts[i].r.inuse ) G_FreeEdict( &game.edicts[i] ); } G_Free( game.edicts ); G_Free( game.clients ); }
void JKG_Pairs_Clear(KeyPairSet_t *set){ int i; for(i = 0; i<set->count; i++){ G_Free(set->pairs[i].key); G_Free(set->pairs[i].value); } JKG_Arrays_RemoveAllElements((void **)&set->pairs); set->count = 0; }
/* ================= EndDMLevel The timelimit or fraglimit has been exceeded ================= */ void EndDMLevel (void) { edict_t *ent; char *s, *t, *f; static const char seps[] = " ,\n\r"; // stay on same level flag if ((int)dmflags->value & DF_SAME_LEVEL) { BeginIntermission (CreateTargetChangeLevel (level.mapname) ); return; } // see if it's in the map list if (*sv_maplist->string) { s = G_CopyString(sv_maplist->string); f = NULL; t = strtok(s, seps); while (t != NULL) { if (Q_strcasecmp(t, level.mapname) == 0) { // it's in the list, go to the next one t = strtok(NULL, seps); if (t == NULL) { // end of list, go to first one if (f == NULL) // there isn't a first one, same level BeginIntermission (CreateTargetChangeLevel (level.mapname) ); else BeginIntermission (CreateTargetChangeLevel (f) ); } else BeginIntermission (CreateTargetChangeLevel (t) ); G_Free(s); return; } if (!f) f = t; t = strtok(NULL, seps); } G_Free(s); } if (level.nextmap[0]) // go to a specific map BeginIntermission (CreateTargetChangeLevel (level.nextmap) ); else { // search for a changelevel ent = G_Find (NULL, FOFS(classname), "target_changelevel"); if (!ent) { // the map designer didn't include a changelevel, // so create a fake ent that goes back to the same level BeginIntermission (CreateTargetChangeLevel (level.mapname) ); return; } BeginIntermission (ent); } }
qboolean G_deleteGlobal(int id) { global_t *global = level.globals; global_t *lastGlobal = NULL; while (global) { if (global->id == id) { if (lastGlobal == NULL) { level.globals = global->next; } else { lastGlobal->next = global->next; } if (trap_mysql_runquery(va("DELETE QUICK FROM globals WHERE id = %d LIMIT 1", id)) == qtrue) { trap_mysql_finishquery(); G_Free(global); return qtrue; } else { G_AdminsPrintf("Cant delete %d from database, try !reconnectdb then !gsync\n", id); return qfalse; } } lastGlobal = global; global = global->next; } return qfalse; }
void ChasecamRemove (edict_t *ent) { /* Stop the chasecam from moving */ VectorClear (ent->client->chasecam->velocity); ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model); // if (ent->owner->health) ?? SKid ent->s.modelindex = ent->client->oldplayer->s.modelindex; ent->s.modelindex2= ent->client->oldplayer->s.modelindex2; ent->s.modelindex3= ent->client->oldplayer->s.modelindex3; ent->client->ps.pmove.pm_type &= ~PMF_NO_PREDICTION; if(!ent->client->resp.spectator) { ent->svflags &= ~SVF_NOCLIENT; ent->s.renderfx &= ~RF_NOSHADOW; } G_Free(ent->client->oldplayer->client); G_FreeEdict (ent->client->oldplayer); G_FreeEdict (ent->client->chasecam); ent->client->chase_target = NULL; ent->client->chasetoggle = 0; ent->client->chaseactive = 0; }
/* * G_SanitizeUserString */ static int G_SanitizeUserString( char *string, size_t size ) { static char *colorless = NULL; static size_t colorless_size = 0; int i, c_ascii; // life is hard, UTF-8 will have to go strip_highchars( string ); COM_SanitizeColorString( va( "%s", string ), string, size, -1, COLOR_WHITE ); Q_trim( string ); if( colorless_size < strlen( string ) + 1 ) { colorless_size = strlen( string ) + 1; G_Free( colorless ); colorless = ( char * )G_Malloc( colorless_size ); } Q_strncpyz( colorless, COM_RemoveColorTokens( string ), colorless_size ); // require at least one non-whitespace ascii char in the string // (this will upset people who would like to have a name entirely in a non-latin // script, but it makes damn sure you can't get an empty name by exploiting some // utf-8 decoder quirk) c_ascii = 0; for( i = 0; colorless[i]; i++ ) if( colorless[i] > 32 && colorless[i] < 127 ) c_ascii++; return c_ascii; }
// only use on pmenu's that have been called with PMenu_Open void PMenu_UpdateEntry(pmenu_t *entry, const char *text, int align, SelectFunc_t SelectFunc) { if (entry->text) G_Free(entry->text); entry->text = G_CopyString((char *)text); entry->align = align; entry->SelectFunc = SelectFunc; }
void G_globalExit(void) { global_t *temp = level.globals; whitelist_t *whitelist = level.whitelist; while (temp != NULL) { global_t *temp2 = temp->next; G_Free(temp); temp = temp2; } while (whitelist != NULL) { whitelist_t *whitelist2 = whitelist->next; G_Free(whitelist); whitelist = whitelist2; } }
//========================================== // G_FreeAI // removes the AI handle from memory //========================================== void G_FreeAI( edict_t *ent ) { if( !ent->ai ) { return; } if( ent->ai->type == AI_ISBOT ) { game.numBots--; } G_Free( ent->ai ); ent->ai = NULL; }
// free the list of clientRatings static void g_ratingsFree( clientRating_t *list ) { clientRating_t *next; while( list ) { next = list->next; G_Free( list ); list = next; } }
//========================================== // G_FreeAI // removes the AI handle from memory //========================================== void G_FreeAI( edict_t *ent ) { if (!ent->ai) return; AiManager::Instance()->UnlinkAi(ent->ai); // Perform virtual destructor call ent->ai->aiRef->~Ai(); G_Free(ent->ai); ent->ai = nullptr; }
/* * G_Gametype_GenerateGametypesList */ void G_Gametype_GenerateGametypesList( void ) { char *scriptsList; scriptsList = G_AllocCreateNamesList( "progs/gametypes", GAMETYPE_PROJECT_EXTENSION, CHAR_GAMETYPE_SEPARATOR ); if( !scriptsList ) { trap_Cvar_ForceSet( "g_gametypes_list", "dm;" ); return; } trap_Cvar_ForceSet( "g_gametypes_list", scriptsList ); G_Free( scriptsList ); }
void AiBaseTeamBrain::RegisterTeamBrain( int team, AiBaseTeamBrain *brain ) { if( teamBrains[team - 1] ) { UnregisterTeamBrain( team ); } // Set team brain pointer teamBrains[team - 1] = brain; // Use address of a static array cell for the brain pointer as a tag uint64_t tag = (uint64_t)( teamBrains + team - 1 ); // Capture brain pointer (a stack variable) by value! AiShutdownHooksHolder::Instance()->RegisterHook( tag, [ = ] { brain->~AiBaseTeamBrain(); G_Free( brain ); } ); }
void AiBaseTeamBrain::UnregisterTeamBrain( int team ) { if( !teamBrains[team - 1] ) { return; } AiBaseTeamBrain *brainToDelete = teamBrains[team - 1]; // Reset team brain pointer teamBrains[team - 1] = nullptr; // Destruct the brain brainToDelete->~AiBaseTeamBrain(); // Free brain memory G_Free( brainToDelete ); // Use address of a static array cell for the brain pointer as a tag uint64_t tag = (uint64_t)( teamBrains + team - 1 ); AiShutdownHooksHolder::Instance()->UnregisterHook( tag ); }
// removes all references for given entity void G_RemoveRating( edict_t *ent ) { gclient_t *client; clientRating_t *cr; client = ent->r.client; // first from the game cr = Rating_DetachId( &game.ratings, client->mm_session ); if( cr ) G_Free( cr ); // then the clients own list g_ratingsFree( client->ratings ); client->ratings = 0; g_serverRating(); }
qboolean G_deleteWhite(int id) { whitelist_t *whitelist = level.whitelist; whitelist_t *lastWhitelist = NULL; while (whitelist) { if (whitelist->id == id) { if (lastWhitelist == NULL) { level.whitelist = whitelist->next; } else { lastWhitelist->next = whitelist->next; } if (trap_mysql_runquery(va("DELETE QUICK FROM whitelist WHERE id = %d LIMIT 1", id)) == qtrue) { trap_mysql_finishquery(); G_Free(whitelist); return qtrue; } else { G_AdminsPrintf("Cant delete %d from database, try !reconnectdb then !gsync\n",id); return qfalse; } } lastWhitelist = whitelist; whitelist = whitelist->next; } return qfalse; }
/* * G_UpdateServerInfo * update the cvars which show the match state at server browsers */ static void G_UpdateServerInfo( void ) { // g_match_time if( GS_MatchState() <= MATCH_STATE_WARMUP ) { trap_Cvar_ForceSet( "g_match_time", "Warmup" ); } else if( GS_MatchState() == MATCH_STATE_COUNTDOWN ) { trap_Cvar_ForceSet( "g_match_time", "Countdown" ); } else if( GS_MatchState() == MATCH_STATE_PLAYTIME ) { // partly from G_GetMatchState char extra[MAX_INFO_VALUE]; int clocktime, timelimit, mins, secs; if( GS_MatchDuration() ) timelimit = ( ( GS_MatchDuration() ) * 0.001 ) / 60; else timelimit = 0; clocktime = (float)( game.serverTime - GS_MatchStartTime() ) * 0.001f; if( clocktime <= 0 ) { mins = 0; secs = 0; } else { mins = clocktime / 60; secs = clocktime - mins * 60; } extra[0] = 0; if( GS_MatchExtended() ) { if( timelimit ) Q_strncatz( extra, " overtime", sizeof( extra ) ); else Q_strncatz( extra, " suddendeath", sizeof( extra ) ); } if( GS_MatchPaused() ) Q_strncatz( extra, " (in timeout)", sizeof( extra ) ); if( timelimit ) trap_Cvar_ForceSet( "g_match_time", va( "%02i:%02i / %02i:00%s", mins, secs, timelimit, extra ) ); else trap_Cvar_ForceSet( "g_match_time", va( "%02i:%02i%s", mins, secs, extra ) ); } else { trap_Cvar_ForceSet( "g_match_time", "Finished" ); } // g_match_score if( GS_MatchState() >= MATCH_STATE_PLAYTIME && GS_TeamBasedGametype() ) { char score[MAX_INFO_STRING]; score[0] = 0; Q_strncatz( score, va( " %s: %i", GS_TeamName( TEAM_ALPHA ), teamlist[TEAM_ALPHA].stats.score ), sizeof( score ) ); Q_strncatz( score, va( " %s: %i", GS_TeamName( TEAM_BETA ), teamlist[TEAM_BETA].stats.score ), sizeof( score ) ); if( strlen( score ) >= MAX_INFO_VALUE ) { // prevent "invalid info cvar value" flooding score[0] = '\0'; } trap_Cvar_ForceSet( "g_match_score", score ); } else { trap_Cvar_ForceSet( "g_match_score", "" ); } // g_needpass if( password->modified ) { if( password->string && strlen( password->string ) ) { trap_Cvar_ForceSet( "g_needpass", "1" ); } else { trap_Cvar_ForceSet( "g_needpass", "0" ); } password->modified = false; } // g_gametypes_available if( g_votable_gametypes->modified || g_disable_vote_gametype->modified ) { if( g_disable_vote_gametype->integer || !g_votable_gametypes->string || !strlen( g_votable_gametypes->string ) ) { trap_Cvar_ForceSet( "g_gametypes_available", "" ); } else { char *votable; char *name; size_t len; int count; len = 0; for( count = 0; ( name = G_ListNameForPosition( g_gametypes_list->string, count, CHAR_GAMETYPE_SEPARATOR ) ) != NULL; count++ ) { if( G_Gametype_IsVotable( name ) ) len += strlen( name ) + 1; } len++; votable = ( char * )G_Malloc( len ); votable[0] = 0; for( count = 0; ( name = G_ListNameForPosition( g_gametypes_list->string, count, CHAR_GAMETYPE_SEPARATOR ) ) != NULL; count++ ) { if( G_Gametype_IsVotable( name ) ) { Q_strncatz( votable, name, len ); Q_strncatz( votable, " ", len ); } } //votable[ strlen( votable )-2 ] = 0; // remove the last space trap_Cvar_ForceSet( "g_gametypes_available", votable ); G_Free( votable ); } g_votable_gametypes->modified = false; g_disable_vote_gametype->modified = false; } if( GS_RaceGametype() ) { trap_Cvar_ForceSet( "g_race_gametype", "1" ); } else { trap_Cvar_ForceSet( "g_race_gametype", "0" ); } }
/* * G_UpdateMapRotation * * Reads current map rotation into internal list */ static void G_UpdateMapRotation( void ) { int count; qboolean thiswhitespace, lastwhitespace; char *p; static const char *seps = " ,\n\r"; if( g_maplist->modified || !map_rotation_s || !map_rotation_p ) { g_maplist->modified = qfalse; // reread the maplist if( map_rotation_s ) G_Free( map_rotation_s ); if( map_rotation_p ) G_Free( map_rotation_p ); map_rotation_s = G_CopyString( g_maplist->string ); map_rotation_p = NULL; map_rotation_current = 0; // reset the mapcounter too map_rotation_count = 0; // count the number of tokens p = map_rotation_s; count = 0; lastwhitespace = qtrue; while( *p ) { thiswhitespace = ( strchr( seps, *p ) != NULL ) ? qtrue : qfalse; if( lastwhitespace && !thiswhitespace ) count++; lastwhitespace = thiswhitespace; p++; } if( !count ) return; // allocate the array of pointers map_rotation_p = G_Malloc( ( count + 1 ) * sizeof( *map_rotation_p ) ); // now convert the string to tokens by nulling the separators p = map_rotation_s; count = 0; lastwhitespace = qtrue; while( *p ) { thiswhitespace = ( strchr( seps, *p ) != NULL ) ? qtrue : qfalse; if( lastwhitespace && !thiswhitespace ) map_rotation_p[count++] = p; if( thiswhitespace ) *p = 0; lastwhitespace = thiswhitespace; p++; } // final null pointer to mark the end map_rotation_p[count] = NULL; map_rotation_count = count; } }
/* * SpawnEntities * * Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void G_InitLevel( char *mapname, char *entities, int entstrlen, unsigned int levelTime, unsigned int serverTime, unsigned int realTime ) { char *mapString = NULL; char name[MAX_CONFIGSTRING_CHARS]; int i; edict_t *ent; char *token; const gsitem_t *item; G_asGarbageCollect( true ); GT_asCallShutdown(); G_asCallMapExit(); G_asShutdownMapScript(); GT_asShutdownScript(); G_FreeCallvotes(); game.serverTime = serverTime; game.realtime = realTime; game.levelSpawnCount++; GClip_ClearWorld(); // clear areas links if( !entities ) G_Error( "G_SpawnLevel: NULL entities string\n" ); // make a copy of the raw entities string so it's not freed with the pool mapString = ( char * )G_Malloc( entstrlen + 1 ); memcpy( mapString, entities, entstrlen ); Q_strncpyz( name, mapname, sizeof( name ) ); // clear old data G_LevelInitPool( strlen( mapname ) + 1 + ( entstrlen + 1 ) * 2 + G_LEVELPOOL_BASE_SIZE ); G_StringPoolInit(); memset( &level, 0, sizeof( level_locals_t ) ); memset( &gs.gameState, 0, sizeof( gs.gameState ) ); level.spawnedTimeStamp = game.realtime; level.time = levelTime; level.gravity = g_gravity->value; // get the strings back Q_strncpyz( level.mapname, name, sizeof( level.mapname ) ); level.mapString = ( char * )G_LevelMalloc( entstrlen + 1 ); level.mapStrlen = entstrlen; memcpy( level.mapString, mapString, entstrlen ); G_Free( mapString ); mapString = NULL; // make a copy of the raw entities string for parsing level.map_parsed_ents = ( char * )G_LevelMalloc( entstrlen + 1 ); level.map_parsed_ents[0] = 0; if( !level.time ) memset( game.edicts, 0, game.maxentities * sizeof( game.edicts[0] ) ); else { G_FreeEdict( world ); for( i = gs.maxclients + 1; i < game.maxentities; i++ ) { if( game.edicts[i].r.inuse ) G_FreeEdict( game.edicts + i ); } } game.numentities = gs.maxclients + 1; // link client fields on player ents for( i = 0; i < gs.maxclients; i++ ) { game.edicts[i+1].s.number = i+1; game.edicts[i+1].r.client = &game.clients[i]; game.edicts[i+1].r.inuse = ( trap_GetClientState( i ) >= CS_CONNECTED ) ? true : false; memset( &game.clients[i].level, 0, sizeof( game.clients[0].level ) ); game.clients[i].level.timeStamp = level.time; } // initialize game subsystems trap_ConfigString( CS_MAPNAME, level.mapname ); trap_ConfigString( CS_SKYBOX, "" ); trap_ConfigString( CS_AUDIOTRACK, "" ); trap_ConfigString( CS_STATNUMS, va( "%i %i %i", STAT_SCORE, STAT_HEALTH, STAT_LAST_KILLER ) ); trap_ConfigString( CS_POWERUPEFFECTS, va( "%i %i %i %i", EF_QUAD, EF_SHELL, EF_CARRIER, EF_REGEN ) ); trap_ConfigString( CS_SCB_PLAYERTAB_LAYOUT, "" ); trap_ConfigString( CS_SCB_PLAYERTAB_TITLES, "" ); trap_ConfigString( CS_MATCHNAME, "" ); trap_ConfigString( CS_MATCHSCORE, "" ); // reset map messages for( i = 0; i < MAX_HELPMESSAGES; i++ ) { trap_ConfigString( CS_HELPMESSAGES + i, "" ); } G_InitGameCommands(); G_MapLocations_Init(); G_CallVotes_Init(); G_SpawnQueue_Init(); G_Teams_Init(); // load map script G_asLoadMapScript( level.mapname ); G_Gametype_Init(); // ch : this would be the location to "transfer ratings" G_PrecacheItems(); // set configstrings for items (gametype must be initialized) G_PrecacheMedia(); G_PrecacheGameCommands(); // adding commands after this point won't update them to the client AI_InitLevel(); // load navigation file of the current map // start spawning entities level.canSpawnEntities = true; G_InitBodyQueue(); // reserve some spots for dead player bodies entities = level.mapString; i = 0; ent = NULL; while( 1 ) { level.spawning_entity = NULL; // parse the opening brace token = COM_Parse( &entities ); if( !entities ) break; if( token[0] != '{' ) G_Error( "G_SpawnMapEntities: found %s when expecting {", token ); if( !ent ) { ent = world; G_InitEdict( world ); } else ent = G_Spawn(); ent->spawnString = entities; // keep track of string definition of this entity entities = ED_ParseEdict( entities, ent ); if( !ent->classname ) { i++; // racesow - introducing the freestyle map bug again in // order to make some freestyle maps work if( !level.gametype.freestyleMapFix ) G_FreeEdict( ent ); // !racesow G_FreeEdict( ent ); continue; } if( !G_CanSpawnEntity( ent ) ) { i++; G_FreeEdict( ent ); continue; } if( !G_CallSpawn( ent ) ) { i++; G_FreeEdict( ent ); continue; } // check whether an item is allowed to spawn if( ( item = ent->item ) ) { // not pickable items aren't spawnable if( item->flags & ITFLAG_PICKABLE ) { if( G_Gametype_CanSpawnItem( item ) ) { // override entity's classname with whatever item specifies ent->classname = item->classname; PrecacheItem( item ); continue; } } i++; G_FreeEdict( ent ); continue; } } G_FindTeams(); // is the parsing string sane? assert( (int)level.map_parsed_len < entstrlen ); level.map_parsed_ents[level.map_parsed_len] = 0; // make sure server got the edicts data trap_LocateEntities( game.edicts, sizeof( game.edicts[0] ), game.numentities, game.maxentities ); // items need brush model entities spawned before they are linked G_Items_FinishSpawningItems(); // // initialize game subsystems which require entities initialized // // call gametype specific GT_asCallSpawn(); // call map specific G_asCallMapInit(); AI_InitEntitiesData(); // always start in warmup match state and let the thinking code // revert it to wait state if empty ( so gametype based item masks are setup ) G_Match_LaunchState( MATCH_STATE_WARMUP ); G_asGarbageCollect( true ); // racesow RS_Init(); }
//========================================== // BOT_GetUnusedSkin // Retrieve a random unused skin & name //========================================== static bool BOT_GetUnusedSkin( char *bot_model, char *bot_skin, char *bot_name ) { bool inuse; int skinnumber; char *model, *skin; char scratch[MAX_INFO_STRING]; int i, freeskins; edict_t *ent; localbotskin_t *botskins; localbotskin_t *localbotskin; //count the unused skins, and make sure there is at least 1 of them skinnumber = freeskins = 0; while( LocalBotSkins[skinnumber] != NULL ) { inuse = false; for( i = 0, ent = game.edicts + 1; i < gs.maxclients; i++, ent++ ) { if( !( ent->r.svflags & SVF_FAKECLIENT ) || !ent->r.client ) continue; model = Info_ValueForKey( ent->r.client->userinfo, "model" ); skin = Info_ValueForKey( ent->r.client->userinfo, "skinl" ); if( model && skin ) { Q_snprintfz( scratch, sizeof( scratch ), "%s/%s", model, skin ); if( !Q_stricmp( scratch, LocalBotSkins[skinnumber] ) ) { inuse = true; break; } } } if( inuse == false ) freeskins++; skinnumber++; } //fallback to old method if( !freeskins ) return false; //assign tmp memory for storing unused skins botskins = (localbotskin_t *)G_Malloc( sizeof( localbotskin_t ) * freeskins ); //create a list of unused skins skinnumber = freeskins = 0; while( LocalBotSkins[skinnumber] != NULL ) { inuse = false; for( i = 0, ent = game.edicts + 1; i < gs.maxclients; i++, ent++ ) { if( !( ent->r.svflags & SVF_FAKECLIENT ) || !ent->r.client ) continue; model = Info_ValueForKey( ent->r.client->userinfo, "model" ); skin = Info_ValueForKey( ent->r.client->userinfo, "skinl" ); if( model && skin ) { Q_snprintfz( scratch, sizeof( scratch ), "%s/%s", model, skin ); if( !Q_stricmp( scratch, LocalBotSkins[skinnumber] ) ) { inuse = true; break; } } } //store and advance if( inuse == false ) { const char *p; localbotskin = botskins + freeskins; p = strchr( LocalBotSkins[skinnumber], '/' ); if( !strlen( p ) ) continue; p++; Q_strncpyz( localbotskin->bot_model, LocalBotSkins[skinnumber], strlen( LocalBotSkins[skinnumber] ) - strlen( p ) ); Q_strncpyz( localbotskin->bot_skin, p, sizeof( localbotskin->bot_skin ) ); Q_strncpyz( localbotskin->bot_name, LocalBotNames[skinnumber], sizeof( localbotskin->bot_name ) ); if( nav.debugMode ) Com_Printf( "Free skin: %i: %s %s\n", freeskins, localbotskin->bot_skin, localbotskin->bot_name ); freeskins++; } skinnumber++; } //now get a random skin from the list skinnumber = (int)( random()*freeskins ); localbotskin = botskins + skinnumber; Q_strncpyz( bot_model, localbotskin->bot_model, sizeof( localbotskin->bot_model ) ); Q_strncpyz( bot_skin, localbotskin->bot_skin, sizeof( localbotskin->bot_skin ) ); Q_strncpyz( bot_name, localbotskin->bot_name, sizeof( localbotskin->bot_name ) ); if( nav.debugMode ) Com_Printf( "Assigned bot character: %i: %s %s %s\n", skinnumber, bot_model, bot_skin, bot_name ); G_Free( botskins ); return true; }
// Argh! - loads id baseq2/player models, "patches" their skin links // for misc_actor (all id skins, and slots for 10 custom // skins), and saves them to the current moddir location // int PatchPlayerModels (char *modelname) { cvar_t *game; int j; int numskins; // number of skin entries char skins[MAX_MD2SKINS][MAX_SKINNAME]; // skin entries char infilename[MAX_OSPATH]; char outfilename[MAX_OSPATH]; FILE *infile; FILE *outfile; dmdl_t model; // model header byte *data; // model data int datasize; // model data size (bytes) int newoffset; // model data offset (after skins) // get game (moddir) name game = gi.cvar("game", "", 0); if (!*game->string) return 0; // we're in baseq2 sprintf (outfilename, "%s/players/%s/tris.md2", game->string, modelname); if ((outfile = fopen (outfilename, "rb"))) { // output file already exists, move along fclose (outfile); // gi.dprintf ("PatchPlayerModels: Could not save %s, file already exists\n", outfilename); return 0; } // clear skin names (just in case) for (j = 0; j < MAX_MD2SKINS; j++) memset (skins[j], 0, MAX_SKINNAME); // set model-specific data if(!Q_strcasecmp(modelname,"male")) { numskins = 15; sprintf (skins[0], "players/male/cipher.pcx"); sprintf (skins[1], "players/male/claymore.pcx"); sprintf (skins[2], "players/male/flak.pcx"); sprintf (skins[3], "players/male/grunt.pcx"); sprintf (skins[4], "players/male/howitzer.pcx"); sprintf (skins[5], "players/male/major.pcx"); sprintf (skins[6], "players/male/nightops.pcx"); sprintf (skins[7], "players/male/pointman.pcx"); sprintf (skins[8], "players/male/psycho.pcx"); sprintf (skins[9], "players/male/rampage.pcx"); sprintf (skins[10], "players/male/razor.pcx"); sprintf (skins[11], "players/male/recon.pcx"); sprintf (skins[12], "players/male/scout.pcx"); sprintf (skins[13], "players/male/sniper.pcx"); sprintf (skins[14], "players/male/viper.pcx"); } else if(!Q_strcasecmp(modelname,"female")) { numskins = 10; sprintf (skins[0], "players/female/athena.pcx"); sprintf (skins[1], "players/female/brianna.pcx"); sprintf (skins[2], "players/female/cobalt.pcx"); sprintf (skins[3], "players/female/ensign.pcx"); sprintf (skins[4], "players/female/jezebel.pcx"); sprintf (skins[5], "players/female/jungle.pcx"); sprintf (skins[6], "players/female/lotus.pcx"); sprintf (skins[7], "players/female/stiletto.pcx"); sprintf (skins[8], "players/female/venus.pcx"); sprintf (skins[9], "players/female/voodoo.pcx"); } else if(!Q_strcasecmp(modelname,"cyborg")) { numskins = 3; sprintf (skins[0], "players/cyborg/oni911.pcx"); sprintf (skins[1], "players/cyborg/ps9000.pcx"); sprintf (skins[2], "players/cyborg/tyr574.pcx"); } else return 0; // fill in 32 slots with "customXX" for(j=numskins; j<32; j++) sprintf( skins[j], "players/%s/custom%d.pcx", modelname, j-numskins+1); numskins = 32; // load original player model sprintf (infilename, "baseq2/players/%s/tris.md2", modelname); if ( !(infile = fopen (infilename, "rb")) ) return 0; // no player model (this shouldn't happen) fread (&model, sizeof (dmdl_t), 1, infile); datasize = model.ofs_end - model.ofs_skins; if ( !(data = (byte*)G_Malloc (datasize)) ) // make sure freed locally { gi.dprintf ("PatchPlayerModels: Could not allocate memory for model\n"); return 0; } fread (data, sizeof (byte), datasize, infile); fclose (infile); // update model info model.num_skins = numskins; newoffset = numskins * MAX_SKINNAME; model.ofs_st += newoffset; model.ofs_tris += newoffset; model.ofs_frames += newoffset; model.ofs_glcmds += newoffset; model.ofs_end += newoffset; // save new player model sprintf (outfilename, "%s/players", game->string); // make some dirs if needed _mkdir (outfilename); sprintf (outfilename, "%s/players/%s", game->string, modelname); _mkdir (outfilename); sprintf (outfilename, "%s/players/%s/tris.md2", game->string, modelname); if ( !(outfile = fopen (outfilename, "wb")) ) { // file couldn't be created for some other reason gi.dprintf ("PatchPlayerModels: Could not save %s\n", outfilename); G_Free(data); return 0; } fwrite (&model, sizeof (dmdl_t), 1, outfile); fwrite (skins, sizeof (char), newoffset, outfile); fwrite (data, sizeof (byte), datasize, outfile); fclose (outfile); gi.dprintf ("PatchPlayerModels: Saved %s\n", outfilename); G_Free(data); return 1; }
void JKG_Pairs_Remove(KeyPairSet_t *set, int index){ // Just free, if its NULL it'll bail out anyway, no need to check twice G_Free(set->pairs[index].key); G_Free(set->pairs[index].value); JKG_Arrays_RemoveArrayElement((void **)&set->pairs, index, sizeof(KeyPair_t), &set->count); }
/* * G_GS_Free - Used only for gameshared linking */ static void G_GS_Free( void *data ) { G_Free( data ); }
/* * G_UpdateMapRotation * * Reads current map rotation into internal list */ static void G_UpdateMapRotation( void ) { int count, i; bool thiswhitespace, lastwhitespace, found; char *p, *start; static const char *seps = " ,\n\r"; if( g_maplist->modified || !map_rotation_s || !map_rotation_p ) { g_maplist->modified = false; // reread the maplist if( map_rotation_s ) G_Free( map_rotation_s ); if( map_rotation_p ) G_Free( map_rotation_p ); map_rotation_s = G_CopyString( g_maplist->string ); map_rotation_p = NULL; map_rotation_current = -1; // reset the mapcounter too map_rotation_count = 0; // count the number of tokens p = map_rotation_s; count = 0; lastwhitespace = true; start = NULL; found = false; while( *p ) { thiswhitespace = ( strchr( seps, *p ) != NULL ) ? true : false; if( lastwhitespace && !thiswhitespace ) { start = p; count++; } else if( thiswhitespace && !lastwhitespace && !found && start ) { found = true; for( i = 0; start + i < p; i++ ) { if( tolower( start[i] ) != tolower( level.mapname[i] ) ) found = false; } if( found ) map_rotation_current = count - 1; } lastwhitespace = thiswhitespace; p++; } if( !count ) return; // allocate the array of pointers map_rotation_p = ( char ** )G_Malloc( ( count + 1 ) * sizeof( *map_rotation_p ) ); // now convert the string to tokens by nulling the separators p = map_rotation_s; count = 0; lastwhitespace = true; while( *p ) { thiswhitespace = ( strchr( seps, *p ) != NULL ) ? true : false; if( lastwhitespace && !thiswhitespace ) map_rotation_p[count++] = p; if( thiswhitespace ) *p = 0; lastwhitespace = thiswhitespace; p++; } // final null pointer to mark the end map_rotation_p[count] = NULL; map_rotation_count = count; } }