/** * @brief Responds with teaminfo such as free team num * @sa CL_ParseTeamInfoMessage */ static void SVC_TeamInfo (struct net_stream *s) { client_t *cl; dbuffer msg; char infoGlobal[MAX_INFO_STRING] = ""; NET_WriteByte(&msg, clc_oob); NET_WriteRawString(&msg, "teaminfo\n"); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam")); NET_WriteString(&msg, infoGlobal); cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { if (cl->state >= cs_connected) { char infoPlayer[MAX_INFO_STRING] = ""; /* show players that already have a team with their teamnum */ int teamId = svs.ge->ClientGetTeamNum(cl->player); if (!teamId) teamId = TEAM_NO_ACTIVE; Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId); Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player)); Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name); NET_WriteString(&msg, infoPlayer); } } NET_WriteByte(&msg, 0); NET_WriteMsg(s, msg); }
/** * @brief Plays the music file given via commandline parameter */ static void M_Play_f (void) { if (Cmd_Argc() == 2) Cvar_Set("snd_music", "%s", Cmd_Argv(1)); M_Start(Cvar_GetString("snd_music")); }
/** * @brief Changed the given cvar to the next/prev equipment definition */ static void GAME_SK_ChangeEquip_f (void) { const equipDef_t *ed; int index; const char *cvarName; if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <cvarname>\n", Cmd_Argv(0)); return; } cvarName = Cmd_Argv(1); ed = INV_GetEquipmentDefinitionByID(Cvar_GetString(cvarName)); index = ed - csi.eds; if (Q_streq(Cmd_Argv(0), "sk_prevequip")) { index--; if (index < 0) index = csi.numEDs - 1; Cvar_Set(cvarName, csi.eds[index].name); } else { index++; if (index >= csi.numEDs) index = 0; Cvar_Set(cvarName, csi.eds[index].name); } }
/* * Svc_Info * * Responds with short info for broadcast scans. */ static void Svc_Info(void) { char string[MAX_MSG_SIZE]; int i, count; int prot; if (sv_max_clients->integer == 1) return; // ignore in single player prot = atoi(Cmd_Argv(1)); if (prot != PROTOCOL) snprintf(string, sizeof(string), "%s: wrong protocol version\n", sv_hostname->string); else { count = 0; for (i = 0; i < sv_max_clients->integer; i++) { if (svs.clients[i].state >= SV_CLIENT_CONNECTED) count++; } snprintf(string, sizeof(string), "%-63s\\%-31s\\%-31s\\%d\\%d", sv_hostname->string, sv.name, Cvar_GetString("g_gameplay"), count, sv_max_clients->integer); } Netchan_OutOfBandPrint(NS_SERVER, net_from, "info\n%s", string); }
/** * @brief Opens the UFOpedia for the current selected item/aircraft. * @note called by market_openpedia */ static void BS_MarketInfoClick_f (void) { const technology_t *tech = RS_GetTechByProvided(Cvar_GetString("mn_item")); if (tech) UP_OpenWith(tech->id); }
/* * Sv_New_f * * Sends the first message from the server to a connected client. * This will be sent on the initial connection and upon each server load. */ static void Sv_New_f(void) { int player_num; Com_Debug("New() from %s\n", Sv_NetaddrToString(sv_client)); if (sv_client->state != SV_CLIENT_CONNECTED) { Com_Warn("Sv_New_f: %s already spawned\n", Sv_NetaddrToString(sv_client)); return; } // demo servers will send the demo file's server info packet if (sv.state == SV_ACTIVE_DEMO) { return; } // send the server data Msg_WriteByte(&sv_client->netchan.message, SV_CMD_SERVER_DATA); Msg_WriteLong(&sv_client->netchan.message, PROTOCOL); Msg_WriteLong(&sv_client->netchan.message, svs.spawn_count); Msg_WriteLong(&sv_client->netchan.message, svs.frame_rate); Msg_WriteByte(&sv_client->netchan.message, 0); Msg_WriteString(&sv_client->netchan.message, Cvar_GetString("game")); player_num = sv_client - svs.clients; Msg_WriteShort(&sv_client->netchan.message, player_num); // send full level name Msg_WriteString(&sv_client->netchan.message, sv.config_strings[CS_NAME]); // begin fetching config_strings Msg_WriteByte(&sv_client->netchan.message, SV_CMD_CBUF_TEXT); Msg_WriteString(&sv_client->netchan.message, va("config_strings %i 0\n", svs.spawn_count)); }
/** * @brief Add a new command to the script interface * @param[in] cmd_name The name the command is available via script interface * @param[in] function The function pointer * @param[in] desc A usually(?) one-line description of what the cmd does * @sa Cmd_RemoveCommand */ void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc) { cmd_function_t *cmd; unsigned int hash; if (!cmd_name || !cmd_name[0]) return; /* fail if the command is a variable name */ if (Cvar_GetString(cmd_name)[0]) { Com_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name); return; } /* fail if the command already exists */ hash = Com_HashKey(cmd_name, CMD_HASH_SIZE); for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) { if (Q_streq(cmd_name, cmd->name)) { Com_DPrintf(DEBUG_COMMANDS, "Cmd_AddCommand: %s already defined\n", cmd_name); return; } } cmd = (cmd_function_t *)Mem_PoolAlloc(sizeof(*cmd), com_cmdSysPool, 0); cmd->name = cmd_name; cmd->description = desc; cmd->function = function; cmd->completeParam = NULL; HASH_Add(cmd_functions_hash, cmd, hash); cmd->next = cmd_functions; cmd_functions = cmd; }
/** * @brief Updates needed cvar for loading screens * @param[in] mapString The mapstring of the map that is currently loaded * @note If @c mapString is NULL the @c sv_mapname cvar is used * @return The loading/background pic path */ static const image_t* SCR_SetLoadingBackground (const char *mapString) { const char *mapname; image_t* image; if (!mapString || Com_ServerState()) mapname = Cvar_GetString("sv_mapname"); else { mapname = mapString; Cvar_Set("sv_mapname", mapString); } /* we will try to load the random map shots by just removing the + from the beginning */ if (mapname[0] == '+') mapname++; image = R_FindImage(va("pics/maps/loading/%s", mapname), it_worldrelated); if (image == r_noTexture) image = R_FindImage("pics/maps/loading/default", it_pic); /* strip away the pics/ part */ Cvar_Set("mn_mappicbig", image->name + 5); return image; }
/** * @brief Responds with teaminfo such as free team num * @sa CL_ParseTeamInfoMessage */ static void SVC_TeamInfo (struct net_stream* s) { if (SVC_RateLimitAddress(*s)) { Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s)); return; } /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */ if (SVC_RateLimit(&outboundLeakyBucket)) { Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit exceeded, dropping request\n"); return; } char infoGlobal[MAX_INFO_STRING] = ""; Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam")); dbuffer msg; NET_WriteByte(&msg, svc_oob); NET_WriteRawString(&msg, "teaminfo\n"); NET_WriteString(&msg, infoGlobal); client_t* cl = nullptr; while ((cl = SV_GetNextClient(cl)) != nullptr) { if (cl->state < cs_connected) continue; char infoPlayer[MAX_INFO_STRING] = ""; /* show players that already have a team with their teamnum */ int teamId = svs.ge->ClientGetTeamNum(*cl->player); if (!teamId) teamId = TEAM_NO_ACTIVE; Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId); Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player)); Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name); NET_WriteString(&msg, infoPlayer); } NET_WriteByte(&msg, 0); NET_WriteMsg(s, msg); }
/** * @brief Allows copying variables * Available via console command copy */ static void Cvar_Copy_f (void) { int c; c = Cmd_Argc(); if (c < 3) { Com_Printf("Usage: %s <target> <source>\n", Cmd_Argv(0)); return; } Cvar_Set(Cmd_Argv(1), "%s", Cvar_GetString(Cmd_Argv(2))); }
const char* GAME_GetTeamDef (void) { const char *teamDefID; const cgame_export_t *list = GAME_GetCurrentType(); if (list && list->GetTeamDef) return list->GetTeamDef(); teamDefID = Cvar_GetString("cl_teamdef"); if (teamDefID[0] == '\0') teamDefID = "phalanx"; return teamDefID; }
void LoadPics(void) { char buffer[256]; char conchars_name[256]; //main bar (add cvars later) Cvar_GetString("gl_consolefont", buffer, sizeof(buffer)); snprintf(conchars_name, sizeof(conchars_name), "textures/charsets/%s", buffer); if (*buffer) con_chars = Draw_LoadImage(conchars_name, false); else con_chars = Draw_LoadImage("textures/charsets/povo5", false); }
int Plug_ExecuteCommand(int *args) { char cmd[256]; Cmd_Argv(0, cmd, sizeof(cmd)); if (!strcmp("namemaker", cmd)) { Menu_Control(1); Cvar_GetString("name", (char*)namebuffer, sizeof(namebuffer)); LoadPics(); insertpos = strlen(namebuffer); return 1; } return 0; }
/** * @brief Take a screen shot of the map with the position of the radar * * We add 1 pixel into the border to easy check the result: * the screen shot must have a border of 1 black pixel */ static void CL_BattlescapeRadarGenerate_f (void) { const int border = 0; const char* mapName = Cvar_GetString("sv_mapname"); const int level = Cvar_GetInteger("cl_worldlevel"); const char* filename = nullptr; int x, y, width, height; CL_BattlescapeRadarMapInFrameBuffer(&x, &y, &width, &height); if (mapName) filename = va("%s_%i", mapName, level + 1); R_ScreenShot(x - border, y - border, width + border * 2, height + border * 2, filename, nullptr); }
/** * @brief Parses the given string into command line tokens. * @note @c cmd_argv and @c cmd_argv are filled and set here * @note *cvars will be expanded unless they are in a quoted token * @sa Com_MacroExpandString * @param[in] text The text to parse and tokenize * @param[in] macroExpand expand cvar string with their values */ void Cmd_TokenizeString (const char *text, qboolean macroExpand) { const char *com_token, *expanded; Cmd_BufClear(); /* macro expand the text */ if (macroExpand) { expanded = Com_MacroExpandString(text); if (expanded) text = expanded; } while (1) { /* skip whitespace up to a newline */ while (*text && *text <= ' ' && *text != '\n') { text++; } if (*text == '\n') { /* a newline seperates commands in the buffer */ text++; break; } if (!*text) return; /* set cmd_args to everything after the first arg */ if (cmd_argc == 1) { Q_strncpyz(cmd_args, text, sizeof(cmd_args)); Com_Chop(cmd_args); } com_token = Com_Parse(&text); if (!text) return; if (cmd_argc < MAX_STRING_TOKENS) { /* check first char of string if it is a variable */ if (com_token[0] == '*') { com_token++; com_token = Cvar_GetString(com_token); } assert(!cmd_argv[cmd_argc]); cmd_argv[cmd_argc] = Mem_PoolStrDup(com_token, com_cmdSysPool, 0); cmd_argc++; } } }
/** * @brief Starts a new skirmish game */ static void GAME_SK_Start_f (void) { char map[MAX_VAR]; mapDef_t *md; if (!chrDisplayList.num) { unsigned int i; /** @todo make the teamdef configurable */ const char *ugvTeamDefID = "phalanx_ugv_phoenix"; const char *name = Cvar_GetString("cl_equip"); const equipDef_t *ed = INV_GetEquipmentDefinitionByID(name); const size_t size = GAME_GetCharacterArraySize(); uint32_t maxSoldiers = Cvar_GetInteger("sv_maxsoldiersperplayer"); uint32_t ugvs = Cvar_GetInteger("cl_ugvs"); if (maxSoldiers <= 0) maxSoldiers = size; ugvs = min(ugvs, size - maxSoldiers); Com_Printf("Starting skirmish with %i soldiers and %i ugvs\n", maxSoldiers, ugvs); GAME_AutoTeam(name, maxSoldiers); for (i = 0; i < ugvs; i++) GAME_AppendTeamMember(i + maxSoldiers, ugvTeamDefID, ed); } else { Com_Printf("Using already loaded team with %i members\n", chrDisplayList.num); } assert(cls.currentSelectedMap >= 0); assert(cls.currentSelectedMap < MAX_MAPDEFS); md = Com_GetMapDefByIDX(cls.currentSelectedMap); if (!md) return; GAME_SK_SetMissionParameters(md); assert(md->map); Com_sprintf(map, sizeof(map), "map %s %s %s;", Cvar_GetInteger("mn_serverday") ? "day" : "night", md->map, md->param ? md->param : ""); /* prepare */ UI_InitStack(NULL, "singleplayermission", qtrue, qfalse); Cbuf_AddText(map); }
// handler of ExecuteCommand event int Plug_ExecuteCommand(int *args) { char cmd[256]; Cmd_Argv(0, cmd, sizeof(cmd)); if (!strcmp("dummyplugin_cmd", cmd)) { char buf[100]; Con_Printf("This is dummy plugin talking.\n"); if (Cvar_GetString("dummyplugin_cvar", buf, sizeof(buf))) { Con_Printf("dummyplugin_cvar value is: '%s'", buf); } else { Con_Printf("Something went wrong, cannot find dummyplugin_cvar\n"); } return 1; } return 0; }
/** * Updates the material editor node for a given image and a given material stage * @param image The image to load into the material editor * @param materialStage The material stage to display */ static void UI_MaterialEditorUpdate (image_t *image, materialStage_t *materialStage) { linkedList_t *materialStagesList = NULL; if (image->normalmap == NULL) UI_ExecuteConfunc("hideshaders true 0 0 0 0"); else UI_ExecuteConfunc("hideshaders false %f %f %f %f", image->material.bump, image->material.hardness, image->material.parallax, image->material.specular); if (image->normalmap == NULL) Cvar_Set("me_imagename", image->name); else Cvar_Set("me_imagename", va("%s (nm)", image->name)); if (!image->material.num_stages) { UI_ExecuteConfunc("hidestages true"); } else { int i; if (materialStage) { const char *stageType = Cvar_GetString("me_stagetype"); if (stageType[0] == '\0') stageType = "stretch"; UI_ExecuteConfunc("hidestages false %s", stageType); } else Cvar_Set("me_stage_id", "-1"); for (i = 0; i < image->material.num_stages; i++) { const materialStage_t *stage = UI_MaterialEditorGetStage(&image->material, i); char stageName[MAX_VAR] = "stage "; if (stage == materialStage) { UI_ExecuteConfunc("updatestagevalues %f %f %f %f %f %f %f %f %f %f %f %f %f %f", stage->rotate.hz, stage->rotate.deg, stage->stretch.hz, stage->stretch.dhz, stage->stretch.amp, stage->stretch.damp, stage->pulse.hz, stage->pulse.dhz, stage->scroll.ds, stage->scroll.dt, stage->scroll.s, stage->scroll.t, stage->scale.s, stage->scale.t); } UI_MaterialEditorStagesToName(stage, stageName, sizeof(stageName) - 1); LIST_AddString(&materialStagesList, stageName); } } UI_RegisterLinkedListText(TEXT_MATERIAL_STAGES, materialStagesList); }
/* * @brief */ static void Cl_ParseServerData(void) { char *str; int32_t i; // wipe the cl_client_t struct Cl_ClearState(); cls.state = CL_CONNECTED; cls.key_state.dest = KEY_CONSOLE; // parse protocol version number i = Net_ReadLong(&net_message); // ensure protocol matches if (i != PROTOCOL) { Com_Error(ERR_DROP, "Server is using unknown protocol %d\n", i); } // retrieve spawn count and packet rate cl.server_count = Net_ReadLong(&net_message); cl.server_hz = Net_ReadLong(&net_message); // determine if we're viewing a demo cl.demo_server = Net_ReadByte(&net_message); // game directory str = Net_ReadString(&net_message); if (g_strcmp0(Cvar_GetString("game"), str)) { Fs_SetGame(str); // reload the client game Cl_InitCgame(); } // parse player entity number cl.entity_num = Net_ReadShort(&net_message); // get the full level name str = Net_ReadString(&net_message); Com_Print("\n"); Com_Print("%c%s\n", 2, str); }
/** * @brief */ static void Cl_ParseServerData(void) { // wipe the cl_client_t struct Cl_ClearState(); Cl_SetKeyDest(KEY_CONSOLE); // parse protocol version number const uint16_t major = Net_ReadShort(&net_message); const uint16_t minor = Net_ReadShort(&net_message); // ensure protocol major matches if (major != PROTOCOL_MAJOR) { Com_Error(ERROR_DROP, "Server is using protocol major %d\n", major); } // determine if we're viewing a demo cl.demo_server = Net_ReadByte(&net_message); // game directory char *str = Net_ReadString(&net_message); if (g_strcmp0(Cvar_GetString("game"), str)) { Fs_SetGame(str); // reload the client game Cl_InitCgame(); } // ensure protocol minor matches if (minor != cls.cgame->protocol) { Com_Error(ERROR_DROP, "Server is using protocol minor %d\n", minor); } // parse client slot number, which is our entity number + 1 cl.client_num = Net_ReadShort(&net_message); // get the full level name str = Net_ReadString(&net_message); Com_Print("\n"); Com_Print("^2%s^7\n", str); }
/** * @sa CP_StartMissionMap */ static void R_ModLoadTexinfo (const lump_t *l) { const dBspTexinfo_t *in; int i, j, count; char name[MAX_QPATH]; in = (const dBspTexinfo_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadTexinfo: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspTexInfo_t* out = Mem_PoolAllocTypeN(mBspTexInfo_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...texinfo: %i\n", count); r_worldmodel->bsp.texinfo = out; r_worldmodel->bsp.numtexinfo = count; const char *mapZone = Cvar_GetString("sv_mapzone"); for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { out->uv[j] = LittleFloat(in->vecs[0][j]); out->vv[j] = LittleFloat(in->vecs[1][j]); } out->u_offset = LittleFloat(in->vecs[0][3]); out->v_offset = LittleFloat(in->vecs[1][3]); out->flags = LittleLong(in->surfaceFlags); /* exchange the textures with the ones that are needed for base assembly */ if (mapZone && strstr(in->texture, "tex_terrain/dummy")) Com_sprintf(name, sizeof(name), "textures/tex_terrain/%s", mapZone); else Com_sprintf(name, sizeof(name), "textures/%s", in->texture); out->image = R_FindImage(name, it_world); } }
/** * @brief Responses to broadcasts, etc * @sa CL_ReadPackets * @sa CL_Frame * @sa SVC_DirectConnect * @param[in,out] msg The client stream message buffer to read from */ static void CL_ConnectionlessPacket (dbuffer* msg) { char s[512]; NET_ReadStringLine(msg, s, sizeof(s)); Cmd_TokenizeString(s, false); const char* c = Cmd_Argv(0); Com_DPrintf(DEBUG_CLIENT, "server OOB: %s (%s)\n", c, Cmd_Args()); /* server connection */ if (Q_streq(c, CL_CMD_CLIENT_CONNECT)) { int i; for (i = 1; i < Cmd_Argc(); i++) { if (char const* const p = Q_strstart(Cmd_Argv(i), "dlserver=")) { Com_sprintf(cls.downloadReferer, sizeof(cls.downloadReferer), "ufo://%s", cls.servername); CL_SetHTTPServer(p); if (cls.downloadServer[0]) Com_Printf("HTTP downloading enabled, URL: %s\n", cls.downloadServer); } } if (cls.state == ca_connected) { Com_Printf("Dup connect received. Ignored.\n"); return; } dbuffer buf(5); NET_WriteByte(&buf, clc_stringcmd); NET_WriteString(&buf, NET_STATE_NEW "\n"); NET_WriteMsg(cls.netStream, buf); GAME_InitMissionBriefing(_("Loading")); return; } /* remote command from gui front end */ if (Q_streq(c, CL_CMD_COMMAND)) { if (!NET_StreamIsLoopback(cls.netStream)) { Com_Printf("Command packet from remote host. Ignored.\n"); return; } else { char str[512]; NET_ReadString(msg, str, sizeof(str)); Cbuf_AddText("%s\n", str); } return; } /* ping from server */ if (Q_streq(c, CL_CMD_PING)) { NET_OOB_Printf(cls.netStream, SV_CMD_ACK); return; } /* echo request from server */ if (Q_streq(c, CL_CMD_ECHO)) { NET_OOB_Printf(cls.netStream, "%s", Cmd_Argv(1)); return; } /* print */ if (Q_streq(c, SV_CMD_PRINT)) { NET_ReadString(msg, popupText, sizeof(popupText)); /* special reject messages needs proper handling */ if (strstr(popupText, REJ_PASSWORD_REQUIRED_OR_INCORRECT)) { UI_PushWindow("serverpassword"); if (Q_strvalid(Cvar_GetString("password"))) { Cvar_Set("password", ""); CL_Drop(); UI_Popup(_("Connection failure"), _("The password you specified was wrong.")); } else { CL_Drop(); UI_Popup(_("Connection failure"), _("This server requires a password.")); } } else if (strstr(popupText, REJ_SERVER_FULL)) { CL_Drop(); UI_Popup(_("Connection failure"), _("This server is full.")); } else if (strstr(popupText, REJ_BANNED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("You are banned on this server.")); } else if (strstr(popupText, REJ_GAME_ALREADY_STARTED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The game has already started.")); } else if (strstr(popupText, REJ_SERVER_VERSION_MISMATCH)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The server is running a different version of the game.")); } else if (strstr(popupText, BAD_RCON_PASSWORD)) { Cvar_Set("rcon_password", ""); UI_Popup(_("Bad rcon password"), _("The rcon password you specified was wrong.")); } else if (strstr(popupText, REJ_CONNECTION_REFUSED)) { CL_Drop(); UI_Popup(_("Connection failure"), _("The server refused the connection.")); } else if (Q_strvalid(popupText)) { UI_Popup(_("Notice"), _(popupText)); } return; } if (!GAME_HandleServerCommand(c, msg)) Com_Printf("Unknown command received \"%s\"\n", c); }
/** * @brief Update the item description according to the tech and the slot selected */ static void AIM_UpdateItemDescription (bool fromList, bool fromSlot) { int status; aircraft_t *aircraft; aircraftSlot_t *slot; base_t *base = B_GetCurrentSelectedBase(); assert(base); aircraft = base->aircraftCurrent; assert(aircraft); slot = AII_SelectAircraftSlot(aircraft, airequipID); /* update mini ufopedia */ /** @todo we should clone the text, and not using the ufopedia text */ if (fromList) UP_AircraftItemDescription(INVSH_GetItemByIDSilent(aimSelectedTechnology ? aimSelectedTechnology->provides : NULL)); else if (fromSlot) { if (airequipID == AC_ITEM_AMMO) UP_AircraftItemDescription(slot->ammo); else UP_AircraftItemDescription(slot->item); } /* update status */ status = AIM_CheckTechnologyIntoSlot(slot, aimSelectedTechnology); switch (status) { case AIM_LOADING_NOSLOTSELECTED: Cvar_Set("mn_aircraft_item_warning", _("No slot selected.")); break; case AIM_LOADING_NOTECHNOLOGYSELECTED: Cvar_Set("mn_aircraft_item_warning", _("No item selected.")); break; case AIM_LOADING_ALIENTECH: Cvar_Set("mn_aircraft_item_warning", _("You can't equip an alien technology.")); break; case AIM_LOADING_TECHNOLOGYNOTRESEARCHED: Cvar_Set("mn_aircraft_item_warning", _("Technology requested is not yet completed.")); break; case AIM_LOADING_TOOHEAVY: Cvar_Set("mn_aircraft_item_warning", _("This item is too heavy for the selected slot.")); break; case AIM_LOADING_NOWEAPON: Cvar_Set("mn_aircraft_item_warning", _("Equip a weapon first.")); break; case AIM_LOADING_NOTUSABLEWITHWEAPON: Cvar_Set("mn_aircraft_item_warning", _("Ammo not usable with current weapon.")); break; case AIM_LOADING_UNKNOWNPROBLEM: Cvar_Set("mn_aircraft_item_warning", _("Unknown problem.")); break; case AIM_LOADING_OK: Cvar_Set("mn_aircraft_item_warning", _("Ok")); break; } if (*Cvar_GetString("mn_item") == '\0') { cgi->UI_ExecuteConfunc("airequip_no_item"); } else { if (fromSlot) { cgi->UI_ExecuteConfunc("airequip_installed_item"); } else { if (status == AIM_LOADING_OK) cgi->UI_ExecuteConfunc("airequip_installable_item"); else cgi->UI_ExecuteConfunc("airequip_noinstallable_item"); } } }
/** * @brief Expands strings with cvar values that are dereferenced by a '*cvar' * @note There is an overflow check for cvars that also contain a '*cvar' * @sa Cmd_TokenizeString * @sa UI_GetReferenceString */ const char* Com_MacroExpandString (const char* text) { static char expanded[MAX_STRING_CHARS]; const char* scan = text; if (!text || !*text) return nullptr; int len = strlen(scan); if (len >= MAX_STRING_CHARS) { Com_Printf("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS); return nullptr; } bool inquote = false; int count = 0; OBJZERO(expanded); char* pos = expanded; /* also the \0 */ assert(scan[len] == '\0'); for (int i = 0; i <= len; i++) { const char* token, *start, *cvarvalue; if (scan[i] == '"') inquote ^= 1; /* don't expand inside quotes */ if (inquote || strncmp(&scan[i], "*cvar:", MACRO_CVAR_ID_LENGTH)) { *pos++ = scan[i]; continue; } /* scan out the complete macro and only parse the cvar name */ start = &scan[i + MACRO_CVAR_ID_LENGTH]; token = Com_Parse(&start); if (!start) continue; /* skip the macro and the cvar name in the next loop */ i += MACRO_CVAR_ID_LENGTH; i += strlen(token); i--; /* get the cvar value */ cvarvalue = Cvar_GetString(token); if (!cvarvalue) { Com_Printf("Could not get cvar value for cvar: %s\n", token); return nullptr; } int j = strlen(cvarvalue); if (strlen(pos) + j >= MAX_STRING_CHARS) { Com_Printf("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS); return nullptr; } /* copy the cvar value into the target buffer */ /* check for overflow is already done - so MAX_STRING_CHARS won't hurt here */ Q_strncpyz(pos, cvarvalue, j + 1); pos += j; if (++count == 100) { Com_Printf("Macro expansion loop, discarded.\n"); return nullptr; } } if (inquote) { Com_Printf("Line has unmatched quote, discarded.\n"); return nullptr; } if (count) return expanded; return nullptr; }
/** * @brief Writes server_data, config_strings, and baselines once a non-delta * compressed frame arrives from the server. */ static void Cl_WriteDemoHeader(void) { static entity_state_t null_state; mem_buf_t msg; byte buffer[MAX_MSG_SIZE]; // write out messages to hold the startup information Mem_InitBuffer(&msg, buffer, sizeof(buffer)); // write the server data Net_WriteByte(&msg, SV_CMD_SERVER_DATA); Net_WriteShort(&msg, PROTOCOL_MAJOR); Net_WriteShort(&msg, cls.cgame->protocol); Net_WriteByte(&msg, 1); // demo_server byte Net_WriteString(&msg, Cvar_GetString("game")); Net_WriteShort(&msg, cl.client_num); Net_WriteString(&msg, cl.config_strings[CS_NAME]); // and config_strings for (int32_t i = 0; i < MAX_CONFIG_STRINGS; i++) { if (*cl.config_strings[i] != '\0') { if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); msg.size = 0; } Net_WriteByte(&msg, SV_CMD_CONFIG_STRING); Net_WriteShort(&msg, i); Net_WriteString(&msg, cl.config_strings[i]); } } // and baselines for (size_t i = 0; i < lengthof(cl.entities); i++) { entity_state_t *ent = &cl.entities[i].baseline; if (!ent->number) { continue; } if (msg.size + 64 > msg.max_size) { // write it out const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); msg.size = 0; } Net_WriteByte(&msg, SV_CMD_BASELINE); Net_WriteDeltaEntity(&msg, &null_state, &cl.entities[i].baseline, true); } Net_WriteByte(&msg, SV_CMD_CBUF_TEXT); Net_WriteString(&msg, "precache 0\n"); // write it to the demo file const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); Com_Debug(DEBUG_CLIENT, "Demo started\n"); // the rest of the demo file will be individual frames }
/** * @brief Change the server to a new map, taking all connected clients along with it. * @note the full syntax is: @code map [day|night] [+]<map> [<assembly>] @endcode * @sa SV_AssembleMap * @sa CM_LoadMap * @sa Com_SetServerState */ void SV_Map (bool day, const char* levelstring, const char* assembly) { int i; unsigned checksum = 0; char* map = SV_GetConfigString(CS_TILES); char* pos = SV_GetConfigString(CS_POSITIONS); char* entityString = SV_GetConfigString(CS_ENTITYSTRING); MapInfo* randomMap = nullptr; client_t* cl; /* any partially connected client will be restarted */ Com_SetServerState(ss_restart); /* the game is just starting */ SV_InitGame(); if (!svs.initialized) { Com_Printf("Could not spawn the server\n"); return; } assert(Q_strvalid(levelstring)); Com_DPrintf(DEBUG_SERVER, "SpawnServer: %s\n", levelstring); /* save name for levels that don't set message */ SV_SetConfigString(CS_NAME, levelstring); SV_SetConfigString(CS_LIGHTMAP, day); SV_SetConfigString(CS_MAPZONE, Cvar_GetString("sv_mapzone")); Q_strncpyz(sv->name, levelstring, sizeof(sv->name)); /* set serverinfo variable */ sv_mapname = Cvar_FullSet("sv_mapname", sv->name, CVAR_SERVERINFO | CVAR_NOSET); /* notify the client in case of a listening server */ SCR_BeginLoadingPlaque(); if (assembly) Q_strncpyz(sv->assembly, assembly, sizeof(sv->assembly)); else sv->assembly[0] = '\0'; /* leave slots at start for clients only */ cl = nullptr; while ((cl = SV_GetNextClient(cl)) != nullptr) { /* needs to reconnect */ if (cl->state >= cs_spawning) SV_SetClientState(cl, cs_connected); } /* assemble and load the map */ if (levelstring[0] == '+') { randomMap = SV_AssembleMap(levelstring + 1, assembly, map, pos, entityString, 0, true); if (!randomMap) { Com_Printf("Could not load assembly for map '%s'\n", levelstring); return; } } else { SV_SetConfigString(CS_TILES, levelstring); SV_SetConfigString(CS_POSITIONS, assembly ? assembly : ""); SV_SetConfigString(CS_ENTITYSTRING, ""); } CM_LoadMap(map, day, pos, entityString, &sv->mapData, &sv->mapTiles); Com_Printf("checksum for the map '%s': %u\n", levelstring, sv->mapData.mapChecksum); SV_SetConfigString(CS_MAPCHECKSUM, sv->mapData.mapChecksum); checksum = Com_GetScriptChecksum(); Com_Printf("ufo script checksum %u\n", checksum); SV_SetConfigString(CS_UFOCHECKSUM, checksum); SV_SetConfigString(CS_OBJECTAMOUNT, csi.numODs); SV_SetConfigString(CS_VERSION, UFO_VERSION); SV_SetConfigString(CS_MAPTITLE, SV_GetMapTitle(randomMap, levelstring)); if (Q_strstart(SV_GetConfigString(CS_MAPTITLE), "b/")) { /* For base attack, CS_MAPTITLE contains too many chars */ SV_SetConfigString(CS_MAPTITLE, "Base attack"); SV_SetConfigString(CS_NAME, ".baseattack"); } /* clear random-map assembly data */ Mem_Free(randomMap); randomMap = nullptr; /* clear physics interaction links */ SV_ClearWorld(); /* fix this! */ for (i = 1; i <= sv->mapData.numInline; i++) sv->models[i] = CM_InlineModel(&sv->mapTiles, va("*%i", i)); /* precache and static commands can be issued during map initialization */ Com_SetServerState(ss_loading); /* load and spawn all other entities */ { const ScopedMutex scopedMutex(svs.serverMutex); svs.ge->SpawnEntities(sv->name, SV_GetConfigStringInteger(CS_LIGHTMAP), sv->mapData.mapEntityString); } /* all precaches are complete */ Com_SetServerState(ss_game); Com_Printf("-------------------------------------\n"); Cbuf_CopyToDefer(); }
/* * Cl_WriteDemoHeader * * Writes server_data, config_strings, and baselines once a non-delta * compressed frame arrives from the server. */ static void Cl_WriteDemoHeader(void) { byte buffer[MAX_MSG_SIZE]; size_buf_t msg; int i; int len; entity_state_t null_state; // write out messages to hold the startup information Sb_Init(&msg, buffer, sizeof(buffer)); // write the server data Msg_WriteByte(&msg, SV_CMD_SERVER_DATA); Msg_WriteLong(&msg, PROTOCOL); Msg_WriteLong(&msg, cl.server_count); Msg_WriteLong(&msg, cl.server_frame_rate); Msg_WriteByte(&msg, 1); // demo_server byte Msg_WriteString(&msg, Cvar_GetString("game")); Msg_WriteShort(&msg, cl.player_num); Msg_WriteString(&msg, cl.config_strings[CS_NAME]); // and config_strings for (i = 0; i < MAX_CONFIG_STRINGS; i++) { if (*cl.config_strings[i] != '\0') { if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out len = LittleLong(msg.size); Fs_Write(&len, 4, 1, cls.demo_file); Fs_Write(msg.data, msg.size, 1, cls.demo_file); msg.size = 0; } Msg_WriteByte(&msg, SV_CMD_CONFIG_STRING); Msg_WriteShort(&msg, i); Msg_WriteString(&msg, cl.config_strings[i]); } } // and baselines for (i = 0; i < MAX_EDICTS; i++) { entity_state_t *ent = &cl.entities[i].baseline; if (!ent->number) continue; if (msg.size + 64 > msg.max_size) { // write it out len = LittleLong(msg.size); Fs_Write(&len, 4, 1, cls.demo_file); Fs_Write(msg.data, msg.size, 1, cls.demo_file); msg.size = 0; } memset(&null_state, 0, sizeof(null_state)); Msg_WriteByte(&msg, SV_CMD_ENTITY_BASELINE); Msg_WriteDeltaEntity(&null_state, &cl.entities[i].baseline, &msg, true, true); } Msg_WriteByte(&msg, SV_CMD_CBUF_TEXT); Msg_WriteString(&msg, "precache 0\n"); // write it to the demo file len = LittleLong(msg.size); Fs_Write(&len, 4, 1, cls.demo_file); Fs_Write(msg.data, msg.size, 1, cls.demo_file); Com_Print("Recording to %s.\n", cls.demo_path); // the rest of the demo file will be individual frames }