Example #1
0
/**
 * @brief Moves actor.
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg The netchannel message
 * @sa LET_PathMove
 * @note EV_ACTOR_MOVE
 */
void CL_ActorDoMove (const eventRegister_t* self, dbuffer* msg)
{
	const int number = NET_ReadShort(msg);

	/* get le */
	le_t* le = LE_Get(number);
	if (!le)
		LE_NotFoundError(number);

	if (!LE_IsActor(le))
		Com_Error(ERR_DROP, "Can't move, LE doesn't exist or is not an actor (entnum: %i, type: %i)\n",
			number, le->type);

	if (LE_IsDead(le))
		Com_Error(ERR_DROP, "Can't move, actor on team %i dead (entnum: %i)", le->team, number);

	/* lock this le for other events, the corresponding unlock is in LE_DoEndPathMove() */
	LE_Lock(le);
	if (le->isMoving()) {
		if (le->pathLength == le->pathPos) {
			LE_DoEndPathMove(le);
		} else {
			Com_Error(ERR_DROP, "Actor (entnum: %i) on team %i is still moving (%i steps left).  Times: %i, %i, %i",
					le->entnum, le->team, le->pathLength - le->pathPos, le->startTime, le->endTime, cl.time);
		}
	}

	int i = 0;
	/* the end of this event is marked with a 0 */
	while (NET_PeekLong(msg) != 0) {
		NET_ReadByte(msg);
		le->dvtab[i] = NET_ReadShort(msg); /** Don't adjust dv values here- the whole thing is needed to move the actor! */
		le->speed[i] = NET_ReadShort(msg);
		le->pathContents[i] = NET_ReadShort(msg);
		i++;
	}
	le->pathLength = i;

	if (le->pathLength > MAX_ROUTE)
		Com_Error(ERR_DROP, "Overflow in pathLength (entnum: %i)", number);

	/* skip the end of move marker */
	NET_ReadLong(msg);
	/* Also get the final position */
	NET_ReadGPos(msg, le->newPos);

	if (VectorCompare(le->newPos, le->pos))
		Com_Error(ERR_DROP, "start and end pos are the same (entnum: %i)", number);

	/* activate PathMove function */
	le->resetFloor();
	if (LE_IsInvisible(le))
		/* Hack: this relies on the visibility events interrupting the EV_ACTOR_MOVE event */
		LE_SetThink(le, LET_HiddenMove);
	else
		LE_SetThink(le, LET_StartPathMove);
	le->pathPos = 0;
	le->startTime = cl.time;
	le->endTime = cl.time;
}
Example #2
0
/**
 * @brief Change the animation of an actor to the idle animation (which can be
 * panic, dead or stand)
 * @note We have more than one animation for dead - the index is given by the
 * state of the local entity
 * @note Think function
 * @note See the *.anm files in the models dir
 */
void LET_StartIdle (le_t* le)
{
	/* hidden actors don't have models assigned, thus we can not change the
	 * animation for any model */
	if (!LE_IsInvisible(le)) {
		if (LE_IsDead(le))
			R_AnimChange(&le->as, le->model1, va("dead%i", LE_GetAnimationIndexForDeath(le)));
		else if (LE_IsPanicked(le))
			R_AnimChange(&le->as, le->model1, "panic0");
		else
			R_AnimChange(&le->as, le->model1, LE_GetAnim("stand", le->right, le->left, le->state));
	}

	le->pathPos = le->pathLength = 0;
	if (le->stepList != nullptr) {
		leStep_t* step = le->stepList->next;
		Mem_Free(le->stepList);
		le->stepList = step;
		if (step != nullptr) {
			le->stepIndex--;
		} else if (le->stepIndex != 0) {
			Com_Error(ERR_DROP, "stepindex for entnum %i is out of sync (%i should be 0)\n", le->entnum, le->stepIndex);
		}
	}

	/* keep this animation until something happens */
	LE_SetThink(le, nullptr);
}
Example #3
0
/**
 * @brief Checks whether the given le is a living and visible actor
 * @param[in] le The local entity to perform the check for
 * @sa G_IsLivingActor
 * @sa LE_IsActor
 */
bool LE_IsLivingAndVisibleActor (const le_t* le)
{
	assert(le);
	if (LE_IsInvisible(le))
		return false;

	assert(le->type != ET_ACTORHIDDEN);

	return LE_IsLivingActor(le);
}
Example #4
0
/**
 * @brief Shows a list of current know local entities with type and status
 */
void LE_List_f (void)
{
	Com_Printf("number | entnum | type | inuse | invis | pnum | team | size |  HP | state | level | model/ptl\n");
	for (int i = 0; i < cl.numLEs; i++) {
		le_t& le = cl.LEs[i];
		Com_Printf("#%5i | #%5i | %4i | %5i | %5i | %4i | %4i | %4i | %3i | %5i | %5i | ",
			i, le.entnum, le.type, le.inuse, LE_IsInvisible(&le), le.pnum, le.team,
			le.fieldSize, le.HP, le.state, le.levelflags);
		if (le.type == ET_PARTICLE) {
			if (le.ptl)
				Com_Printf("%s\n", le.ptl->ctrl->name);
			else
				Com_Printf("no ptl\n");
		} else if (le.model1)
			Com_Printf("%s\n", le.model1->name);
		else
			Com_Printf("no mdl\n");
	}
}
Example #5
0
/**
 * @sa CMod_GetMapSize
 * @note we only need to handle the 2d plane and can ignore the z level
 * @param[in] node Node description of the radar
 */
void uiRadarNode::draw (uiNode_t* node)
{
	vec2_t pos;
	vec2_t screenPos;
#ifdef RADARSIZE_DEBUG
	int textposy = 40;
	static const vec4_t red = {1, 0, 0, 0.5};
#endif

	static const vec4_t backgroundColor = {0.0, 0.0, 0.0, 1};
	const float mapWidth = cl.mapData->mapBox.getWidthX();
	const float mapHeight = cl.mapData->mapBox.getWidthY();

	/** @todo use the same coef for x and y */
	const float mapCoefX = (float) node->box.size[0] / (float) mapWidth;
	const float mapCoefY = (float) node->box.size[1] / (float) mapHeight;

	if (cls.state != ca_active)
		return;

	UI_GetNodeAbsPos(node, pos);
	UI_GetNodeScreenPos(node, screenPos);
	R_CleanupDepthBuffer(pos[0], pos[1], node->box.size[0], node->box.size[1]);
	UI_DrawFill(pos[0], pos[1], mapWidth * mapCoefX, mapHeight * mapCoefY, backgroundColor);
#ifndef RADARSIZE_DEBUG
	UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]);
#endif

	/* the cl struct is wiped with every new map */
	if (!cl.radarInitialized) {
		UI_InitRadar(node);
		cl.radarInitialized = true;
	}

	/* update context */
	radar.x = pos[0];
	radar.y = pos[1];
	radar.w = node->box.size[0];
	radar.h = node->box.size[1];
	if (radar.gridWidth < 6)
		radar.gridWidth = 6;
	if (radar.gridHeight < 6)
		radar.gridHeight = 6;

#ifdef RADARSIZE_DEBUG
	UI_DrawStringInBox("f_small", ALIGN_UL, 50, textposy, 500, 25, va("%fx%f %fx%f map", cl.mapData->mapBox.getMinX(), cl.mapData->mapBox.getMinY(), cl.mapData->getMaxX(), cl.mapData->getMaxY()));
	textposy += 25;
	UI_DrawStringInBox("f_small", ALIGN_UL, 50, textposy, 500, 25, va("%fx%f map", mapWidth, mapHeight));
	textposy += 25;
#endif

	/* draw background */
	for (int i = 0; i < radar.numImages; i++) {
		vec2_t imagePos;
		hudRadarImage_t* tile = &radar.images[i];
		int maxlevel = cl_worldlevel->integer;

		/* check the max level value for this map tile */
		if (maxlevel >= tile->maxlevel)
			maxlevel = tile->maxlevel - 1;
		assert(tile->path[maxlevel]);
		imagePos[0] = radar.x + mapCoefX * (tile->mapX - cl.mapData->mapBox.getMinX());
		imagePos[1] = radar.y + mapCoefY * (tile->mapY - cl.mapData->mapBox.getMinY());

		UI_DrawNormImageByName(false, imagePos[0], imagePos[1],
				mapCoefX * tile->mapWidth, mapCoefY * tile->mapHeight,
				0, 0, 0, 0, tile->path[maxlevel]);
#ifdef RADARSIZE_DEBUG
		UI_DrawStringInBox("f_small", ALIGN_UL, 50, textposy, 500, 25, va("%dx%d %dx%d %s", tile->x, tile->y, tile->width, tile->height, tile->path[maxlevel]));
		textposy += 25;
		UI_DrawStringInBox("f_small", ALIGN_UL, imagePos[0], imagePos[1], 500, 25, va("%dx%d", tile->gridX, tile->gridY));
#endif
	}

#ifdef RADARSIZE_DEBUG
	UI_DrawFill(pos[0], pos[1], 100.0f * mapCoefX, 100.0f * mapCoefY, red);
	UI_DrawFill(pos[0], pos[1], UNIT_SIZE * mapCoefX, UNIT_SIZE * mapCoefY, red);
#endif

	le_t* le = nullptr;
	while ((le = LE_GetNextInUse(le))) {
		vec3_t itempos;
		if (LE_IsInvisible(le))
			continue;

		/* convert to radar area coordinates */
		itempos[0] = pos[0] + (le->origin[0] - cl.mapData->mapBox.getMinX()) * mapCoefX;
		itempos[1] = pos[1] + (mapHeight - (le->origin[1] - cl.mapData->mapBox.getMinY())) * mapCoefY;

		switch (le->type) {
		case ET_ACTOR:
		case ET_ACTOR2x2:
			UI_RadarNodeDrawActor(le, itempos);
			break;
		case ET_ITEM:
			UI_RadarNodeDrawItem(le, itempos);
			break;
		default:
			break;
		}
#ifdef RADARSIZE_DEBUG
		UI_DrawStringInBox("f_small", ALIGN_UL, 50, textposy, 500, 25, va("%fx%f %dx%d actor", le->origin[0], le->origin[1], le->pos[0], le->pos[1]));
		textposy += 25;
		UI_DrawFill(itempos[0], itempos[1], UNIT_SIZE * mapCoefX, 1, red);
		UI_DrawFill(itempos[0], itempos[1], 1, UNIT_SIZE * mapCoefY, red);
#endif
	}

#ifndef RADARSIZE_DEBUG
	UI_PopClipRect();
#endif
}
Example #6
0
/**
 * @brief Calculates chance to hit if the actor has a fire mode activated.
 * @param[in] actor The local entity of the actor to calculate the hit probability for.
 * @todo The hit probability should work somewhat differently for splash damage weapons.
 * Since splash damage weapons can deal damage even when they don't directly hit an actor,
 * the hit probability should be defined as the predicted percentage of the maximum splash
 * damage of the firemode, assuming the projectile explodes at the desired location. This
 * means that a percentage should be displayed for EVERY actor in the predicted blast
 * radius. This will likely require specialized code.
 */
int CL_GetHitProbability (const le_t* actor)
{
	assert(actor);
	assert(actor->fd);

	pos3_t toPos;
	if (IS_MODE_FIRE_PENDING(actor->actorMode))
		VectorCopy(actor->mousePendPos, toPos);
	else
		VectorCopy(mousePos, toPos);

	/** @todo use LE_FindRadius */
	const le_t* le = LE_GetFromPos(toPos);
	if (!le)
		return 0;

	/* Target is not visible */
	if  (LE_IsInvisible(le))
		return 0;

	/* or suicide attempted */
	if (LE_IsSelected(le) && !FIRESH_IsMedikit(le->fd))
		return 0;

	vec3_t shooter;
	VectorCopy(actor->origin, shooter);
	vec3_t target;
	VectorCopy(le->origin, target);

	/* Calculate HitZone: */
	const int distx = fabs(shooter[0] - target[0]);
	const int disty = fabs(shooter[1] - target[1]);
	const float distance = sqrtf(distx * distx + disty * disty);
	float pseudosin;
	if (distx > disty)
		pseudosin = distance / distx;
	else
		pseudosin = distance / disty;
	float width = 2 * PLAYER_WIDTH * pseudosin;
	float height = LE_IsCrouched(le) ? PLAYER_CROUCHING_HEIGHT : PLAYER_STANDING_HEIGHT;

	const character_t* chr = CL_ActorGetChr(actor);
	if (!chr)
		Com_Error(ERR_DROP, "No character given for local entity");

	const float acc = GET_ACC(chr->score.skills[ABILITY_ACCURACY],
			actor->fd->weaponSkill ? chr->score.skills[actor->fd->weaponSkill] : 0.0, CL_ActorInjuryModifier(actor, MODIFIER_ACCURACY));

	const float crouch = (LE_IsCrouched(actor) && actor->fd->crouch) ? actor->fd->crouch : 1.0;

	const float commonfactor = crouch * torad * distance;
	const float stdevupdown = (actor->fd->spread[0] * (WEAPON_BALANCE + SKILL_BALANCE * acc)) * commonfactor;
	const float stdevleftright = (actor->fd->spread[1] * (WEAPON_BALANCE + SKILL_BALANCE * acc)) * commonfactor;
	const float hitchance = (stdevupdown > LOOKUP_EPSILON ? CL_LookupErrorFunction(height * 0.3536f / stdevupdown) : 1.0f)
			  * (stdevleftright > LOOKUP_EPSILON ? CL_LookupErrorFunction(width * 0.3536f / stdevleftright) : 1.0f);
	/* 0.3536=sqrt(2)/4 */

	/* Calculate cover: */
	int n = 0;
	height = height / 18;
	width = width / 18;
	target[2] -= UNIT_HEIGHT / 2;
	target[2] += height * 9;
	float perpX = disty / distance * width;
	float perpY = 0 - distx / distance * width;

	target[0] += perpX;
	perpX *= 2;
	target[1] += perpY;
	perpY *= 2;
	target[2] += 6 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[0] += perpX;
	target[1] += perpY;
	target[2] -= 6 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[0] += perpX;
	target[1] += perpY;
	target[2] += 4 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[2] += 4 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[0] -= perpX * 3;
	target[1] -= perpY * 3;
	target[2] -= 12 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[0] -= perpX;
	target[1] -= perpY;
	target[2] += 6 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[0] -= perpX;
	target[1] -= perpY;
	target[2] -= 4 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;
	target[0] -= perpX;
	target[1] -= perpY;
	target[2] += 10 * height;
	if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
		n++;

	return 100 * (hitchance * (0.125) * n);
}
Example #7
0
/**
 * @sa CL_ViewRender
 * @sa CL_AddUGV
 * @sa CL_AddActor
 */
void LE_AddToScene (void)
{
	for (int i = 0; i < cl.numLEs; i++) {
		le_t& le = cl.LEs[i];
		if (le.flags & LE_REMOVE_NEXT_FRAME) {
			le.inuse = false;
			le.flags &= ~LE_REMOVE_NEXT_FRAME;
		}
		if (le.inuse && !LE_IsInvisible(&le)) {
			if (le.flags & LE_CHECK_LEVELFLAGS) {
				if (!((1 << cl_worldlevel->integer) & le.levelflags))
					continue;
			} else if (le.flags & LE_ALWAYS_VISIBLE) {
				/* show them always */
			} else if (le.pos[2] > cl_worldlevel->integer)
				continue;

			entity_t ent(RF_NONE);
			ent.alpha = le.alpha;

			VectorCopy(le.angles, ent.angles);
			ent.model = le.model1;
			ent.skinnum = le.bodySkin;
			ent.lighting = &le.lighting;

			switch (le.contents) {
			/* Only breakables do not use their origin; func_doors and func_rotating do!!!
			 * But none of them have animations. */
			case CONTENTS_SOLID:
			case CONTENTS_DETAIL: /* they use mins/maxs */
				break;
			default:
				/* set entity values */
				R_EntitySetOrigin(&ent, le.origin);
				VectorCopy(le.origin, ent.oldorigin);
				/* store animation values */
				ent.as = le.as;
				break;
			}

			if (LE_IsOriginBrush(&le)) {
				ent.isOriginBrushModel = true;
				R_EntitySetOrigin(&ent, le.origin);
				VectorCopy(le.origin, ent.oldorigin);
			}

			if (LE_IsSelected(&le) && le.clientAction != nullptr) {
				const le_t* action = le.clientAction;
				if (action->inuse && action->type > ET_NULL && action->type < ET_MAX)
					LE_AddEdictHighlight(action);
			}

			/* call add function */
			/* if it returns false, don't draw */
			if (le.addFunc)
				if (!le.addFunc(&le, &ent))
					continue;

			/* add it to the scene */
			R_AddEntity(&ent);

			if (cl_le_debug->integer)
				CL_ParticleSpawn("cross", 0, le.origin);
		}
	}
}