Exemplo n.º 1
0
/**
 * @brief
 * @sa FinalLightFace
 */
void BuildFacelights (unsigned int facenum)
{
	dBspSurface_t* face;
	dBspPlane_t* plane;
	dBspTexinfo_t* tex;
	float* center;
	float* sdir, *tdir;
	vec3_t normal, binormal;
	vec4_t tangent;
	lightinfo_t li;
	float scale;
	int i, j, numsamples;
	facelight_t* fl;
	int* headhints;
	const int grid_type = config.soft ? 1 : 0;

	if (facenum >= MAX_MAP_FACES) {
		Com_Printf("MAX_MAP_FACES hit\n");
		return;
	}

	face = &curTile->faces[facenum];
	plane = &curTile->planes[face->planenum];
	tex = &curTile->texinfo[face->texinfo];

	if (tex->surfaceFlags & SURF_WARP)
		return;		/* non-lit texture */

	sdir = tex->vecs[0];
	tdir = tex->vecs[1];

	/* lighting -extra antialiasing */
	if (config.extrasamples)
		numsamples = config.soft ? SOFT_SAMPLES : MAX_SAMPLES;
	else
		numsamples = 1;

	OBJZERO(li);

	scale = 1.0 / numsamples; /* each sample contributes this much */

	li.face = face;
	li.facedist = plane->dist;
	VectorCopy(plane->normal, li.facenormal);
	/* negate the normal and dist */
	if (face->side) {
		VectorNegate(li.facenormal, li.facenormal);
		li.facedist = -li.facedist;
	}

	/* get the origin offset for rotating bmodels */
	VectorCopy(face_offset[facenum], li.modelorg);

	/* calculate lightmap texture mins and maxs */
	CalcLightinfoExtents(&li);

	/* and the lightmap texture vectors */
	CalcLightinfoVectors(&li);

	/* now generate all of the sample points */
	CalcPoints(&li, 0, 0);

	fl = &facelight[config.compile_for_day][facenum];
	fl->numsamples = li.numsurfpt;
	fl->samples    = Mem_AllocTypeN(vec3_t, fl->numsamples);
	fl->directions = Mem_AllocTypeN(vec3_t, fl->numsamples);

	center = face_extents[facenum].center;  /* center of the face */

	/* Also setup the hints.  Each hint is specific to each light source, including sunlight. */
	headhints = Mem_AllocTypeN(int, (numlights[config.compile_for_day] + 1));

	/* calculate light for each sample */
	for (i = 0; i < fl->numsamples; i++) {
		float* const sample    = fl->samples[i];    /* accumulate lighting here */
		float* const direction = fl->directions[i]; /* accumulate direction here */

		if (tex->surfaceFlags & SURF_PHONG)
			/* interpolated normal */
			SampleNormal(&li, li.surfpt[i], normal);
		else
			/* or just plane normal */
			VectorCopy(li.facenormal, normal);

		for (j = 0; j < numsamples; j++) {  /* with antialiasing */
			vec3_t pos;

			/* add offset for supersampling */
			VectorMA(li.surfpt[i], sampleofs[grid_type][j][0] * li.step, li.textoworld[0], pos);
			VectorMA(pos, sampleofs[grid_type][j][1] * li.step, li.textoworld[1], pos);

			NudgeSamplePosition(pos, normal, center, pos);

			GatherSampleLight(pos, normal, sample, direction, scale, headhints);
		}
		if (VectorNotEmpty(direction)) {
			vec3_t dir;

			/* normalize it */
			VectorNormalize(direction);

			/* finalize the lighting direction for the sample */
			TangentVectors(normal, sdir, tdir, tangent, binormal);

			dir[0] = DotProduct(direction, tangent);
			dir[1] = DotProduct(direction, binormal);
			dir[2] = DotProduct(direction, normal);

			VectorCopy(dir, direction);
		}
	}

	/* Free the hints. */
	Mem_Free(headhints);

	for (i = 0; i < fl->numsamples; i++) {  /* pad them */
		float* const direction = fl->directions[i];
		if (VectorEmpty(direction))
			VectorSet(direction, 0.0, 0.0, 1.0);
	}

	/* free the sample positions for the face */
	Mem_Free(li.surfpt);
}
Exemplo n.º 2
0
void uiWindowNode::clone (const uiNode_t* source, uiNode_t* clone)
{
	/* clean up index */
	EXTRADATA(clone).index = nullptr;
	OBJZERO(EXTRADATA(clone).index_hash);
}
Exemplo n.º 3
0
/**
 * @sa S_Shutdown
 * @sa S_Restart_f
 */
void S_Init (void)
{
    SDL_version version;
    char drivername[MAX_VAR];

    Com_Printf("\n------- sound initialization -------\n");

    OBJZERO(s_env);

    snd_init = Cvar_Get("snd_init", "1", CVAR_ARCHIVE, "Should the sound renderer get initialized");
    snd_init->modified = false; /* don't restart right away */
    Cmd_AddCommand("snd_restart", S_Restart_f, "Restart the sound renderer");

    if (!snd_init->integer) {
        Com_Printf("not initializing.\n");
        Cmd_AddCommand("music_change", Cmd_Dummy_f, "Dummy command if sound is disabled");
        Cvar_Get("snd_music", "PsymongN3", 0, "Background music track");
        return;
    }

    cl_soundSysPool = Mem_CreatePool("Client: Sound system");

    snd_distance_scale = Cvar_Get("snd_distance_scale", "0.1", 0, "Sound distance scale");
    snd_volume = Cvar_Get("snd_volume", "0.7", CVAR_ARCHIVE, "Sound volume - default is 0.7");
    snd_rate = Cvar_Get("snd_rate", "44100", CVAR_ARCHIVE, "Hz value for sound renderer - default is 44100");
    snd_chunkbufsize = Cvar_Get("snd_chunkbufsize", "1024", CVAR_ARCHIVE, "The sound buffer chunk size");
    /* set volumes to be changed so they are applied again for next sound/music playing */
    /** @todo implement the volume change for already loaded sample chunks */
    snd_volume->modified = true;

    Cmd_AddCommand("snd_play", S_Play_f, "Plays a sound fx file. Pass path relative to base/sound without file extension");
    Cmd_AddParamCompleteFunction("snd_play", S_CompleteSounds);

    if (SDL_WasInit(SDL_INIT_AUDIO) == 0) {
        if (SDL_Init(SDL_INIT_AUDIO) < 0) {
            Com_Printf("S_Init: %s.\n", SDL_GetError());
            return;
        }
    }

    MIX_VERSION(&version)
    Com_Printf("SDL_mixer version: %d.%d.%d\n", version.major, version.minor, version.patch);
    Com_Printf("... requested audio rate: %i\n", snd_rate->integer);

    if (Mix_OpenAudio(snd_rate->integer, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, snd_chunkbufsize->integer) == -1) {
        Com_Printf("S_Init: %s\n", Mix_GetError());
        return;
    }

    if (Mix_QuerySpec(&s_env.rate, &s_env.format, &s_env.numChannels) == 0) {
        Com_Printf("S_Init: %s\n", Mix_GetError());
        return;
    }

    if (SDL_AudioDriverName(drivername, sizeof(drivername)) == NULL)
        Q_strncpyz(drivername, "(UNKNOWN)", sizeof(drivername));
    Com_Printf("... driver: '%s'\n", drivername);

    if (Mix_AllocateChannels(MAX_CHANNELS) != MAX_CHANNELS) {
        Com_Printf("S_Init: %s\n", Mix_GetError());
        return;
    }

    Mix_ChannelFinished(S_FreeChannel);

    Com_Printf("... audio rate: %i\n", s_env.rate);
    Com_Printf("... audio channels: %i\n", s_env.numChannels);

#if COMPARE_VERSION(1, 2, 10)
    if (!(Mix_Init(MIX_INIT_OGG) & MIX_INIT_OGG))
        Com_Printf("... could not load ogg vorbis support\n");
    else
        Com_Printf("... loaded ogg vorbis support\n");
#endif

    s_env.initialized = true;

    M_Init();
}
Exemplo n.º 4
0
/**
 * @brief Creates a server's entity / program execution context
 * by parsing textual entity definitions out of an ent file.
 * @sa CM_EntityString
 * @sa SV_SpawnServer
 */
void G_SpawnEntities (const char *mapname, bool day, const char *entities)
{
	int entnum;

	G_FreeTags(TAG_LEVEL);

	OBJZERO(level);
	level.pathingMap = (pathing_t *)G_TagMalloc(sizeof(*level.pathingMap), TAG_LEVEL);

	G_EdictsReset();

	/* initialize reactionFire data */
	G_ReactionFireTargetsInit();

	Q_strncpyz(level.mapname, mapname, sizeof(level.mapname));
	level.day = day;

	G_ResetClientData();

	level.activeTeam = TEAM_NO_ACTIVE;
	level.actualRound = 1;
	level.hurtAliens = sv_hurtaliens->integer;
	ai_waypointList = NULL;

	/* parse ents */
	entnum = 0;
	while (1) {
		edict_t *ent;
		/* parse the opening brace */
		const char *token = Com_Parse(&entities);
		if (!entities)
			break;
		if (token[0] != '{')
			gi.Error("ED_LoadFromFile: found %s when expecting {", token);

		ent = G_Spawn();

		entities = ED_ParseEdict(entities, ent);

		ent->mapNum = entnum++;

		/* Set the position of the entity */
		VecToPos(ent->origin, ent->pos);

		/* Call this entity's specific initializer (sets ent->type) */
		ED_CallSpawn(ent);

		/* if this entity is an bbox (e.g. actor), then center its origin based on its position */
		if (ent->solid == SOLID_BBOX)
			G_EdictCalcOrigin(ent);
	}

	/* spawn ai players, if needed */
	if (level.num_spawnpoints[TEAM_CIVILIAN]) {
		if (AI_CreatePlayer(TEAM_CIVILIAN) == NULL)
			gi.DPrintf("Could not create civilian\n");
	}

	if ((sv_maxclients->integer == 1 || ai_numactors->integer) && level.num_spawnpoints[TEAM_ALIEN]) {
		if (AI_CreatePlayer(TEAM_ALIEN) == NULL)
			gi.DPrintf("Could not create alien\n");
	}

	Com_Printf("Used inventory slots after ai spawn: %i\n", game.i.GetUsedSlots(&game.i));

	G_FindEdictGroups();
}
Exemplo n.º 5
0
static void testCharacterAnimationFiles (void)
{
	const char *pattern = "models/**.anm";
	const char *filename;
	mAliasModel_t mod;
	const char* bloodspider[] = { "death1", "death2", "death3", "dead1",
			"dead2", "dead3", "stand0", "stand1", "stand2", "stand3", "walk0",
			"walk1", "walk2", "walk3", "cstand0", "cstand1", "cstand2",
			"cstand3", "cwalk0", "cwalk1", "cwalk2", "cwalk3", "stand_menu",
			"panic0", NULL };
	const char* hovernet[] = { "death1", "dead1", "death2","dead2", "death3",
			"dead3", "stand0", "walk0", "cstand0", "cwalk0", "stand1", "walk1",
			"cstand1", "cwalk1", "stand2", "walk2", "cstand2", "cwalk2",
			"stand3", "walk3", "cstand3", "cwalk3", "move_rifle", "shoot_rifle",
			"cmove_rifle", "cshoot_rifle", "stand_menu", "panic0", NULL };
	const char* soldiers[] = { "death1", "death2", "death3", "dead1", "dead2",
			"dead3", "stand0", "stand1", "stand2", "stand3", "walk0", "walk1",
			"walk2", "walk3", "cstand0", "cstand1", "cstand2", "cstand3",
			"cwalk0", "cwalk1", "cwalk2", "cwalk3", "stand_menu", "panic0",
			"move_rifle", "shoot_rifle", "cmove_rifle", "cshoot_rifle",
			"move_biggun", "shoot_biggun", "cmove_biggun", "cshoot_biggun",
			"move_melee", "shoot_melee", "cmove_melee", "cshoot_melee",
			"stand_still", "move_pistol", "shoot_pistol", "cmove_pistol",
			"cshoot_pistol", "move_pistol_d", "shoot_pistol_d",
			"cmove_pistol_d", "cshoot_pistol_d", "move_grenade",
			"shoot_grenade", "cmove_grenade", "cshoot_grenade", "move_item",
			"shoot_item", "cmove_item", "cshoot_item", "move_rpg", "shoot_rpg",
			"cmove_rpg", "cshoot_rpg", NULL };
	const char* civilians[] = { "death1", "dead1", "death2", "dead2", "death3",
			"dead3", "stand0", "walk0", "panic0", "stand1", "stand2",
			"stand_menu", "stand_still", NULL };

	FS_BuildFileList(pattern);

	vid_modelPool = Mem_CreatePool("Vid Model Pool");

	while ((filename = FS_NextFileFromFileList(pattern)) != NULL) {
		const char **animList;
		if (Q_strstart(filename, "models/soldiers/"))
			animList = soldiers;
		else if (Q_strstart(filename, "models/civilians/"))
			animList = civilians;
		else if (Q_strstart(filename, "models/aliens/bloodspider"))
			animList = bloodspider;
		else if (Q_strstart(filename, "models/aliens/hovernet"))
			animList = hovernet;
		else if (Q_strstart(filename, "models/aliens/"))
			animList = soldiers;
		else
			animList = NULL;

		/** @todo remove this hack - but ugvs are just not ready yet */
		if (Q_strstart(filename, "models/soldiers/ugv_"))
			continue;
		/** @todo remove this hack - alientank is just not ready yet */
		if (Q_strstart(filename, "models/aliens/alientank/"))
			continue;

		if (animList != NULL) {
			OBJZERO(mod);
			/* set a very high value to work around the error check in the loading function */
			mod.num_frames = 100000;

			Com_Printf("load character anim file: %s\n", filename);
			R_ModLoadAnims(&mod, filename);

			while (*animList != NULL) {
				int i;
				for (i = 0; i < mod.num_anims; i++) {
					const mAliasAnim_t *a = &mod.animdata[i];
					if (Q_streq(a->name, *animList))
						break;
				}
				if (i == mod.num_anims)
					UFO_CU_ASSERT_MSG(va("anm file %s does not contain the needed animation definition %s", filename, *animList));

				animList++;
			}
		}
	}

	Mem_DeletePool(vid_modelPool);

	FS_NextFileFromFileList(NULL);
}
Exemplo n.º 6
0
	ReactionFireTargetList () {
		OBJZERO(targets);
		init();
	}
Exemplo n.º 7
0
/**
 * @brief This is a savegame function which stores the game in xml-Format.
 * @param[in] filename The Filename to save to (without extension)
 * @param[in] comment Description of the savegame
 * @param[out] error On failure an errormessage may be set.
 */
static bool SAV_GameSave (const char* filename, const char* comment, char** error)
{
	if (!CP_IsRunning()) {
		*error = _("No campaign active.");
		Com_Printf("Error: No campaign active.\n");
		return false;
	}

	if (!B_AtLeastOneExists()) {
		*error = _("Nothing to save yet.");
		Com_Printf("Error: Nothing to save yet.\n");
		return false;
	}

	char savegame[MAX_OSPATH];
	dateLong_t date;
	char message[30];
	char timeStampBuffer[32];

	Com_MakeTimestamp(timeStampBuffer, sizeof(timeStampBuffer));
	cgi->GetRelativeSavePath(savegame, sizeof(savegame));
	Q_strcat(savegame, sizeof(savegame), "%s.%s", filename, SAVEGAME_EXTENSION);
	xmlNode_t* topNode = mxmlNewXML("1.0");
	xmlNode_t* node = cgi->XML_AddNode(topNode, SAVE_ROOTNODE);
	/* writing  Header */
	cgi->XML_AddInt(node, SAVE_SAVEVERSION, SAVE_FILE_VERSION);
	cgi->XML_AddString(node, SAVE_COMMENT, comment);
	cgi->XML_AddString(node, SAVE_UFOVERSION, UFO_VERSION);
	cgi->XML_AddString(node, SAVE_REALDATE, timeStampBuffer);
	CP_DateConvertLong(&ccs.date, &date);
	Com_sprintf(message, sizeof(message), _("%i %s %02i"),
		date.year, Date_GetMonthName(date.month - 1), date.day);
	cgi->XML_AddString(node, SAVE_GAMEDATE, message);
	/* working through all subsystems. perhaps we should redesign it, order is not important anymore */
	Com_Printf("Calling subsystems\n");
	for (int i = 0; i < saveSubsystemsAmount; i++) {
		if (!saveSubsystems[i].save)
			continue;
		if (!saveSubsystems[i].save(node))
			Com_Printf("...subsystem '%s' failed to save the data\n", saveSubsystems[i].name);
		else
			Com_Printf("...subsystem '%s' - saved\n", saveSubsystems[i].name);
	}

	/* calculate the needed buffer size */
	saveFileHeader_t header;
	OBJZERO(header);
	header.compressed = LittleLong(save_compressed->integer);
	header.version = LittleLong(SAVE_FILE_VERSION);
	header.subsystems = LittleLong(saveSubsystemsAmount);
	Q_strncpyz(header.name, comment, sizeof(header.name));
	Q_strncpyz(header.gameVersion, UFO_VERSION, sizeof(header.gameVersion));
	CP_DateConvertLong(&ccs.date, &date);
	Com_sprintf(header.gameDate, sizeof(header.gameDate), _("%i %s %02i"),
		date.year, Date_GetMonthName(date.month - 1), date.day);
	Q_strncpyz(header.realDate, timeStampBuffer, sizeof(header.realDate));

	char dummy[2];
	int requiredBufferLength = mxmlSaveString(topNode, dummy, 2, MXML_NO_CALLBACK);

	header.xmlSize = LittleLong(requiredBufferLength);
	byte* const buf = Mem_PoolAllocTypeN(byte, requiredBufferLength + 1, cp_campaignPool);
	if (!buf) {
		mxmlDelete(topNode);
		*error = _("Could not allocate enough memory to save this game");
		Com_Printf("Error: Could not allocate enough memory to save this game\n");
		return false;
	}
	int res = mxmlSaveString(topNode, (char*)buf, requiredBufferLength + 1, MXML_NO_CALLBACK);
	mxmlDelete(topNode);
	Com_Printf("XML Written to buffer (%d Bytes)\n", res);

	uLongf bufLen;
	if (header.compressed)
		bufLen = compressBound(requiredBufferLength);
	else
		bufLen = requiredBufferLength;

	byte* const fbuf = Mem_PoolAllocTypeN(byte, bufLen + sizeof(header), cp_campaignPool);
	memcpy(fbuf, &header, sizeof(header));

	if (header.compressed) {
		res = compress(fbuf + sizeof(header), &bufLen, buf, requiredBufferLength);
		cgi->Free(buf);

		if (res != Z_OK) {
			cgi->Free(fbuf);
			*error = _("Memory error compressing save-game data - set save_compressed cvar to 0");
			Com_Printf("Memory error compressing save-game data (%s) (Error: %i)!\n", comment, res);
			return false;
		}
	} else {
		memcpy(fbuf + sizeof(header), buf, requiredBufferLength);
		cgi->Free(buf);
	}

	/* last step - write data */
	cgi->FS_WriteFile(fbuf, bufLen + sizeof(header), savegame);
	cgi->Free(fbuf);

	return true;
}
Exemplo n.º 8
0
/**
 * @brief Update xviInfection value for each nation, using the XVI overlay.
 * @note should be executed after all daily event that could change XVI overlay
 */
void CP_UpdateNationXVIInfection (void)
{
	/* No need to update XVI levels if the overlay didn't change */
	if (!xviNationInfectionNeedsUpdate)
		return;

	/* width in pixel of the XVI overlay */
	int width;
	/* height in pixel of the XVI overlay */
	int height;
	CP_GetXVIMapDimensions(&width, &height);

	const float heightPerDegree = height / 180.0f;
	const float widthPerDegree = width / 360.0f;
	/* parameter used to normalize nation XVI level.
	 * decrease this factor to increase XVI level per nation */
	const float AREA_FACTOR = 650.0f;
	/* area used to normalized XVI infection level for each nation.
	 * depend on overlay size so that if we change resolution of
	 * overlay it doesn't impact nation XIInfection */
	const float normalizingArea = width * height / AREA_FACTOR;

	/* temporary array to store the XVI levels */
	float xviInfection[MAX_NATIONS];
	/* Initialize array */
	OBJZERO(xviInfection);

	for (int y = 0; y < height; y++) {
		int sum[MAX_NATIONS];
		const byte* previousNationColor;
		const nation_t* nation;
		/* current position (in latitude / longitude) */
		vec2_t currentPos;

		OBJZERO(sum);

		Vector2Set(currentPos, 180.0f, 90.0f - y / heightPerDegree);
		previousNationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr);
		nation = GEO_GetNation(currentPos);

		for (int x = 0; x < width; x++) {
			const byte* nationColor;
			currentPos[0] = 180.0f - x / widthPerDegree;
			nationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr);
			if (!VectorCompare(nationColor, previousNationColor)) {
				previousNationColor = nationColor;
				nation = GEO_GetNation(currentPos);
			}
			if (nation) {
				const int xviLevel = CP_GetXVILevel(x, y);
				if (xviLevel > 0)
					sum[nation->idx] += xviLevel;
			}
		}
		/* divide the total XVI infection by the area of a pixel
		 * because pixel are smaller as you go closer from the pole */
		for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++)
			xviInfection[nationIdx] += ((float) sum[nationIdx]) / (cos(torad * currentPos[1]) * normalizingArea);
	}

	/* copy the new values of XVI infection level into nation array */
	for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++) {
		nation_t* nation = NAT_GetNationByIDX(nationIdx);
		nation->stats[0].xviInfection = ceil(xviInfection[nation->idx]);
	}

	xviNationInfectionNeedsUpdate = false;
}
Exemplo n.º 9
0
/**
 * @brief Copies an entry from the building description file into the list of building types.
 * @note Parses one "building" entry in the basemanagement.ufo file and writes
 * it into the next free entry in bmBuildings[0], which is the list of buildings
 * in the first base (building_t).
 * @param[in] name Unique script id of a building. This is parsed from "building xxx" -> id=xxx.
 * @param[in] text the whole following text that is part of the "building" item definition in .ufo.
 * @param[in] link Bool value that decides whether to link the tech pointer in or not
 * @sa CL_ParseScriptFirst (link is false here)
 * @sa CL_ParseScriptSecond (link it true here)
 */
void B_ParseBuildings (const char* name, const char** text, bool link)
{
	building_t* building;
	technology_t* techLink;
	const char* errhead = "B_ParseBuildings: unexpected end of file (names ";
	const char* token;

	/* get id list body */
	token = Com_Parse(text);
	if (!*text || *token != '{') {
		cgi->Com_Printf("B_ParseBuildings: building \"%s\" without body ignored\n", name);
		return;
	}

	if (ccs.numBuildingTemplates >= MAX_BUILDINGS)
		cgi->Com_Error(ERR_DROP, "B_ParseBuildings: too many buildings");

	if (!link) {
		for (int i = 0; i < ccs.numBuildingTemplates; i++) {
			if (Q_streq(ccs.buildingTemplates[i].id, name)) {
				cgi->Com_Printf("B_ParseBuildings: Second building with same name found (%s) - second ignored\n", name);
				return;
			}
		}

		/* new entry */
		building = &ccs.buildingTemplates[ccs.numBuildingTemplates];
		OBJZERO(*building);
		building->id = cgi->PoolStrDup(name, cp_campaignPool, 0);

		cgi->Com_DPrintf(DEBUG_CLIENT, "...found building %s\n", building->id);

		/* set standard values */
		building->tpl = building;	/* Self-link just in case ... this way we can check if it is a template or not. */
		building->idx = -1;			/* No entry in buildings list (yet). */
		building->base = nullptr;
		building->buildingType = MAX_BUILDING_TYPE;
		building->dependsBuilding = nullptr;
		building->maxCount = -1;	/* Default: no limit */
		building->size[0] = 1;
		building->size[1] = 1;

		ccs.numBuildingTemplates++;
		do {
			/* get the name type */
			token = cgi->Com_EParse(text, errhead, name);
			if (!*text)
				break;
			if (*token == '}')
				break;

			/* get values */
			if (Q_streq(token, "type")) {
				token = cgi->Com_EParse(text, errhead, name);
				if (!*text)
					return;

				building->buildingType = B_GetBuildingTypeByBuildingID(token);
				if (building->buildingType >= MAX_BUILDING_TYPE)
					cgi->Com_Printf("didn't find buildingType '%s'\n", token);
			} else {
				/* no linking yet */
				if (Q_streq(token, "depends")) {
					cgi->Com_EParse(text, errhead, name);
					if (!*text)
						return;
				} else {
					if (!cgi->Com_ParseBlockToken(name, text, building, valid_building_vars, cp_campaignPool, token))
						cgi->Com_Printf("B_ParseBuildings: unknown token \"%s\" ignored (building %s)\n", token, name);
				}
			}
		} while (*text);
		if (building->size[0] < 1 || building->size[1] < 1 || building->size[0] >= BASE_SIZE || building->size[1] >= BASE_SIZE) {
			cgi->Com_Printf("B_ParseBuildings: Invalid size for building %s (%i, %i)\n", building->id, (int)building->size[0], (int)building->size[1]);
			ccs.numBuildingTemplates--;
		}
	} else {
		building = B_GetBuildingTemplate(name);
		if (!building)
			cgi->Com_Error(ERR_DROP, "B_ParseBuildings: Could not find building with id %s\n", name);

		techLink = RS_GetTechByProvided(name);
		if (techLink)
			building->tech = techLink;

		do {
			/* get the name type */
			token = cgi->Com_EParse(text, errhead, name);
			if (!*text)
				break;
			if (*token == '}')
				break;
			/* get values */
			if (Q_streq(token, "depends")) {
				const building_t* dependsBuilding = B_GetBuildingTemplate(cgi->Com_EParse(text, errhead, name));
				if (!dependsBuilding)
					cgi->Com_Error(ERR_DROP, "Could not find building depend of %s\n", building->id);
				building->dependsBuilding = dependsBuilding;
				if (!*text)
					return;
			}
		} while (*text);
	}
}
Exemplo n.º 10
0
/**
 * @brief Writes the brush list to the bsp
 */
void EmitBrushes (void)
{
	curTile->numbrushsides = 0;
	curTile->numbrushes = nummapbrushes;
	/* Clear out curTile->brushes */
	OBJZERO(curTile->brushes);

	for (int bnum = 0; bnum < nummapbrushes; bnum++) {
		const mapbrush_t* b = &mapbrushes[bnum];
		dBspBrush_t* db = &curTile->dbrushes[bnum];
		cBspBrush_t* cb = &curTile->brushes[bnum];

		db->brushContentFlags = b->contentFlags;
		db->firstbrushside = curTile->numbrushsides;
		db->numsides = b->numsides;
		cb->brushContentFlags = b->contentFlags;
		cb->firstbrushside = curTile->numbrushsides;
		cb->numsides = b->numsides;
		cb->checkcount = 0;
		for (int j = 0; j < b->numsides; j++) {
			if (curTile->numbrushsides == MAX_MAP_BRUSHSIDES) {
				Sys_Error("MAX_MAP_BRUSHSIDES (%i)", curTile->numbrushsides);
			} else {
				dBspBrushSide_t* cp = &curTile->brushsides[curTile->numbrushsides];
				curTile->numbrushsides++;
				cp->planenum = b->original_sides[j].planenum;
				cp->texinfo = b->original_sides[j].texinfo;
			}
		}

		/* add any axis planes not contained in the brush to bevel off corners */
		for (int x = 0; x < 3; x++)
			for (int s = -1; s <= 1; s += 2) {
				/* add the plane */
				vec3_t normal;
				VectorCopy(vec3_origin, normal);
				normal[x] = (float)s;

				vec_t dist;
				if (s == -1)
					dist = -b->mbBox.mins[x];
				else
					dist = b->mbBox.maxs[x];
				int planenum = FindOrCreateFloatPlane(normal, dist);

				int i;
				for (i = 0; i < b->numsides; i++)
					if (b->original_sides[i].planenum == planenum)
						break;
				if (i == b->numsides) {
					if (curTile->numbrushsides >= MAX_MAP_BRUSHSIDES)
						Sys_Error("MAX_MAP_BRUSHSIDES (%i)", curTile->numbrushsides);

					curTile->brushsides[curTile->numbrushsides].planenum = planenum;
					curTile->brushsides[curTile->numbrushsides].texinfo = curTile->brushsides[curTile->numbrushsides - 1].texinfo;
					curTile->numbrushsides++;
					db->numsides++;
					cb->numsides++;
				}
			}
	}
}
Exemplo n.º 11
0
void Cvar_Shutdown (void)
{
	cvarVars = NULL;
	OBJZERO(cvarVarsHash);
}
Exemplo n.º 12
0
/**
 * @todo need to merge UI model case, and the common case (look to be a copy-pasted code)
 */
void UI_DrawModelNode (uiNode_t *node, const char *source)
{
	modelInfo_t mi;
	uiModel_t *model;
	vec3_t nodeorigin;
	vec3_t autoScale;
	vec3_t autoCenter;

	assert(UI_NodeInstanceOf(node, "model"));			/**< We use model extradata */

	if (source[0] == '\0')
		return;

	model = UI_GetUIModel(source);
	/* direct model name - no UI model definition */
	if (!model) {
		/* prevent the searching for a model def in the next frame */
		mi.model = R_FindModel(source);
		mi.name = source;
		if (!mi.model) {
			Com_Printf("Could not find model '%s'\n", source);
			return;
		}
	}

	/* compute the absolute origin ('origin' property is relative to the node center) */
	UI_GetNodeAbsPos(node, nodeorigin);
	R_CleanupDepthBuffer(nodeorigin[0], nodeorigin[1], node->size[0], node->size[1]);
	if (EXTRADATA(node).clipOverflow)
		R_PushClipRect(nodeorigin[0], nodeorigin[1], node->size[0], node->size[1]);
	nodeorigin[0] += node->size[0] / 2 + EXTRADATA(node).origin[0];
	nodeorigin[1] += node->size[1] / 2 + EXTRADATA(node).origin[1];
	nodeorigin[2] = EXTRADATA(node).origin[2];

	VectorMA(EXTRADATA(node).angles, cls.frametime, EXTRADATA(node).omega, EXTRADATA(node).angles);
	mi.origin = nodeorigin;
	mi.angles = EXTRADATA(node).angles;
	mi.scale = EXTRADATA(node).scale;
	mi.center = nullVector;
	mi.color = node->color;
	mi.mesh = 0;

	/* special case to draw models with UI model */
	if (model) {
		UI_DrawModelNodeWithUIModel(node, source, &mi, model);
		if (EXTRADATA(node).clipOverflow)
			R_PopClipRect();
		return;
	}

	/* if the node is linked to a parent, the parent will display it */
	if (EXTRADATA(node).tag) {
		if (EXTRADATA(node).clipOverflow)
			R_PopClipRect();
		return;
	}

	/* autoscale? */
	if (EXTRADATA(node).autoscale) {
		const vec2_t size = {node->size[0] - node->padding, node->size[1] - node->padding};
		R_ModelAutoScale(size, &mi, autoScale, autoCenter);
	}

	/* no animation */
	mi.frame = 0;
	mi.oldframe = 0;
	mi.backlerp = 0;

	/* get skin */
	if (EXTRADATA(node).skin && *EXTRADATA(node).skin)
		mi.skin = atoi(UI_GetReferenceString(node, EXTRADATA(node).skin));
	else
		mi.skin = 0;

	/* do animations */
	if (EXTRADATA(node).animation && *EXTRADATA(node).animation) {
		animState_t *as;
		const char *ref;
		ref = UI_GetReferenceString(node, EXTRADATA(node).animation);

		/* check whether the cvar value changed */
		if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) {
			Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE);
			/* model has changed but mem is already reserved in pool */
			if (EXTRADATA(node).animationState) {
				Mem_Free(EXTRADATA(node).animationState);
				EXTRADATA(node).animationState = NULL;
			}
		}
		if (!EXTRADATA(node).animationState) {
			as = (animState_t *) Mem_PoolAlloc(sizeof(*as), cl_genericPool, 0);
			if (!as)
				Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref);
			R_AnimChange(as, mi.model, ref);
			EXTRADATA(node).animationState = as;
		} else {
			const char *anim;
			/* change anim if needed */
			as = EXTRADATA(node).animationState;
			if (!as)
				Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref);
			anim = R_AnimGetName(as, mi.model);
			if (anim && !Q_streq(anim, ref))
				R_AnimChange(as, mi.model, ref);
			R_AnimRun(as, mi.model, cls.frametime * 1000);
		}

		mi.frame = as->frame;
		mi.oldframe = as->oldframe;
		mi.backlerp = as->backlerp;
	}

	/* draw the main model on the node */
	R_DrawModelDirect(&mi, NULL, NULL);

	/* draw all children */
	if (node->firstChild) {
		uiNode_t *child;
		modelInfo_t pmi = mi;
		for (child = node->firstChild; child; child = child->next) {
			const char *tag;
			char childSource[MAX_VAR];
			const char* childRef;

			/* skip non "model" nodes */
			if (child->behaviour != node->behaviour)
				continue;

			/* skip invisible child */
			if (child->invis || !UI_CheckVisibility(child))
				continue;

			OBJZERO(mi);
			mi.angles = EXTRADATA(child).angles;
			mi.scale = EXTRADATA(child).scale;
			mi.center = nullVector;
			mi.origin = EXTRADATA(child).origin;
			mi.color = pmi.color;

			/* get the anchor name to link the model into the parent */
			tag = EXTRADATA(child).tag;

			/* init model name */
			childRef = UI_GetReferenceString(child, EXTRADATA(child).model);
			if (Q_strnull(childRef))
				childSource[0] = '\0';
			else
				Q_strncpyz(childSource, childRef, sizeof(childSource));
			mi.model = R_FindModel(childSource);
			mi.name = childSource;

			/* init skin */
			if (EXTRADATA(child).skin && *EXTRADATA(child).skin)
				mi.skin = atoi(UI_GetReferenceString(child, EXTRADATA(child).skin));
			else
				mi.skin = 0;

			R_DrawModelDirect(&mi, &pmi, tag);
		}
	}

	if (EXTRADATA(node).clipOverflow)
		R_PopClipRect();
}
/**
 * @brief Start Base Attack.
 * @note Base attack mission -- Stage 2
 */
void CP_BaseAttackStartMission (mission_t *mission)
{
	base_t *base = mission->data.base;
	linkedList_t *hiredSoldiersInBase = NULL;
	int soldiers;

	assert(base);

	mission->stage = STAGE_BASE_ATTACK;

	CP_MissionDisableTimeLimit(mission);

	if (mission->ufo) {
		/* ufo becomes invisible on geoscape, but don't remove it from ufo global array (may reappear)*/
		CP_UFORemoveFromGeoscape(mission, qfalse);
	}

	/* we always need at least one command centre in the base - because the
	 * phalanx soldiers have their starting positions here.
	 * There should also always be an entrance - the aliens start there
	 * but we don't need to check that as entrance can't be destroyed */
	if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, B_COMMAND)) {
		/** @todo handle command centre properly */
		Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no Command Center: it can't defend itself. Destroy base.\n", base->name);
		CP_BaseAttackMissionDestroyBase(mission);
		return;
	}

	MSO_CheckAddNewMessage(NT_BASE_ATTACK, _("Base attack"), va(_("Base '%s' is under attack!"), base->name), qfalse, MSG_BASEATTACK, NULL);

	base->baseStatus = BASE_UNDER_ATTACK;
	ccs.campaignStats.basesAttacked++;

	MAP_SelectMission(mission);
	mission->active = qtrue;
	ccs.mapAction = MA_BASEATTACK;
	Com_DPrintf(DEBUG_CLIENT, "Base attack: %s at %.0f:%.0f\n", mission->id, mission->pos[0], mission->pos[1]);

	/** @todo EMPL_ROBOT */
	E_GetHiredEmployees(base, EMPL_SOLDIER, &hiredSoldiersInBase);

	/* Fill the fake aircraft */
	LIST_Delete(&baseAttackFakeAircraft.acTeam);
	OBJZERO(baseAttackFakeAircraft);
	baseAttackFakeAircraft.homebase = base;
	/* needed for transfer of alien corpses */
	VectorCopy(base->pos, baseAttackFakeAircraft.pos);
#if 0
	/** @todo active this once more than 8 soldiers are working */
	/* needed to spawn soldiers on map */
	baseAttackFakeAircraft.maxTeamSize = LIST_Count(hiredSoldiersInBase);
#else
	baseAttackFakeAircraft.maxTeamSize = MAX_ACTIVETEAM;
#endif

	if (!hiredSoldiersInBase) {
		Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers: it can't defend itself. Destroy base.\n", base->name);
		CP_BaseAttackMissionDestroyBase(mission);
		return;
	}

	UI_ExecuteConfunc("soldierlist_clear");
	soldiers = 0;
	LIST_Foreach(hiredSoldiersInBase, employee_t, employee) {
		const rank_t *rank = CL_GetRankByIdx(employee->chr.score.rank);

		if (E_IsAwayFromBase(employee))
			continue;
		UI_ExecuteConfunc("soldierlist_add %d \"%s %s\"", employee->chr.ucn, (rank) ? _(rank->shortname) : "", employee->chr.name);
		if (soldiers < 1)
			UI_ExecuteConfunc("team_select_ucn %d", employee->chr.ucn);
		soldiers++;
	}
	if (soldiers == 0) {
		Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers at home: it can't defend itself. Destroy base.\n", base->name);
		CP_BaseAttackMissionDestroyBase(mission);
		return;
	}
#if 0
	/** @todo active this once more than 8 soldiers are working */
	/* all soldiers in the base should get used */
	baseAttackFakeAircraft.maxTeamSize = AIR_GetTeamSize(&baseAttackFakeAircraft);
#endif

	LIST_Delete(&hiredSoldiersInBase);
	base->aircraftCurrent = &baseAttackFakeAircraft;
	MAP_SetMissionAircraft(&baseAttackFakeAircraft);
	/** @todo remove me - this is not needed because we are using the base->aircraftCurrent
	 * pointer for resolving the aircraft - only CP_GameAutoGo needs this */
	MAP_SetInterceptorAircraft(&baseAttackFakeAircraft);	/* needed for updating soldier stats sa CP_UpdateCharacterStats*/
	B_SetCurrentSelectedBase(base);						/* needed for equipment menu */

	Com_sprintf(popupText, sizeof(popupText), _("Base '%s' is under attack! What to do ?"), base->name);
	UI_RegisterText(TEXT_POPUP, popupText);

	CP_GameTimeStop();
	UI_PushWindow("popup_baseattack", NULL, NULL);
}
Exemplo n.º 14
0
/**
 * @sa CL_ParseClientData
 */
static void CP_ParseCampaign (const char *name, const char **text)
{
	const char *errhead = "CP_ParseCampaign: unexpected end of file (campaign ";
	campaign_t *cp;
	const char *token;
	int i;
	salary_t *s;
	bool drop = false;

	/* search for campaigns with same name */
	for (i = 0; i < ccs.numCampaigns; i++)
		if (Q_streq(name, ccs.campaigns[i].id))
			break;

	if (i < ccs.numCampaigns) {
		Com_Printf("CP_ParseCampaign: campaign def \"%s\" with same name found, second ignored\n", name);
		return;
	}

	if (ccs.numCampaigns >= MAX_CAMPAIGNS) {
		Com_Printf("CP_ParseCampaign: Max campaigns reached (%i)\n", MAX_CAMPAIGNS);
		return;
	}

	/* initialize the campaign */
	cp = &ccs.campaigns[ccs.numCampaigns++];
	OBJZERO(*cp);

	cp->idx = ccs.numCampaigns - 1;
	Q_strncpyz(cp->id, name, sizeof(cp->id));

	/* some default values */
	cp->team = TEAM_PHALANX;
	Q_strncpyz(cp->researched, "researched_human", sizeof(cp->researched));
	cp->researchRate = 0.8f;
	cp->produceRate = 1.0f;
	cp->healingRate = 1.0f;
	cp->ufoReductionRate = NON_OCCURRENCE_PROBABILITY;
	cp->initialInterest = INITIAL_OVERALL_INTEREST;

	/* get it's body */
	token = Com_Parse(text);

	if (!*text || *token != '{') {
		Com_Printf("CP_ParseCampaign: campaign def \"%s\" without body ignored\n", name);
		ccs.numCampaigns--;
		return;
	}

	/* set undefined markers */
	s = &cp->salaries;
    for (i = 0; i < MAX_EMPL; i++) {
		s->base[i] = -1;
		s->rankBonus[i] = -1;
		s->admin[i] = -1;
	}
	s->aircraftFactor = -1;
	s->aircraftDivisor = -1;
	s->baseUpkeep = -1;
	s->adminInitial = -1;
	s->debtInterest = -1;

	do {
		token = cgi->Com_EParse(text, errhead, name);
		if (!*text)
			break;
		if (*token == '}')
			break;

		/* check for some standard values */
		if (Com_ParseBlockToken(name, text, cp, campaign_vals, NULL, token)) {
			continue;
		} else if (Q_streq(token, "salary")) {
			CP_ParseSalary(token, text, s);
		} else if (Q_streq(token, "events")) {
			token = cgi->Com_EParse(text, errhead, name);
			if (!*text)
				return;
			cp->events = CP_GetEventsByID(token);
		} else {
			Com_Printf("CP_ParseCampaign: unknown token \"%s\" ignored (campaign %s)\n", token, name);
			cgi->Com_EParse(text, errhead, name);
		}
	} while (*text);

	if (cp->difficulty < -4)
		cp->difficulty = -4;
	else if (cp->difficulty > 4)
		cp->difficulty = 4;

	/* checking for undefined values */
	for (i = 0; i < MAX_EMPL; i++) {
		if (s->base[i] == -1 || s->rankBonus[i] == -1 || s->admin[i] == -1) {
			drop = true;
			break;
		}
	}
	if (drop || s->aircraftFactor == -1 || s->aircraftDivisor == -1 || s->baseUpkeep == -1
	 || s->adminInitial == -1 || s->debtInterest == -1) {
		Com_Printf("CP_ParseCampaign: check salary definition. Campaign def \"%s\" ignored\n", name);
		ccs.numCampaigns--;
		return;
	}
}
Exemplo n.º 15
0
/**
 * @brief Register all save-subsystems and init some cvars and commands
 * @sa SAV_GameSave
 * @sa SAV_GameLoad
 */
void SAV_Init (void)
{
	static saveSubsystems_t cp_subsystemXML = {"campaign", CP_SaveXML, CP_LoadXML};
	static saveSubsystems_t rs_subsystemXML = {"research", RS_SaveXML, RS_LoadXML};
	static saveSubsystems_t b_subsystemXML = {"base", B_SaveXML, B_LoadXML};
	static saveSubsystems_t hos_subsystemXML = {"hospital", HOS_SaveXML, HOS_LoadXML};
	static saveSubsystems_t bs_subsystemXML = {"market", BS_SaveXML, BS_LoadXML};
	static saveSubsystems_t e_subsystemXML = {"employee", E_SaveXML, E_LoadXML};
	static saveSubsystems_t ac_subsystemXML = {"aliencont", nullptr, AC_LoadXML};
	static saveSubsystems_t pr_subsystemXML = {"production", PR_SaveXML, PR_LoadXML};
	static saveSubsystems_t air_subsystemXML = {"aircraft", AIR_SaveXML, AIR_LoadXML};
	static saveSubsystems_t ab_subsystemXML = {"alien base", AB_SaveXML, AB_LoadXML};
	static saveSubsystems_t int_subsystemXML = {"interest", INT_SaveXML, INT_LoadXML};
	static saveSubsystems_t mis_subsystemXML = {"mission", MIS_SaveXML, MIS_LoadXML};
	static saveSubsystems_t ms_subsystemXML = {"messagesystem", MS_SaveXML, MS_LoadXML};
	static saveSubsystems_t stats_subsystemXML = {"stats", STATS_SaveXML, STATS_LoadXML};
	static saveSubsystems_t na_subsystemXML = {"nations", NAT_SaveXML, NAT_LoadXML};
	static saveSubsystems_t trans_subsystemXML = {"transfer", TR_SaveXML, TR_LoadXML};
	static saveSubsystems_t xvi_subsystemXML = {"xvirate", XVI_SaveXML, XVI_LoadXML};
	static saveSubsystems_t ins_subsystemXML = {"installation", INS_SaveXML, INS_LoadXML};
	static saveSubsystems_t mso_subsystemXML = {"messageoptions", MSO_SaveXML, MSO_LoadXML};
	static saveSubsystems_t event_subsystemXML = {"triggerevents", CP_TriggerEventSaveXML, CP_TriggerEventLoadXML};
	static saveSubsystems_t us_subsystemXML = {"ufostores", US_SaveXML, US_LoadXML};

	saveSubsystemsAmount = 0;
	OBJZERO(saveSubsystems);

	Com_Printf("\n--- save subsystem initialization --\n");

	/* don't mess with the order */
	SAV_AddSubsystem(&cp_subsystemXML);
	SAV_AddSubsystem(&rs_subsystemXML);
	SAV_AddSubsystem(&b_subsystemXML);
	SAV_AddSubsystem(&hos_subsystemXML);
	SAV_AddSubsystem(&bs_subsystemXML);
	SAV_AddSubsystem(&e_subsystemXML);
	SAV_AddSubsystem(&ac_subsystemXML);
	SAV_AddSubsystem(&air_subsystemXML);
	SAV_AddSubsystem(&ab_subsystemXML);
	SAV_AddSubsystem(&int_subsystemXML);
	SAV_AddSubsystem(&ins_subsystemXML);
	SAV_AddSubsystem(&mis_subsystemXML);
	SAV_AddSubsystem(&us_subsystemXML);
	SAV_AddSubsystem(&pr_subsystemXML);
	SAV_AddSubsystem(&ms_subsystemXML);
	SAV_AddSubsystem(&stats_subsystemXML);
	SAV_AddSubsystem(&na_subsystemXML);
	SAV_AddSubsystem(&trans_subsystemXML);
	SAV_AddSubsystem(&xvi_subsystemXML);
	SAV_AddSubsystem(&mso_subsystemXML);
	SAV_AddSubsystem(&event_subsystemXML);

	/* Check whether there is a quicksave at all */
	cgi->Cmd_AddCommand("game_quickloadinit", SAV_GameQuickLoadInit_f, "Load the game from the quick save slot.");
	cgi->Cmd_AddCommand("game_quicksave", SAV_GameQuickSave_f, "Save to the quick save slot.");
	cgi->Cmd_AddCommand("game_quickload", SAV_GameQuickLoad_f, "Load the game from the quick save slot.");
	cgi->Cmd_AddCommand("game_save", SAV_GameSave_f, "Saves to a given filename");
	cgi->Cmd_AddCommand("game_load", SAV_GameLoad_f, "Loads a given filename");
	cgi->Cmd_AddCommand("game_delete", SAV_GameDelete_f, "Deletes a given filename");
	cgi->Cmd_AddCommand("game_comments", SAV_GameReadGameComments_f, "Loads the savegame names");
	cgi->Cmd_AddCommand("game_continue", SAV_GameContinue_f, "Continue with the last saved game");
	save_compressed = cgi->Cvar_Get("save_compressed", "1", CVAR_ARCHIVE, "Save the savefiles compressed if set to 1");
	cl_lastsave = cgi->Cvar_Get("cl_lastsave", "", CVAR_ARCHIVE, "Last saved slot - use for the continue-campaign function");
}
Exemplo n.º 16
0
/**
 * @brief Parses one "components" entry in a .ufo file and writes it into the next free entry in xxxxxxxx (components_t).
 * @param[in] name The unique id of a components_t array entry.
 * @param[in] text the whole following text after the "components" definition.
 * @sa CP_ParseScriptFirst
 */
static void CP_ParseComponents (const char *name, const char **text)
{
	components_t *comp;
	const char *errhead = "CP_ParseComponents: unexpected end of file.";
	const char *token;

	/* get body */
	token = Com_Parse(text);
	if (!*text || *token != '{') {
		Com_Printf("CP_ParseComponents: \"%s\" components def without body ignored.\n", name);
		return;
	}
	if (ccs.numComponents >= MAX_ASSEMBLIES) {
		Com_Printf("CP_ParseComponents: too many technology entries. limit is %i.\n", MAX_ASSEMBLIES);
		return;
	}

	/* New components-entry (next free entry in global comp-list) */
	comp = &ccs.components[ccs.numComponents];
	ccs.numComponents++;

	OBJZERO(*comp);

	/* name is not used */

	do {
		/* get the name type */
		token = cgi->Com_EParse(text, errhead, name);
		if (!*text)
			break;
		if (*token == '}')
			break;

		/* get values */
		if (Q_streq(token, "aircraft")) {
			token = cgi->Com_EParse(text, errhead, name);
			if (!*text)
				break;

			/* set standard values */
			Q_strncpyz(comp->assemblyId, token, sizeof(comp->assemblyId));
			comp->assemblyItem = INVSH_GetItemByIDSilent(comp->assemblyId);
			if (comp->assemblyItem)
				Com_DPrintf(DEBUG_CLIENT, "CP_ParseComponents: linked item: %s with components: %s\n", token, comp->assemblyId);
		} else if (Q_streq(token, "item")) {
			/* Defines what items need to be collected for this item to be researchable. */
			if (comp->numItemtypes < MAX_COMP) {
				/* Parse block */
				component_type_data_t itemTokens;
				OBJZERO(itemTokens);
				if (Com_ParseBlock ("item", text, &itemTokens, components_type_vals, NULL)) {
					if (itemTokens.id[0] == '\0')
						cgi->Com_Error(ERR_DROP, "CP_ParseComponents: \"item\" token id is missing.\n");
					if (itemTokens.amount[0] == '\0')
						cgi->Com_Error(ERR_DROP, "CP_ParseComponents: \"amount\" token id is missing.\n");
					if (itemTokens.numbercrash[0] == '\0')
						cgi->Com_Error(ERR_DROP, "CP_ParseComponents: \"numbercrash\" token id is missing.\n");

					comp->items[comp->numItemtypes] = INVSH_GetItemByID(itemTokens.id);	/* item id -> item pointer */

					/* Parse number of items. */
					comp->itemAmount[comp->numItemtypes] = atoi(itemTokens.amount);
					/* If itemcount needs to be scaled */
					if (itemTokens.numbercrash[0] == '%')
						comp->itemAmount2[comp->numItemtypes] = COMP_ITEMCOUNT_SCALED;
					else
						comp->itemAmount2[comp->numItemtypes] = atoi(itemTokens.numbercrash);

					/** @todo Set item links to NONE if needed */
					/* comp->item_idx[comp->numItemtypes] = xxx */

					comp->numItemtypes++;
				}
			} else {
				Com_Printf("CP_ParseComponents: \"%s\" Too many 'items' defined. Limit is %i - ignored.\n", name, MAX_COMP);
			}
		} else if (Q_streq(token, "time")) {
			/* Defines how long disassembly lasts. */
			token = Com_Parse(text);
			comp->time = atoi(token);
		} else {
			Com_Printf("CP_ParseComponents: Error in \"%s\" - unknown token: \"%s\".\n", name, token);
		}
	} while (*text);

	if (comp->assemblyId[0] == '\0') {
		cgi->Com_Error(ERR_DROP, "CP_ParseComponents: component \"%s\" is not applied to any aircraft.\n", name);
	}
}
Exemplo n.º 17
0
void CIN_InitCinematic (cinematic_t* cin)
{
	OBJZERO(*cin);
}
Exemplo n.º 18
0
/**
 * @brief Reset all characters in the static character array
 * @sa GAME_GetCharacterArraySize
 * @sa GAME_GetCharacter
 */
void GAME_ResetCharacters (void)
{
	OBJZERO(characters);
	chrDisplayList.num = 0;
}
Exemplo n.º 19
0
/**
 * @brief Parse medals and ranks defined in the medals.ufo file.
 * @sa CL_ParseScriptFirst
 */
void CL_ParseRanks (const char* name, const char** text)
{
	rank_t* rank;
	const char* errhead = "CL_ParseRanks: unexpected end of file (medal/rank ";
	const char* token;

	/* get name list body body */
	token = Com_Parse(text);

	if (!*text || *token != '{') {
		Com_Printf("CL_ParseRanks: rank/medal \"%s\" without body ignored\n", name);
		return;
	}

	for (int i = 0; i < ccs.numRanks; i++) {
		if (Q_streq(name, ccs.ranks[i].name)) {
			Com_Printf("CL_ParseRanks: Rank with same name '%s' already loaded.\n", name);
			return;
		}
	}
	/* parse ranks */
	if (ccs.numRanks >= MAX_RANKS) {
		Com_Printf("CL_ParseRanks: Too many rank descriptions, '%s' ignored.\n", name);
		ccs.numRanks = MAX_RANKS;
		return;
	}

	rank = &ccs.ranks[ccs.numRanks++];
	OBJZERO(*rank);
	rank->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
	rank->level = -1;

	do {
		/* get the name type */
		token = cgi->Com_EParse(text, errhead, name);
		if (!*text)
			break;
		if (*token == '}')
			break;

		if (cgi->Com_ParseBlockToken(name, text, rank, rankValues, cp_campaignPool, token)) {
			continue;
		} else if (Q_streq(token, "type")) {
			/* employeeType_t */
			token = cgi->Com_EParse(text, errhead, name);
			if (!*text)
				return;
			/* error check is performed in E_GetEmployeeType function */
			rank->type = E_GetEmployeeType(token);
		} else
			Com_Printf("CL_ParseRanks: unknown token \"%s\" ignored (medal/rank %s)\n", token, name);
	} while (*text);

	if (rank->image == nullptr || !strlen(rank->image))
		cgi->Com_Error(ERR_DROP, "CL_ParseRanks: image is missing for rank %s", rank->id);

	if (rank->name == nullptr || !strlen(rank->name))
		cgi->Com_Error(ERR_DROP, "CL_ParseRanks: name is missing for rank %s", rank->id);

	if (rank->shortname == nullptr || !strlen(rank->shortname))
		rank->shortname = rank->name;

	if (rank->level == -1)
		cgi->Com_Error(ERR_DROP, "CL_ParseRanks: level is missing for rank %s", rank->id);
}
Exemplo n.º 20
0
/**
 * @brief create a new framebuffer object
 * @param[in] width The width of the framebuffer
 * @param[in] height The height of the framebuffer
 * @param[in] ntextures The amount of textures for this framebuffer. See also the filters array.
 * @param[in] depth Also generate a depth buffer
 * @param[in] halfFloat Use half float pixel format
 * @param[in] filters Filters for the textures. Must have @c ntextures entries
 */
r_framebuffer_t * R_CreateFramebuffer (int width, int height, int ntextures, qboolean depth, qboolean halfFloat, unsigned int *filters)
{
	r_framebuffer_t *buf;
	int i;

	if (!r_state.frameBufferObjectsInitialized) {
		Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n");
		return NULL;
	}

	if (frameBufferObjectCount >= lengthof(frameBufferObjects)) {
		Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n");
		return NULL;
	}

	buf = &frameBufferObjects[frameBufferObjectCount++];
	OBJZERO(*buf);

	if (ntextures > r_config.maxDrawBuffers) {
		Com_Printf("Couldn't allocate requested number of drawBuffers in R_SetupFramebuffer!\n");
		ntextures = r_config.maxDrawBuffers;
	}

	Vector4Clear(buf->clearColor);

	buf->width = width;
	buf->height = height;
	R_SetupViewport(buf, 0, 0, width, height);

	buf->nTextures = ntextures;
	buf->textures = (unsigned int *)Mem_Alloc(sizeof(unsigned int) * ntextures);

	buf->pixelFormat = halfFloat ? GL_RGBA16F_ARB : GL_RGBA8;
	buf->byteFormat = halfFloat ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE;

	/* Presence of depth buffer indicates render target that could use antialiasing*/
	if (depth) {
		/** @todo also check if we are running on older (SM2.0) hardware, which doesn't support antialiased MRT */
		if (qglRenderbufferStorageMultisampleEXT && qglBlitFramebuffer) {
			int samples = min(4, max(0, r_multisample->integer));
			if (samples>1)
				buf->samples = samples;
		}
	}

	for (i = 0; i < buf->nTextures; i++) {
		buf->textures[i] = R_GetFreeFBOTexture();
		glBindTexture(GL_TEXTURE_2D, buf->textures[i]);
		glTexImage2D(GL_TEXTURE_2D, 0, buf->pixelFormat, buf->width, buf->height, 0, GL_RGBA, buf->byteFormat, 0);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[i]);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
		qglGenerateMipmapEXT(GL_TEXTURE_2D);
		if (r_config.anisotropic)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic);

		R_CheckError();
	}
	glBindTexture(GL_TEXTURE_2D, 0);

	/* create FBO itself */
	qglGenFramebuffersEXT(1, &buf->fbo);
	R_CheckError();
	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo);

	/* create&attach depth renderbuffer */
	if (depth) {
		qglGenRenderbuffersEXT(1, &buf->depth);
		qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->depth);
		if (buf->samples)
			qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, GL_DEPTH_COMPONENT, buf->width, buf->height);
		else
			qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, buf->width, buf->height);
		qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buf->depth);
	} else {
		buf->depth = 0;
	}

	/* create multisample color buffers if needed */
	if (buf->samples) {
		/* generate color buffers */
		for (i = 0; i < buf->nTextures; i++) {
			unsigned colorbuffer;
			qglGenRenderbuffersEXT(1, &colorbuffer);
			qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorbuffer);
			qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, buf->pixelFormat, buf->width, buf->height);
			qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_RENDERBUFFER_EXT, colorbuffer);
			R_CheckError();
		}
		/* proxy framebuffer object for resolving MSAA */
		qglGenFramebuffersEXT(1, &buf->proxyFBO);
		R_CheckError();
		qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->proxyFBO);
	}

	/* Whether multisampling was enabled or not, current FBO should be populated with render-to-texture bindings */
	for (i = 0; i < buf->nTextures; i++) {
		qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_TEXTURE_2D, buf->textures[i], 0);
		R_CheckError();
	}

	R_CheckError();

	/* unbind the framebuffer and return to default state */
	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	return buf;
}
Exemplo n.º 21
0
/**
 * @brief Copies an entry from the installation description file into the list of installation templates.
 * @note Parses one "installation" entry in the installation.ufo file and writes
 * it into the next free entry in installationTemplates.
 * @param[in] name Unique test-id of a installationTemplate_t.
 * @param[in] text the rest of the script file that is tokenized here
 */
void INS_ParseInstallations (const char *name, const char **text)
{
	installationTemplate_t *installation;
	const char *errhead = "INS_ParseInstallations: unexpected end of file (names ";
	const char *token;
	int i;

	/* get id list body */
	token = Com_Parse(text);
	if (!*text || *token != '{') {
		Com_Printf("INS_ParseInstallations: installation \"%s\" without body ignored\n", name);
		return;
	}

	if (!name) {
		Com_Printf("INS_ParseInstallations: installation name not specified.\n");
		return;
	}

	if (ccs.numInstallationTemplates >= MAX_INSTALLATION_TEMPLATES) {
		Com_Printf("INS_ParseInstallations: too many installation templates\n");
		ccs.numInstallationTemplates = MAX_INSTALLATION_TEMPLATES;	/* just in case it's bigger. */
		return;
	}

	for (i = 0; i < ccs.numInstallationTemplates; i++) {
		if (Q_streq(ccs.installationTemplates[i].name, name)) {
			Com_Printf("INS_ParseInstallations: Second installation with same name found (%s) - second ignored\n", name);
			return;
		}
	}

	/* new entry */
	installation = &ccs.installationTemplates[ccs.numInstallationTemplates];
	OBJZERO(*installation);
	installation->id = Mem_PoolStrDup(name, cp_campaignPool, 0);

	Com_DPrintf(DEBUG_CLIENT, "...found installation %s\n", installation->id);

	ccs.numInstallationTemplates++;
	do {
		/* get the name type */
		token = Com_EParse(text, errhead, name);
		if (!*text)
			break;
		if (*token == '}')
			break;

		/* check for some standard values */
		if (!Com_ParseBlockToken(name, text, installation, installation_vals, cp_campaignPool, token)) {
			/* other values */
			if (Q_streq(token, "cost")) {
				char cvarname[MAX_VAR] = "mn_installation_";

				Q_strcat(cvarname, installation->id, sizeof(cvarname));
				Q_strcat(cvarname, "_cost", sizeof(cvarname));

				token = Com_EParse(text, errhead, name);
				if (!*text)
					return;
				installation->cost = atoi(token);

				Cvar_Set(cvarname, va(_("%d c"), atoi(token)));
			} else if (Q_streq(token, "buildtime")) {
				char cvarname[MAX_VAR];

				token = Com_EParse(text, errhead, name);
				if (!*text)
					return;
				installation->buildTime = atoi(token);

				Com_sprintf(cvarname, sizeof(cvarname), "mn_installation_%s_buildtime", installation->id);
				Cvar_Set(cvarname, va(ngettext("%d day", "%d days", atoi(token)), atoi(token)));
			}
		}
	} while (*text);
}
Exemplo n.º 22
0
	void SetUp() {
		OBJZERO(*sv);
	}
Exemplo n.º 23
0
void IN_JoystickMove (void)
{
	bool joy_pressed[lengthof(joy_keys)];
	unsigned int axes = 0;
	unsigned int hats = 0;
	int total = 0;
	int i = 0;

	/* check whether a user has changed the joystick number */
	if (in_joystickNo->modified)
		IN_StartupJoystick();
	/* check whether joysticks are disabled */
	if (!in_joystick->integer)
		return;

	if (!stick)
		return;

	SDL_JoystickUpdate();

	OBJZERO(joy_pressed);

	/* update the ball state */
	total = SDL_JoystickNumBalls(stick);
	if (total > 0) {
		int balldx = 0;
		int balldy = 0;
		for (i = 0; i < total; i++) {
			int dx = 0;
			int dy = 0;
			SDL_JoystickGetBall(stick, i, &dx, &dy);
			balldx += dx;
			balldy += dy;
		}
		if (balldx || balldy) {
			mousePosX = balldx / viddef.rx;
			mousePosY = balldy / viddef.ry;
		}
	}

	/* now query the stick buttons... */
	total = SDL_JoystickNumButtons(stick);
	if (total > 0) {
		if (total > lengthof(stick_state.buttons))
			total = lengthof(stick_state.buttons);
		for (i = 0; i < total; i++) {
			const bool pressed = (SDL_JoystickGetButton(stick, i) != 0);
			if (pressed != stick_state.buttons[i]) {
				IN_EventEnqueue(K_JOY1 + i, 0, pressed);
				stick_state.buttons[i] = pressed;
			}
		}
	}

	/* look at the hats... */
	total = SDL_JoystickNumHats(stick);
	if (total > 0) {
		if (total > 4)
			total = 4;
		for (i = 0; i < total; i++)
			((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
	}

	/* update hat state */
	if (hats != stick_state.oldhats) {
		for (i = 0; i < 4; i++) {
			if (((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i]) {
				/* release event */
				switch (((Uint8 *)&stick_state.oldhats)[i]) {
				case SDL_HAT_UP:
					IN_EventEnqueue(hat_keys[4 * i + 0], 0, false);
					break;
				case SDL_HAT_RIGHT:
					IN_EventEnqueue(hat_keys[4 * i + 1], 0, false);
					break;
				case SDL_HAT_DOWN:
					IN_EventEnqueue(hat_keys[4 * i + 2], 0, false);
					break;
				case SDL_HAT_LEFT:
					IN_EventEnqueue(hat_keys[4 * i + 3], 0, false);
					break;
				case SDL_HAT_RIGHTUP:
					IN_EventEnqueue(hat_keys[4 * i + 0], 0, false);
					IN_EventEnqueue(hat_keys[4 * i + 1], 0, false);
					break;
				case SDL_HAT_RIGHTDOWN:
					IN_EventEnqueue(hat_keys[4 * i + 2], 0, false);
					IN_EventEnqueue(hat_keys[4 * i + 1], 0, false);
					break;
				case SDL_HAT_LEFTUP:
					IN_EventEnqueue(hat_keys[4 * i + 0], 0, false);
					IN_EventEnqueue(hat_keys[4 * i + 3], 0, false);
					break;
				case SDL_HAT_LEFTDOWN:
					IN_EventEnqueue(hat_keys[4 * i + 2], 0, false);
					IN_EventEnqueue(hat_keys[4 * i + 3], 0, false);
					break;
				default:
					break;
				}
				/* press event */
				switch (((Uint8 *)&hats)[i]) {
				case SDL_HAT_UP:
					IN_EventEnqueue(hat_keys[4 * i + 0], 0, true);
					break;
				case SDL_HAT_RIGHT:
					IN_EventEnqueue(hat_keys[4 * i + 1], 0, true);
					break;
				case SDL_HAT_DOWN:
					IN_EventEnqueue(hat_keys[4 * i + 2], 0, true);
					break;
				case SDL_HAT_LEFT:
					IN_EventEnqueue(hat_keys[4 * i + 3], 0, true);
					break;
				case SDL_HAT_RIGHTUP:
					IN_EventEnqueue(hat_keys[4 * i + 0], 0, true);
					IN_EventEnqueue(hat_keys[4 * i + 1], 0, true);
					break;
				case SDL_HAT_RIGHTDOWN:
					IN_EventEnqueue(hat_keys[4 * i + 2], 0, true);
					IN_EventEnqueue(hat_keys[4 * i + 1], 0, true);
					break;
				case SDL_HAT_LEFTUP:
					IN_EventEnqueue(hat_keys[4 * i + 0], 0, true);
					IN_EventEnqueue(hat_keys[4 * i + 3], 0, true);
					break;
				case SDL_HAT_LEFTDOWN:
					IN_EventEnqueue(hat_keys[4 * i + 2], 0, true);
					IN_EventEnqueue(hat_keys[4 * i + 3], 0, true);
					break;
				default:
					break;
				}
			}
		}
	}

	/* save hat state */
	stick_state.oldhats = hats;

	/* finally, look at the axes... */
	total = SDL_JoystickNumAxes(stick);
	if (total >= 2) {
		/* the first two axes are used for the cursor movement */
		for (i = 0; i < 2; i++) {
			const Sint16 axis = SDL_JoystickGetAxis(stick, i);
			const float velocity = ((float) axis) / 32767.0f;
			if (velocity > -in_joystickThreshold->value && velocity < in_joystickThreshold->value)
				continue;

			if (i & 1) {
				mousePosY += in_joystickSpeed->value * velocity;
				if (mousePosY > (int)viddef.context.height)
					mousePosY = (int)viddef.context.height;
				else if (mousePosY < 0)
					mousePosY = 0;
			} else {
				mousePosX += in_joystickSpeed->value * velocity;
				if (mousePosX > (int)viddef.context.width)
					mousePosX = (int)viddef.context.width;
				else if (mousePosX < 0)
					mousePosX = 0;
			}
		}
	}


	if (total > 2) {
		if (total > 16)
			total = 16;
		/* every axis except the first two can be normally bound to an action */
		for (i = 2; i < total; i++) {
			const Sint16 axis = SDL_JoystickGetAxis(stick, i);
			const float f = ((float) axis) / 32767.0f;
			if (f < -in_joystickThreshold->value) {
				axes |= (1 << (i * 2));
			} else if (f > in_joystickThreshold->value) {
				axes |= (1 << ((i * 2) + 1));
			}
		}
	}


	/* Time to update axes state based on old vs. new. */
	if (axes != stick_state.oldaxes) {
		for (i = 2; i < 16; i++) {
			if ((axes & (1 << i)) && !(stick_state.oldaxes & (1 << i)))
				IN_EventEnqueue(joy_keys[i], 0, true);

			if (!(axes & (1 << i)) && (stick_state.oldaxes & (1 << i)))
				IN_EventEnqueue(joy_keys[i], 0, false);
		}
	}

	/* Save for future generations. */
	stick_state.oldaxes = axes;
}
Exemplo n.º 24
0
/**
 * @brief Called after every player has joined
 */
void G_ResetClientData (void)
{
	scoreMissionNum = 0;
	OBJZERO(scoreMission);
}
Exemplo n.º 25
0
/**
 * @brief A connection request that did not come from the master
 * @sa CL_ConnectionlessPacket
 */
static void SVC_DirectConnect (struct net_stream *stream)
{
	char userinfo[MAX_INFO_STRING];
	client_t *cl;
	player_t *player;
	int playernum;
	int version;
	qboolean connected;
	char buf[256];
	const char *peername = NET_StreamPeerToName(stream, buf, sizeof(buf), qfalse);

	Com_DPrintf(DEBUG_SERVER, "SVC_DirectConnect()\n");

	if (sv->started) {
		Com_Printf("rejected connect because match is already running\n");
		NET_OOB_Printf(stream, "print\nGame has started already.\n");
		return;
	}

	version = atoi(Cmd_Argv(1));
	if (version != PROTOCOL_VERSION) {
		Com_Printf("rejected connect from version %i - %s\n", version, peername);
		NET_OOB_Printf(stream, "print\nServer is version %s.\n", UFO_VERSION);
		return;
	}

	Q_strncpyz(userinfo, Cmd_Argv(2), sizeof(userinfo));

	if (userinfo[0] == '\0') {  /* catch empty userinfo */
		Com_Printf("Empty userinfo from %s\n", peername);
		NET_OOB_Printf(stream, "print\nConnection refused.\n");
		return;
	}

	if (strchr(userinfo, '\xFF')) {  /* catch end of message in string exploit */
		Com_Printf("Illegal userinfo contained xFF from %s\n", peername);
		NET_OOB_Printf(stream, "print\nConnection refused.\n");
		return;
	}

	if (strlen(Info_ValueForKey(userinfo, "ip"))) {  /* catch spoofed ips  */
		Com_Printf("Illegal userinfo contained ip from %s\n", peername);
		NET_OOB_Printf(stream, "print\nConnection refused.\n");
		return;
	}

	/* force the IP key/value pair so the game can filter based on ip */
	Info_SetValueForKey(userinfo, sizeof(userinfo), "ip", peername);

	/* find a client slot */
	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state == cs_free)
			break;
	if (cl == NULL) {
		NET_OOB_Printf(stream, "print\nServer is full.\n");
		Com_Printf("Rejected a connection - server is full.\n");
		return;
	}

	/* build a new connection - accept the new client
	 * this is the only place a client_t is ever initialized */
	OBJZERO(*cl);
	playernum = cl - SV_GetClient(0);
	player = PLAYER_NUM(playernum);
	cl->player = player;
	cl->player->num = playernum;

	TH_MutexLock(svs.serverMutex);
	connected = svs.ge->ClientConnect(player, userinfo, sizeof(userinfo));
	TH_MutexUnlock(svs.serverMutex);

	/* get the game a chance to reject this connection or modify the userinfo */
	if (!connected) {
		const char *rejmsg = Info_ValueForKey(userinfo, "rejmsg");
		if (rejmsg[0] != '\0') {
			NET_OOB_Printf(stream, "print\n%s\nConnection refused.\n", rejmsg);
			Com_Printf("Game rejected a connection from %s. Reason: %s\n", peername, rejmsg);
		} else {
			NET_OOB_Printf(stream, "print\nConnection refused.\n");
			Com_Printf("Game rejected a connection from %s.\n", peername);
		}
		return;
	}

	/* new player */
	cl->player->inuse = qtrue;

	/* parse some info from the info strings */
	strncpy(cl->userinfo, userinfo, sizeof(cl->userinfo) - 1);
	SV_UserinfoChanged(cl);

	/* send the connect packet to the client */
	if (sv_http_downloadserver->string[0])
		NET_OOB_Printf(stream, "client_connect dlserver=%s", sv_http_downloadserver->string);
	else
		NET_OOB_Printf(stream, "client_connect");

	SV_SetClientState(cl, cs_connected);

	cl->lastconnect = svs.realtime;
	Q_strncpyz(cl->peername, peername, sizeof(cl->peername));
	cl->stream = stream;
	NET_StreamSetData(stream, cl);
}