/* ======================= G_RegisterPlayerClasses ======================= */ void G_RegisterPlayerClasses( void ) { bg_playerclass_t *classInfo; bg_character_t *character; int team, cls; for ( team = TEAM_AXIS; team <= TEAM_ALLIES; team++ ) { for ( cls = PC_SOLDIER; cls < NUM_PLAYER_CLASSES; cls++ ) { classInfo = BG_GetPlayerClassInfo( team, cls ); character = BG_GetCharacter( team, cls ); Q_strncpyz( character->characterFile, classInfo->characterFile, sizeof( character->characterFile ) ); if ( !G_RegisterCharacter( character->characterFile, character ) ) { G_Error( "ERROR: G_RegisterPlayerClasses: failed to load character file '%s' for the %s %s\n", character->characterFile, ( team == TEAM_AXIS ? "Axis" : "Allied" ), BG_ClassnameForNumber( classInfo->classNum ) ); } } } }
/** * @brief Sends an class setup message. Enables etpro like classscripts */ void CG_Class_f(void) { char cls[64]; const char *classtype, *teamstring; int weapon1, weapon2, playerclass; bg_playerclass_t *classinfo; team_t team; if (cg.demoPlayback) { return; } team = cgs.clientinfo[cg.clientNum].team; if (team == TEAM_SPECTATOR) { return; } if (trap_Argc() < 2) { CG_Printf("Invalid command format.\n"); return; } switch (team) { case TEAM_AXIS: classtype = "r"; teamstring = CG_TranslateString("Axis"); break; case TEAM_ALLIES: classtype = "b"; teamstring = CG_TranslateString("Allies"); break; default: CG_Printf("Invalid team.\n"); return; } trap_Argv(1, cls, 64); if (!Q_stricmp(cls, "s") || !Q_stricmp(cls, "0")) { playerclass = PC_SOLDIER; } else if (!Q_stricmp(cls, "m") || !Q_stricmp(cls, "1")) { playerclass = PC_MEDIC; } else if (!Q_stricmp(cls, "e") || !Q_stricmp(cls, "2")) { playerclass = PC_ENGINEER; } else if (!Q_stricmp(cls, "f") || !Q_stricmp(cls, "3")) { playerclass = PC_FIELDOPS; } else if (!Q_stricmp(cls, "c") || !Q_stricmp(cls, "4")) { playerclass = PC_COVERTOPS; } else { CG_Printf("Invalid class format.\n"); return; } classinfo = BG_GetPlayerClassInfo(team, playerclass); if (trap_Argc() > 2) { trap_Argv(2, cls, 64); weapon1 = atoi(cls); if (weapon1 <= 0 || weapon1 > MAX_WEAPS_PER_CLASS) { weapon1 = classinfo->classWeapons[0]; } else if (!classinfo->classWeapons[weapon1 - 1]) { CG_Printf("Invalid command format for weapon.\n"); return; } else { weapon1 = classinfo->classWeapons[weapon1 - 1]; } } else { weapon1 = classinfo->classWeapons[0]; } if (trap_Argc() > 3) { trap_Argv(3, cls, 64); weapon2 = atoi(cls); weapon2 = CG_GetSecondaryWeapon(weapon2, team, playerclass); } else { weapon2 = CG_GetSecondaryWeapon(-1, team, playerclass); } // Print out the selected class and weapon info if (cgs.clientinfo[cg.clientNum].skill[SK_HEAVY_WEAPONS] >= 4 && playerclass == PC_SOLDIER && !Q_stricmp(weaponTable[weapon1].desc, weaponTable[weapon2].desc)) { CG_PriorityCenterPrint(va(CG_TranslateString("You will spawn as an %s %s with a %s."), teamstring, BG_ClassnameForNumber(playerclass), weaponTable[weapon1].desc), 400, cg_fontScaleCP.value, -1); } else { switch (weapon2) { case WP_AKIMBO_COLT: case WP_AKIMBO_LUGER: case WP_AKIMBO_SILENCEDCOLT: case WP_AKIMBO_SILENCEDLUGER: CG_PriorityCenterPrint(va(CG_TranslateString("You will spawn as an %s %s with a %s and %s."), teamstring, BG_ClassnameForNumber(playerclass), weaponTable[weapon1].desc, weaponTable[weapon2].desc), 400, cg_fontScaleCP.value, -1); break; default: CG_PriorityCenterPrint(va(CG_TranslateString("You will spawn as an %s %s with a %s and a %s."), teamstring, BG_ClassnameForNumber(playerclass), weaponTable[weapon1].desc, weaponTable[weapon2].desc), 400, cg_fontScaleCP.value, -1); break; } } // Send the switch command to the server trap_SendClientCommand(va("team %s %i %i %i\n", classtype, playerclass, weapon1, weapon2)); }
bg_playerclass_t *BG_PlayerClassForPlayerState(playerState_t *ps) { return BG_GetPlayerClassInfo(ps->persistant[PERS_TEAM], ps->stats[STAT_PLAYER_CLASS]); }
bg_playerclass_t *CG_LimboPanel_GetPlayerClass(void) { return BG_GetPlayerClassInfo(CG_LimboPanel_GetTeam(), CG_LimboPanel_GetClass()); }
/* ================== G_SpawnBot ================== */ void G_SpawnBot( const char *text ) { // bot parameters char name[MAX_TOKEN_CHARS] = "wolfBot"; //GS prevent bot health from counting down to 70 (i.e. don't set STAT_MAX_HEALTH = 70) char skill[MAX_TOKEN_CHARS] = "4"; char team[MAX_TOKEN_CHARS] = ""; char pClass[MAX_TOKEN_CHARS] = ""; char pWeapon[MAX_TOKEN_CHARS] = "0"; char spawnPoint[MAX_TOKEN_CHARS] = ""; char respawn[MAX_TOKEN_CHARS] = ""; char scriptName[MAX_TOKEN_CHARS] = "wolfBot"; char characterFile[MAX_TOKEN_CHARS] = ""; // START - Mad Doc - TDF char rank[MAX_TOKEN_CHARS] = ""; char botSkills[MAX_TOKEN_CHARS] = ""; // END Mad Doc - TDF char pow[MAX_TOKEN_CHARS] = "no"; // This is the selection meny index used in SetWolfSpawnWeapons int weaponSpawnNumber = -1; // parsing vars char *token, *pStr, *old_pStr; char cmd[MAX_TOKEN_CHARS], last_cmd[MAX_TOKEN_CHARS]; char cmd_var[MAX_TOKEN_CHARS]; char string[MAX_TOKEN_CHARS]; int j, pClassInt; int characterInt, rankNum; int skills[SK_NUM_SKILLS]; qboolean prisonerOfWar; int teamNum; // parameters spawnBotCommand_t params[] = { {"/name", name, qfalse, "[name]"}, {"/skill", skill, qfalse, "[0-4]"}, {"/team", team, qfalse, "[AXIS/ALLIES]"}, {"/class", pClass, qfalse, "[SOLDIER/MEDIC/LIEUTENANT/ENGINEER/COVERTOPS/FIELDOPS]"}, // FIXME: remove LIEUTENANT from missionpack {"/weapon", pWeapon, qfalse, "[weaponValue]"}, {"/spawnpoint", spawnPoint, qtrue, "[targetname]"}, {"/respawn", respawn, qfalse, "[ON/OFF]"}, {"/scriptName", scriptName, qfalse, "[scriptName]"}, {"/character", characterFile, qfalse, "[character]"}, // START Mad Doc - TDF {"/rank", rank, qfalse, "[rank]"}, {"/skills", botSkills, qfalse, "[botskills]"}, // not really to be exposed to script // END Mad Doc - TDF {"/pow", pow, qfalse, "[yes/no]"}, {NULL} }; // special tables typedef struct { char *weapon; int index; } spawnBotWeapons_t; // TAT 1/16/2003 - uninit'ed data here - getting crazy data for the skills memset(&skills, 0, sizeof(skills)); // // parse the vars pStr = (char *)text; token = COM_Parse( &pStr ); Q_strncpyz( cmd, token, sizeof(cmd) ); // if this is a question mark, show help info if (!Q_stricmp( cmd, "?" ) || !Q_stricmp( cmd, "/?" )) { G_Printf( "Spawns a bot into the game, with the given parameters.\n\nSPAWNBOT [/param [value]] [/param [value]] ...\n\n where [/param [value]] may consist of:\n\n" ); for (j=0; params[j].cmd; j++) { G_Printf( " %s %s\n", params[j].cmd, params[j].help ); } return; } // // intitializations for (j=0; params[j].cmd; j++) { params[j].count = 0; } memset( last_cmd, 0, sizeof(last_cmd) ); pStr = (char *)text; // // parse each command while (cmd[0]) { // // build the string up to the next parameter change token = COM_Parse( &pStr ); Q_strncpyz( cmd, token, sizeof(cmd) ); if (!cmd[0]) break; // if we find an "or", then use the last command if (!Q_stricmp( cmd, "or" )) { // use the last command Q_strncpyz( cmd, last_cmd, sizeof(cmd) ); } // // read the parameters memset( string, 0, sizeof(string) ); token = COM_Parse( &pStr ); Q_strncpyz( cmd_var, token, sizeof(cmd_var) ); if (!cmd_var[0]) break; while (qtrue) { Q_strcat( string, sizeof(string), cmd_var ); old_pStr = pStr; token = COM_Parse( &pStr ); Q_strncpyz( cmd_var, token, sizeof(cmd_var) ); if (cmd_var[0] && (cmd_var[0] == '/' || !Q_stricmp( cmd_var, "or" ))) { pStr = old_pStr; break; } if (!cmd_var[0]) break; Q_strcat( string, sizeof(string), " " ); } // // see if this command exists in the parameters table for (j=0; params[j].cmd; j++) { if (!Q_stricmp( params[j].cmd, cmd )) { // found a match, if this field already has an entry, then randomly override it if (!params[j].count || (!params[j].appendParams && ((rand()%(++params[j].count)) == 0))) { Q_strncpyz( params[j].string, string, sizeof(string) ); } else if (params[j].appendParams) { // append this token Q_strcat( params[j].string, sizeof(string), va(" %s", string) ); } params[j].count++; break; } } if (!params[j].cmd) { G_Printf( "G_SpawnBot: unknown parameter: %s\nFor usage info, use \"spawnbot /?\"\n", cmd ); return; } // Q_strncpyz( last_cmd, cmd, sizeof(last_cmd) ); Q_strncpyz( cmd, cmd_var, sizeof(cmd) ); } // if (strlen( pClass )) { pClassInt = 1 + G_ClassForString( pClass ); } else { pClassInt = 0; } if ( !Q_stricmp( team, "red" ) || !Q_stricmp( team, "r" ) || !Q_stricmp( team, "axis" ) ) { teamNum = TEAM_AXIS; } else if ( !Q_stricmp( team, "blue" ) || !Q_stricmp( team, "b" ) || !Q_stricmp( team, "allies" ) ) { teamNum = TEAM_ALLIES; } else { // pick the team with the least number of players teamNum = PickTeam( -1 ); } G_BotParseCharacterParms( characterFile, &characterInt ); // Gordon: 27/11/02 if( *pow && !Q_stricmp(pow, "yes") ) { prisonerOfWar = qtrue; } else { prisonerOfWar = qfalse; } // START Mad Doc - TDF // special case: if "NONE" is specified, treat this differently if (!Q_stricmp(pWeapon, "NONE")) { weaponSpawnNumber = -1; } // END Mad Doc - TDF // START Mad Doctor I changes, 8/17/2002. // If we have a weapon specified, and we have a class specified else if (isdigit(pWeapon[0])) { // Just convert the string to a number weaponSpawnNumber = atoi(pWeapon); } // if (isdigit(pWeapon[0]))... // If we have a weapon specified as a string, and we have a class specified else if (pClassInt > 0) { // Translate the weapon name into a proper weapon index // Get the index for the weapon weaponSpawnNumber = Bot_GetWeaponForClassAndTeam( pClassInt - 1, teamNum, pWeapon ); // Get default weapon if (weaponSpawnNumber == -1) weaponSpawnNumber = BG_GetPlayerClassInfo( teamNum, pClassInt - 1 )->classWeapons[0]; } // if (Q_stricmp(pWeapon[MAX_TOKEN_CHARS], "0")... // Otherwise, no weapon is selected else { // Just use the default weaponSpawnNumber = BG_GetPlayerClassInfo( teamNum, pClassInt - 1 )->classWeapons[0]; } // else... // START Mad Doc - TDF rankNum = atoi(rank); if( rankNum ) { rankNum--; // people like to start with 1 // Gordon: coders are people too :( } if (botSkills[0]) { // parse the skills out int i; char *pString, *token; pString = botSkills; for (i = 0; i < SK_NUM_SKILLS; i++) { token = COM_ParseExt( &pString, qfalse ); skills[i] = atoi(token); } } // {"/botskills", botSkills, qfalse, "[botskills]"}, // not really to be exposed to script // END Mad Doc - TDF G_AddBot( name, atoi(skill), team, spawnPoint, pClassInt, weaponSpawnNumber, characterInt, respawn, scriptName, rankNum, skills, prisonerOfWar ); // END Mad Doctor I changes, 8/17/2002. }
/** * @brief Sends an class setup message. Enables etpro like classscripts */ void CG_Class_f(void) { char cls[64]; const char *classtype, *teamstring; int weapon1, weapon2, playerclass; bg_playerclass_t *classinfo; team_t team; weaponType_t *wt; if (cg.demoPlayback) { return; } team = cgs.clientinfo[cg.clientNum].team; if (team == TEAM_SPECTATOR) { return; } if (trap_Argc() < 2) { CG_Printf("Invalid command format.\n"); return; } switch (team) { case TEAM_AXIS: classtype = "r"; teamstring = "Axis"; break; case TEAM_ALLIES: classtype = "b"; teamstring = "Allies"; break; default: CG_Printf("Invalid team.\n"); return; } trap_Argv(1, cls, 64); if (!Q_stricmp(cls, "s")) { playerclass = PC_SOLDIER; } else if (!Q_stricmp(cls, "m")) { playerclass = PC_MEDIC; } else if (!Q_stricmp(cls, "e")) { playerclass = PC_ENGINEER; } else if (!Q_stricmp(cls, "f")) { playerclass = PC_FIELDOPS; } else if (!Q_stricmp(cls, "c")) { playerclass = PC_COVERTOPS; } else { CG_Printf("Invalid class format.\n"); return; } classinfo = BG_GetPlayerClassInfo(team, playerclass); if (trap_Argc() > 2) { trap_Argv(2, cls, 64); weapon1 = atoi(cls); if (!classinfo->classWeapons[weapon1 - 1]) { CG_Printf("Invalid command format for weapon.\n"); return; } } else { weapon1 = 1; } if (cgs.clientinfo[cg.clientNum].skill[SK_HEAVY_WEAPONS] >= 4 && playerclass == PC_SOLDIER) { weapon2 = (team == TEAM_AXIS) ? WP_MP40 : WP_THOMPSON; } else if (cgs.clientinfo[cg.clientNum].skill[SK_LIGHT_WEAPONS] >= 4) { if (playerclass == PC_COVERTOPS) { weapon2 = (team == TEAM_AXIS) ? WP_AKIMBO_SILENCEDLUGER : WP_AKIMBO_SILENCEDCOLT; } else { weapon2 = (team == TEAM_AXIS) ? WP_AKIMBO_LUGER : WP_AKIMBO_COLT; } } else { if (playerclass == PC_COVERTOPS) { weapon2 = (team == TEAM_AXIS) ? WP_SILENCER : WP_SILENCED_COLT; } else { weapon2 = (team == TEAM_AXIS) ? WP_LUGER : WP_COLT; } } // Print out the selected class and weapon info wt = WM_FindWeaponTypeForWeapon(classinfo->classWeapons[weapon1 - 1]); CG_PriorityCenterPrint(va(CG_TranslateString("You will spawn as a %s %s with a %s."), teamstring, BG_ClassnameForNumber(playerclass), wt ? wt->desc : "^1UNKNOWN WEAPON"), SCREEN_HEIGHT - 88, SMALLCHAR_WIDTH, -1); // Send the switch command to the server trap_SendClientCommand(va("team %s %i %i %i\n", classtype, playerclass, classinfo->classWeapons[weapon1 - 1], weapon2)); }