Example #1
0
/**
 * @brief Dumps contents of the entire client routing table to CSV file.
 * @sa CL_InitLocal
 */
void Grid_DumpClientRoutes_f (void)
{
	ipos3_t wpMins, wpMaxs;
	VecToPos(cl.mapData->mapBox.mins, wpMins);
	VecToPos(cl.mapData->mapBox.maxs, wpMaxs);
	RT_WriteCSVFiles(cl.mapData->routing, "ufoaiclient", GridBox(wpMins, wpMaxs));
}
Example #2
0
/**
 * @note This is only working for one z-level. But our models should be
 * split for each level anyway.
 * @param ent The edict to fill the forbidden list for
 */
static void G_BuildForbiddenListForEntity (edict_t *ent)
{
	pos3_t mins, maxs, origin;
	vec3_t center, shiftedMins, shiftedMaxs;
	int xDelta, yDelta, size, i, j;

	VectorAdd(ent->absmin, ent->origin, shiftedMins);
	VectorAdd(ent->absmax, ent->origin, shiftedMaxs);

	VectorCenterFromMinsMaxs(shiftedMins, shiftedMaxs, center);
	VecToPos(shiftedMins, mins);
	VecToPos(shiftedMaxs, maxs);
	VecToPos(center, origin);

	xDelta = std::max(1, maxs[0] - mins[0]);
	yDelta = std::max(1, maxs[1] - mins[1]);

	size = xDelta * yDelta;
	ent->forbiddenListPos = (pos3_t *)G_TagMalloc(size * sizeof(pos3_t), TAG_LEVEL);
	ent->forbiddenListSize = size;

	for (i = 0; i < xDelta; i++) {
		for (j = 0; j < yDelta; j++) {
			const pos_t x = mins[0] + i;
			const pos_t y = mins[1] + j;
			const pos_t z = origin[2];
			VectorSet(ent->forbiddenListPos[i], x, y, z);
		}
	}
}
Example #3
0
/**
 * @brief Dumps contents of the entire client routing table to CSV file.
 * @sa CL_InitLocal
 */
void Grid_DumpClientRoutes_f (void)
{
	ipos3_t wpMins, wpMaxs;
	VecToPos(cl.mapData->mapMin, wpMins);
	VecToPos(cl.mapData->mapMax, wpMaxs);
	RT_WriteCSVFiles(cl.mapData->map, "ufoaiclient", wpMins, wpMaxs);
}
Example #4
0
/**
 * @brief Only moves the camera to the given target location if its not yet close enough
 */
void CL_CheckCameraRoute (const pos3_t from, const pos3_t target)
{
	pos3_t current;
	VecToPos(cl.cam.origin, current);
	const float minDistToMove = 4.0f;
	const float dist = Vector2Dist(target, current);
	if (dist < minDistToMove) {
		if (target[2] != current[2])
			Cvar_SetValue("cl_worldlevel", target[2]);
		return;
	}
	CL_CameraRoute(from, target);
}
Example #5
0
/**
 * @brief Center the camera on the local entity's origin
 * @param le The local entity which origin is used to center the camera
 * @sa CL_CenterView
 * @sa CL_ViewCenterAtGridPosition
 * @sa CL_CameraRoute
 */
void LE_CenterView (const le_t* le)
{
	if (!cl_centerview->integer)
		return;

	assert(le);
	if (le->team == cls.team) {
		const float minDistToMove = 4.0f * UNIT_SIZE;
		const float dist = Vector2Dist(cl.cam.origin, le->origin);
		if (dist < minDistToMove) {
			pos3_t currentCamPos;
			VecToPos(cl.cam.origin, currentCamPos);
			if (le->pos[2] != currentCamPos[2])
				Cvar_SetValue("cl_worldlevel", le->pos[2]);
			return;
		}

		VectorCopy(le->origin, cl.cam.origin);
	} else {
		pos3_t pos;
		VecToPos(cl.cam.origin, pos);
		CL_CheckCameraRoute(pos, le->pos);
	}
}
Example #6
0
/**
 * This is only for particles that are spawned during a match - not for map particles.
 * @return A particle edict
 */
Edict* G_SpawnParticle (const vec3_t origin, int spawnflags, const char* particle)
{
	Edict* ent = G_Spawn("particle");
	ent->type = ET_PARTICLE;
	VectorCopy(origin, ent->origin);

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

	ent->particle = particle;
	ent->spawnflags = spawnflags;

	G_CheckVis(ent);

	return ent;
}
Example #7
0
/**
 * @brief Register this think function once you would like to end the match
 * This think function will register the touch callback and spawns the particles for
 * the client to see the next map trigger.
 */
void Think_NextMapTrigger (Edict* self)
{
	vec3_t center;
	pos3_t centerPos;

	self->absBox.getCenter(center);

	/* spawn the particle to mark the trigger */
	G_SpawnParticle(center, self->spawnflags, self->particle);
	VecToPos(center, centerPos);
	G_EventCenterViewAt(PM_ALL, centerPos);

	gi.BroadcastPrintf(PRINT_HUD, _("You are now ready to switch the map."));

	self->setTouch(Touch_NextMapTrigger);
	self->think = nullptr;
}
Example #8
0
/**
 * @brief Applies morale changes to actors who find themselves in the general direction of a shot.
 * @param shooter The shooting actor.
 * @param fd The firedef used to shoot.
 * @param from The weapon's muzzle location.
 * @param weapon The weapon used to shoot.
 * @param impact The shoot's impact location.
 */
static void G_ShotMorale (const Actor* shooter, const fireDef_t* fd, const vec3_t from, const Item* weapon, const vec3_t impact)
{
	/* Skip not detectable shoots */
	if (weapon->def()->dmgtype == gi.csi->damLaser || fd->irgoggles)
		return;

	Actor* check = nullptr;
	const float minDist = UNIT_SIZE * 1.5f;
	while ((check = G_EdictsGetNextLivingActor(check))) {
		/* Skip yourself */
		if (check == shooter)
			continue;
		pos3_t target;
		VecToPos(impact, target);
		/* Skip the hit actor -- morale was already handled */
		if (check->isSamePosAs(target))
			continue;
		vec3_t dir1, dir2;
		VectorSubtract(check->origin, from, dir1);
		VectorSubtract(impact, from, dir2);
		const float len1 = VectorLength(dir1);
		const float len2 = VectorLength(dir2);
		const float dot = DotProduct(dir1, dir2);
		if (dot / (len1 * len2) < 0.7f)
			continue;
		/* Skip if shooting next or over an ally */
		if (check->isSameTeamAs(shooter) && VectorDistSqr(check->origin, shooter->origin)
				<= minDist * minDist)
			continue;
		vec3_t vec1;
		if (len1 > len2) {
			VectorSubtract(dir2, dir1, vec1);
		} else {
			VectorScale(dir2, dot / (len2 * len2), vec1);
			VectorSubtract(dir1, vec1, vec1);
		}
		const float morDist = (check->isSamePosAs(target) ? UNIT_SIZE * 0.5f : minDist);
		if (VectorLengthSqr(vec1) <= morDist * morDist) {
			/* @todo Add a visibility check here? */
			G_Morale(ML_SHOOT, check, shooter, fd->damage[0]);
		}
	}
}
Example #9
0
static void G_SpawnSmoke (const vec3_t vec, const char *particle, int rounds)
{
	pos3_t pos;
	edict_t *ent;

	VecToPos(vec, pos);

	ent = G_GetEdictFromPos(pos, ET_SMOKE);
	if (ent == NULL) {
		pos_t z = gi.GridFall(gi.routingMap, ACTOR_SIZE_NORMAL, pos);
		if (z != pos[2])
			return;

		ent = G_Spawn();
		VectorCopy(pos, ent->pos);
		G_EdictCalcOrigin(ent);
		ent->spawnflags = G_GetLevelFlagsFromPos(pos);
		ent->particle = particle;
		SP_misc_smoke(ent);
	}

	ent->count = rounds;
}
Example #10
0
static void G_SpawnStunSmoke (const vec3_t vec, const char* particle, int rounds, int damage)
{
	pos3_t pos;
	Edict* ent;

	VecToPos(vec, pos);

	ent = G_GetEdictFromPos(pos, ET_SMOKESTUN);
	if (ent == nullptr) {
		pos_t z = gi.GridFall(ACTOR_SIZE_NORMAL, pos);
		if (z != pos[2])
			return;

		ent = G_Spawn();
		VectorCopy(pos, ent->pos);
		VectorCopy(vec, ent->origin);
		ent->dmg = damage;
		ent->particle = particle;
		ent->spawnflags = G_GetLevelFlagsFromPos(pos);
		SP_misc_smokestun(ent);
	}

	ent->count = rounds;
}
Example #11
0
void G_InitCamera (Edict* ent, camera_type_t cameraType, float angle, bool rotate)
{
	switch (cameraType) {
	CAMERAMODEL(CAMERA_MOBILE, 0);
	CAMERAMODEL(CAMERA_STATIONARY, 1);
	default:
		gi.DPrintf("unknown camera type given: %i\n", cameraType);
		G_FreeEdict(ent);
		return;
	}

	AABB modelAabb;
	if (gi.LoadModelAABB(ent->model, 0, modelAabb)) {
		ent->entBox.set(modelAabb);

		ent->camera.cameraType = cameraType;
		ent->camera.rotate = rotate;
		ent->classname = "misc_camera";
		ent->type = ET_CAMERA;
		ent->solid = SOLID_BBOX;
		ent->flags |= FL_DESTROYABLE;
		ent->material = MAT_ELECTRICAL;
		ent->fieldSize = ACTOR_SIZE_NORMAL;
		ent->destroy = Destroy_Camera;
		ent->use = G_CameraUse;
		ent->dir = AngleToDir(angle);

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

		gi.LinkEdict(ent);
	} else {
		gi.DPrintf("Could not get bounding box for model '%s'\n", ent->model);
		G_FreeEdict(ent);
	}
}
Example #12
0
static void G_SpawnFire (const vec3_t vec, const char *particle, int rounds, int damage)
{
	pos3_t pos;
	edict_t *ent;

	VecToPos(vec, pos);

	ent = G_GetEdictFromPos(pos, ET_FIRE);
	if (ent == NULL) {
		pos_t z = gi.GridFall(gi.routingMap, ACTOR_SIZE_NORMAL, pos);
		if (z != pos[2])
			return;

		ent = G_Spawn();
		VectorCopy(pos, ent->pos);
		VectorCopy(vec, ent->origin);
		ent->dmg = damage;
		ent->particle = particle;
		ent->spawnflags = G_GetLevelFlagsFromPos(pos);
		SP_misc_fire(ent);
	}

	ent->count = rounds;
}
Example #13
0
/**
 * @brief This function recalculates the routing surrounding the entity name.
 * @sa CM_InlineModel
 * @sa CM_CheckUnit
 * @sa CM_UpdateConnection
 * @sa CMod_LoadSubmodels
 * @sa Grid_RecalcBoxRouting
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] routing The routing map (either server or client map)
 * @param[in] name Name of the inline model to compute the mins/maxs for
 * @param[in] box The box around the inline model (alternative to name)
 * @param[in] list The local models list (a local model has a name starting with * followed by the model number)
 */
void Grid_RecalcRouting (mapTiles_t *mapTiles, Routing &routing, const char *name, const GridBox &box, const char **list)
{
	if (box.isZero()) {
		pos3_t min, max;
		vec3_t absmin, absmax;
		const cBspModel_t *model;
		unsigned int i;
		/* get inline model, if it is one */
		if (*name != '*') {
			Com_Printf("Called Grid_RecalcRouting with no inline model\n");
			return;
		}
		model = CM_InlineModel(mapTiles, name);
		if (!model) {
			Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name);
			return;
		}

#if 1
		/* An attempt to fix the 'doors starting opened' bug (# 3456).
		 * The main difference is the (missing) rotation of the halfVec.
		 * The results are better, but do not fix the problem. */
		CalculateMinsMaxs(model->angles, model->mins, model->maxs, model->origin, absmin, absmax);
#else
		/* get the target model's dimensions */
		if (VectorNotEmpty(model->angles)) {
			vec3_t minVec, maxVec;
			vec3_t centerVec, halfVec, newCenterVec;
			vec3_t m[3];

			/* Find the center of the extents. */
			VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec);

			/* Find the half height and half width of the extents. */
			VectorSubtract(model->maxs, centerVec, halfVec);

			/* Rotate the center about the origin. */
			VectorCreateRotationMatrix(model->angles, m);
			VectorRotate(m, centerVec, newCenterVec);

			/* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
			VectorSubtract(newCenterVec, halfVec, minVec);
			VectorAdd(newCenterVec, halfVec, maxVec);

			/* Now offset by origin then convert to position (Doors do not have 0 origins) */
			VectorAdd(minVec, model->origin, absmin);
			VectorAdd(maxVec, model->origin, absmax);
		} else {  /* normal */
			/* Now offset by origin then convert to position (Doors do not have 0 origins) */
			VectorAdd(model->mins, model->origin, absmin);
			VectorAdd(model->maxs, model->origin, absmax);
		}
#endif
		VecToPos(absmin, min);
		VecToPos(absmax, max);

		/* fit min/max into the world size */
		max[0] = std::min(max[0], (pos_t)(PATHFINDING_WIDTH - 1));
		max[1] = std::min(max[1], (pos_t)(PATHFINDING_WIDTH - 1));
		max[2] = std::min(max[2], (pos_t)(PATHFINDING_HEIGHT - 1));
		for (i = 0; i < 3; i++)
			min[i] = std::max(min[i], (pos_t)0);

		/* We now have the dimensions, call the generic rerouting function. */
		GridBox rerouteBox(min, max);
		Grid_RecalcBoxRouting(mapTiles, routing, rerouteBox, list);
	} else {
		/* use the passed box */
		Grid_RecalcBoxRouting(mapTiles, routing, box, list);
	}
}
Example #14
0
static void testMove (void)
{
	vec3_t vec;
	pos3_t pos;
	pos_t gridPos;

	if (FS_CheckFile("maps/%s.bsp", mapName) != -1) {
		char entityString[MAX_TOKEN_CHARS];
		CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles);
		CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles);
	} else {
		UFO_CU_FAIL_MSG_FATAL(va("Map resource '%s.bsp' for test is missing.", mapName));
	}

	VectorSet(vec, 16, 16, 48);
	VecToPos(vec, pos);
	CU_ASSERT_EQUAL(pos[0], 128);
	CU_ASSERT_EQUAL(pos[1], 128);
	CU_ASSERT_EQUAL(pos[2], 0);

	VectorSet(vec, 80, 16, 80);
	VecToPos(vec, pos);
	CU_ASSERT_EQUAL(pos[0], 130);
	CU_ASSERT_EQUAL(pos[1], 128);
	CU_ASSERT_EQUAL(pos[2], 1);

	gridPos = Grid_Fall(mapData.routing, ACTOR_SIZE_NORMAL, pos);
	CU_ASSERT_EQUAL(gridPos, 1);

	{
		const byte crouchingState = 0;
		const int maxTUs = MAX_ROUTE_TUS;
		int lengthStored;
		pos3_t to;
		pathing_t* path = Mem_AllocType(pathing_t);

		VectorSet(vec, 80, 80, 32);
		VecToPos(vec, pos);

		Grid_CalcPathing(mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, nullptr);
		Grid_MoveStore(path);

		/* move downwards */
		{
			int lengthUnstored;
			VectorSet(vec, 80, 48, 32);
			VecToPos(vec, to);

			lengthUnstored = Grid_MoveLength(path, to, crouchingState, false);
			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthUnstored, lengthStored);
			CU_ASSERT_EQUAL(lengthStored, TU_MOVE_STRAIGHT);
		}
		/* try to move three steps upwards - there is a brush*/
		{
			VectorSet(vec, 80, 176, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE);
		}
		/* try move into the nodraw */
		{
			VectorSet(vec, 48, 16, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE);
		}
		/* move into the lightclip */
		{
			VectorSet(vec, 48, 48, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, TU_MOVE_DIAGONAL);
		}
		/* move into the passable */
		{
			VectorSet(vec, 144, 48, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, TU_MOVE_DIAGONAL + TU_MOVE_STRAIGHT);
		}
		/* go to the other side - diagonal, followed by six straight moves */
		{
			VectorSet(vec, -16, 48, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 6 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
		}
		/* try to walk out of the map */
		{
			VectorSet(vec, 48, 272, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE);
		}
		/* walk to the map border */
		{
			VectorSet(vec, 48, 240, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 4 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
		}
		/* walk a level upwards */
		{
			VectorSet(vec, 240, 80, 96);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 5 * TU_MOVE_STRAIGHT);
		}
		/* move to the door (not a func_door) */
		{
			VectorSet(vec, 176, -80, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 4 * TU_MOVE_STRAIGHT + 2 * TU_MOVE_DIAGONAL);
		}
		/* move into the trigger_touch */
		{
			VectorSet(vec, -48, -80, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 5 * TU_MOVE_STRAIGHT + 3 * TU_MOVE_DIAGONAL);
		}
		/* try to walk into the actorclip */
		{
			VectorSet(vec, -48, -48, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, ROUTING_NOT_REACHABLE);
		}
	}
}
Example #15
0
static void testMoveEntities (void)
{
	pos3_t pos;
	vec3_t vec;
	pathing_t* path = Mem_AllocType(pathing_t);
	forbiddenList_t forbiddenList;
	const byte crouchingState = 0;
	const int maxTUs = MAX_ROUTE_TUS;
	forbiddenList.reset();

	SV_Map(true, mapName, nullptr);

	/* starting point */
	VectorSet(vec, 240, -144, 32);
	VecToPos(vec, pos);

	G_CompleteRecalcRouting();

	{
		Edict* ent = nullptr;
		while ((ent = G_EdictsGetNextInUse(ent))) {
			/* Dead 2x2 unit will stop walking, too. */
			if (ent->type == ET_SOLID) {
				int j;
				for (j = 0; j < ent->forbiddenListSize; j++) {
					forbiddenList.add(ent->forbiddenListPos[j], (byte*) &ent->fieldSize);
				}
			}
		}
	}

	{
		int lengthStored;
		pos3_t to;

		Grid_CalcPathing(sv->mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, &forbiddenList);
		Grid_MoveStore(path);

		/* walk onto the func_breakable */
		{
			VectorSet(vec, 112, -144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 4 * TU_MOVE_STRAIGHT);
		}
		/* walk over the func_breakable */
		{
			VectorSet(vec, 80, -144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 5 * TU_MOVE_STRAIGHT);
		}
		/* walk over the func_breakable */
		{
			VectorSet(vec, 16, -144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 7 * TU_MOVE_STRAIGHT);
		}
	}

	/* starting point */
	VectorSet(vec, 144, 144, 32);
	VecToPos(vec, pos);

	{
		int lengthStored;
		pos3_t to;

		Grid_CalcPathing(sv->mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, &forbiddenList);
		Grid_MoveStore(path);

		/* walk through the opened door */
		{
			VectorSet(vec, 112, 144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, TU_MOVE_STRAIGHT);
		}

		/* walk around the opened door */
		{
			VectorSet(vec, 144, 208, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, true);
			CU_ASSERT_EQUAL(lengthStored, 2 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
		}
	}

	SV_ShutdownGameProgs();
}
Example #16
0
/**
 * @brief Register local entities for SOLID_BSP models like func_breakable or func_door
 * @note func_breakable, func_door
 * @sa G_SendEdictsAndBrushModels
 * @sa EV_ADD_BRUSH_MODEL
 * @sa CL_SpawnParseEntitystring
 */
void CL_AddBrushModel (const eventRegister_t *self, struct dbuffer *msg)
{
	le_t *le;
	int entnum, modelnum1, levelflags, speed, dir;
	entity_type_t type;
	const cBspModel_t *model;
	int angle;
	vec3_t origin, angles;

	NET_ReadFormat(msg, self->formatString, &type, &entnum, &modelnum1, &levelflags, &origin, &angles, &speed, &angle, &dir);

	if (type != ET_BREAKABLE && type != ET_DOOR && type != ET_ROTATING && type != ET_DOOR_SLIDING && type != ET_TRIGGER_RESCUE && type != ET_TRIGGER_NEXTMAP)
		Com_Error(ERR_DROP, "Invalid le announced via EV_ADD_BRUSH_MODEL type: %i\n", type);
	else if (modelnum1 > MAX_MODELS || modelnum1 < 1)
		Com_Error(ERR_DROP, "Invalid le modelnum1 announced via EV_ADD_BRUSH_MODEL\n");

	/* check if the ent is already visible */
	le = LE_Get(entnum);
	if (le)
		Com_Error(ERR_DROP, "le announced a second time - le for entnum %i (type: %i) already exists (via EV_ADD_BRUSH_MODEL)\n", entnum, type);

	le = LE_Add(entnum);
	assert(le);

	le->rotationSpeed = speed / 100.0f;
	le->slidingSpeed = speed;
	le->angle = angle;
	le->dir = dir;
	le->type = type;
	le->modelnum1 = modelnum1;
	le->levelflags = levelflags;
	le->addFunc = LE_BrushModelAction;
	LE_SetThink(le, LET_BrushModel);
	/* The origin and angles are REQUIRED for doors to work! */
	VectorCopy(origin, le->origin);
	/* store the initial position - needed for sliding doors */
	VectorCopy(le->origin, le->oldOrigin);
	VectorCopy(angles, le->angles);

	Com_sprintf(le->inlineModelName, sizeof(le->inlineModelName), "*%i", le->modelnum1);
	model = LE_GetClipModel(le);
	le->model1 = R_FindModel(le->inlineModelName);
	if (!le->model1)
		Com_Error(ERR_DROP, "CL_AddBrushModel: Could not register inline model %i", le->modelnum1);

	/* Transfer model mins and maxs to entity */
	VectorCopy(model->mins, le->mins);
	VectorCopy(model->maxs, le->maxs);
	VectorSubtract(le->maxs, le->mins, le->size);
	VecToPos(le->origin, le->pos);

	/* to allow tracing against this le */
	if (!LE_IsNotSolid(le)) {
		/* This is to help the entity collision code out */
		/* Copy entity origin and angles to model*/
		CM_SetInlineModelOrientation(cl.mapTiles, le->inlineModelName, le->origin, le->angles);

		le->contents = CONTENTS_SOLID;

		CL_RecalcRouting(le);
	}
}
Example #17
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();
}
Example #18
0
static void testMoveEntities (void)
{
	routing_t *routing;
	pos3_t pos;
	vec3_t vec;
	pathing_t *path = Mem_AllocType(pathing_t);
	pos_t *forbiddenList[MAX_FORBIDDENLIST];
	int forbiddenListLength = 0;
	const byte crouchingState = 0;
	const int distance = MAX_ROUTE;

	SV_Map(qtrue, mapName, NULL);

	/* starting point */
	VectorSet(vec, 240, -144, 32);
	VecToPos(vec, pos);

	routing = &sv->mapData.map[ACTOR_SIZE_NORMAL - 1];

	G_CompleteRecalcRouting();

	{
		edict_t *ent = NULL;
		while ((ent = G_EdictsGetNextInUse(ent))) {
			/* Dead 2x2 unit will stop walking, too. */
			if (ent->type == ET_SOLID) {
				int j;
				for (j = 0; j < ent->forbiddenListSize; j++) {
					forbiddenList[forbiddenListLength++] = ent->forbiddenListPos[j];
					forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
				}
			}
		}
	}

	{
		int lengthStored;
		pos3_t to;

		Grid_MoveCalc(routing, ACTOR_SIZE_NORMAL, path, pos, crouchingState, distance, forbiddenList, forbiddenListLength);
		Grid_MoveStore(path);

		/* walk onto the func_breakable */
		{
			VectorSet(vec, 112, -144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, qtrue);
			CU_ASSERT_EQUAL(lengthStored, 4 * TU_MOVE_STRAIGHT);
		}
		/* walk over the func_breakable */
		{
			VectorSet(vec, 80, -144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, qtrue);
			CU_ASSERT_EQUAL(lengthStored, 5 * TU_MOVE_STRAIGHT);
		}
		/* walk over the func_breakable */
		{
			VectorSet(vec, 16, -144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, qtrue);
			CU_ASSERT_EQUAL(lengthStored, 7 * TU_MOVE_STRAIGHT);
		}
	}

	/* starting point */
	VectorSet(vec, 144, 144, 32);
	VecToPos(vec, pos);

	{
		int lengthStored;
		pos3_t to;

		Grid_MoveCalc(routing, ACTOR_SIZE_NORMAL, path, pos, crouchingState, distance, forbiddenList, forbiddenListLength);
		Grid_MoveStore(path);

		/* walk through the opened door */
		{
			VectorSet(vec, 112, 144, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, qtrue);
			CU_ASSERT_EQUAL(lengthStored, TU_MOVE_STRAIGHT);
		}

		/* walk around the opened door */
		{
			VectorSet(vec, 144, 208, 32);
			VecToPos(vec, to);

			lengthStored = Grid_MoveLength(path, to, crouchingState, qtrue);
			CU_ASSERT_EQUAL(lengthStored, 2 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
		}
	}

	SV_ShutdownGameProgs();
}
Example #19
0
/**
 * @brief Calculates the routing of a map
 * @sa CheckUnit
 * @sa CheckConnections
 * @sa ProcessWorldModel
 */
void DoRouting (void)
{
	int i;
	byte* data;
	vec3_t mins, maxs;
	pos3_t pos;

	/* Turn on trace debugging if requested. */
	if (config.generateDebugTrace)
		debugTrace = true;

	/* Record the current mapTiles[0] state so we can remove all CLIPS when done. */
	PushInfo();

	/* build tracing structure */
	EmitBrushes();
	EmitPlanes(); /** This is needed for tracing to work!!! */
	/** @note LEVEL_TRACING is not an actual level */
	MakeTracingNodes(LEVEL_ACTORCLIP + 1);

	/* Reset the whole block of map data to 0 */
	Nmap.init();

	/* get world bounds for optimizing */
	RT_GetMapSize(&mapTiles, mins, maxs);
	/* Com_Printf("Vectors: (%f, %f, %f) to (%f, %f, %f)\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); */
	VecToPos(mins, wpMins);
	VecToPos(maxs, wpMaxs);

	/* Verify the world extents are not lopsided. */
	assert(wpMins[0] <= wpMaxs[0]);
	assert(wpMins[1] <= wpMaxs[1]);
	assert(wpMins[2] <= wpMaxs[2]);

	/* scan area heights */
	RunSingleThreadOn(CheckUnitThread, PATHFINDING_WIDTH * PATHFINDING_WIDTH * ACTOR_MAX_SIZE, config.verbosity >= VERB_NORMAL, "UNITCHECK");

	/* scan connections */
	RunSingleThreadOn(CheckConnectionsThread, PATHFINDING_WIDTH * PATHFINDING_WIDTH * (CORE_DIRECTIONS / (1 + RT_IS_BIDIRECTIONAL)) * (ACTOR_MAX_SIZE), config.verbosity >= VERB_NORMAL, "CONNCHECK");

	/* Try to shrink the world bounds along the x and y coordinates */
	for (i = 0; i < 2; i++) {			/* for x and y, but not z */
		int j = i ^ 1;					/* if i points to x, j points to y and vice versa */
		/* Increase the mins */
		while (wpMaxs[j] > wpMins[j]) {
			VectorSet(pos, wpMins[0], wpMins[1], wpMaxs[2]);
			for (pos[i] = wpMins[i]; pos[i] <= wpMaxs[i]; pos[i]++) {	/* for all cells in an x or y row */
				if (Nmap.getFloor(1, pos[0], pos[1], wpMaxs[2]) + wpMaxs[2] * CELL_HEIGHT != -1)	/* no floor ? */
					break;
			}
			if (pos[i] <= wpMaxs[i])	/* found a floor before the end of the row ? */
				break;					/* break while */
			wpMins[j]++;				/* if it was an x-row, increase y-value of mins and vice versa */
		}
		/* Decrease the maxs */
		while (wpMaxs[j] > wpMins[j]) {
			VectorCopy(wpMaxs, pos);
			for (pos[i] = wpMins[i]; pos[i] <= wpMaxs[i]; pos[i]++) {
				if (Nmap.getFloor(1, pos[0], pos[1], wpMaxs[2]) + wpMaxs[2] * CELL_HEIGHT != -1)
					break;
			}
			if (pos[i] <= wpMaxs[i])
				break;
			wpMaxs[j]--;
		}
	}

	/* Output the floor trace file if set */
	if (config.generateTraceFile) {
		RT_WriteCSVFiles(Nmap, baseFilename, wpMins, wpMaxs);
	}

	/* store the data */
	data = curTile->routedata;
	for (i = 0; i < 3; i++)
		wpMins[i] = LittleLong(wpMins[i]);
	data = CompressRouting((byte*)wpMins, data, sizeof(wpMins));
	for (i = 0; i < 3; i++)
		wpMaxs[i] = LittleLong(wpMaxs[i]);
	data = CompressRouting((byte*)wpMaxs, data, sizeof(wpMaxs));
	data = CompressRouting((byte*)&Nmap, data, sizeof(Nmap));

	curTile->routedatasize = data - curTile->routedata;

	/* Ensure that we did not exceed our allotment of memory for this data. */
	assert(curTile->routedatasize <= MAX_MAP_ROUTING);

	/* Remove the CLIPS fom the tracing structure by resetting it. */
	PopInfo();
}
Example #20
0
/**
 * @brief This function recalculates the routing surrounding the entity name.
 * @sa CM_InlineModel
 * @sa CM_CheckUnit
 * @sa CM_UpdateConnection
 * @sa CMod_LoadSubmodels
 * @sa Grid_RecalcBoxRouting
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] map The routing map (either server or client map)
 * @param[in] name Name of the inline model to compute the mins/maxs for
 * @param[in] list The local models list (a local model has a name starting with * followed by the model number)
 */
void Grid_RecalcRouting (mapTiles_t *mapTiles, routing_t *map, const char *name, const char **list)
{
	const cBspModel_t *model;
	pos3_t min, max;
	unsigned int i;
	double start, end;

	start = time(NULL);

	/* get inline model, if it is one */
	if (*name != '*') {
		Com_Printf("Called Grid_RecalcRouting with no inline model\n");
		return;
	}
	model = CM_InlineModel(mapTiles, name);
	if (!model) {
		Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name);
		return;
	}

	Com_DPrintf(DEBUG_PATHING, "Model:%s origin(%f,%f,%f) angles(%f,%f,%f) mins(%f,%f,%f) maxs(%f,%f,%f)\n", name,
		model->origin[0], model->origin[1], model->origin[2],
		model->angles[0], model->angles[1], model->angles[2],
		model->mins[0], model->mins[1], model->mins[2],
		model->maxs[0], model->maxs[1], model->maxs[2]);

	/* get the target model's dimensions */
	if (VectorNotEmpty(model->angles)) {
		vec3_t minVec, maxVec;
		vec3_t centerVec, halfVec, newCenterVec;
		vec3_t m[3];

		/* Find the center of the extents. */
		VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec);

		/* Find the half height and half width of the extents. */
		VectorSubtract(model->maxs, centerVec, halfVec);

		/* Rotate the center about the origin. */
		VectorCreateRotationMatrix(model->angles, m);
		VectorRotate(m, centerVec, newCenterVec);

		/* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
		VectorSubtract(newCenterVec, halfVec, minVec);
		VectorAdd(newCenterVec, halfVec, maxVec);

		/* Now offset by origin then convert to position (Doors do not have 0 origins) */
		VectorAdd(minVec, model->origin, minVec);
		VecToPos(minVec, min);
		VectorAdd(maxVec, model->origin, maxVec);
		VecToPos(maxVec, max);
	} else {  /* normal */
		vec3_t temp;
		/* Now offset by origin then convert to position (Doors do not have 0 origins) */
		VectorAdd(model->mins, model->origin, temp);
		VecToPos(temp, min);
		VectorAdd(model->maxs, model->origin, temp);
		VecToPos(temp, max);
	}

	/* fit min/max into the world size */
	max[0] = min(max[0] + 1, PATHFINDING_WIDTH - 1);
	max[1] = min(max[1] + 1, PATHFINDING_WIDTH - 1);
	max[2] = min(max[2] + 1, PATHFINDING_HEIGHT - 1);
	for (i = 0; i < 3; i++)
		min[i] = max(min[i] - 1, 0);

	/* We now have the dimensions, call the generic rerouting function. */
	Grid_RecalcBoxRouting(mapTiles, map, min, max, list);

	end = time(NULL);
	Com_DPrintf(DEBUG_ROUTING, "Retracing for model %s between (%i, %i, %i) and (%i, %i %i) in %5.1fs\n",
			name, min[0], min[1], min[2], max[0], max[1], max[2], end - start);
}