Example #1
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 #2
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 #3
0
/**
 * @brief Collecting stunned aliens and alien bodies after the mission.
 * @param[in] aircraft Pointer to the aircraft with cargo.
 * @sa CL_ParseResults
 * @sa CL_GameAutoGo
 */
void AL_CollectingAliens (aircraft_t *aircraft)
{
	le_t *le = NULL;

	while ((le = LE_GetNextInUse(le))) {
		if (LE_IsActor(le) && LE_IsAlien(le)) {
			assert(le->teamDef);

			if (LE_IsStunned(le))
				AL_AddAlienTypeToAircraftCargo(aircraft, le->teamDef, 1, qfalse);
			else if (LE_IsDead(le))
				AL_AddAlienTypeToAircraftCargo(aircraft, le->teamDef, 1, qtrue);
		}
	}
}
Example #4
0
/**
 * @brief Turns actor.
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg The netchannel message
 */
void CL_ActorDoTurn (const eventRegister_t* self, dbuffer* msg)
{
	int entnum, dir;
	NET_ReadFormat(msg, self->formatString, &entnum, &dir);

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

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

	if (LE_IsDead(le))
		Com_Error(ERR_DROP, "Can't turn, actor dead\n");

	le->angle = dir;
	le->angles[YAW] = directionAngles[le->angle];
}
Example #5
0
static void UI_RadarNodeGetActorColor (const le_t* le, vec4_t color)
{
	const int actorLevel = le->pos[2];
	Vector4Set(color, 0, 1, 0, 1);

	/* use different alpha values for different levels */
	if (actorLevel < cl_worldlevel->integer)
		color[3] = 0.5;
	else if (actorLevel > cl_worldlevel->integer)
		color[3] = 0.3;

	/* use different colors for different teams */
	if (LE_IsCivilian(le)) {
		color[0] = 1;
	} else if (le->team != cls.team) {
		color[1] = 0;
		color[0] = 1;
	}

	/* show dead actors in full black */
	if (LE_IsDead(le)) {
		Vector4Set(color, 0, 0, 0, 0.3);
	}
}
Example #6
0
static void UI_RadarNodeDrawActor (const le_t* le, const vec3_t pos)
{
	vec2_t coords[4];
	vec2_t vertices[4];
	int i;
	const float size = 10;
	const int tileSize = 28;
	int tilePos = 4;
	const image_t* image;
	vec4_t color;
	const float pov = directionAngles[le->angle] * torad + M_PI;

	image = UI_LoadImage("ui/radar");
	if (image == nullptr)
		return;

	/* draw FOV */
	if (!LE_IsDead(le)) {
		vertices[0][0] = - size * 4;
		vertices[0][1] = + 0;
		vertices[1][0] = + size * 4;
		vertices[1][1] = + 0;
		vertices[2][0] = + size * 4;
		vertices[2][1] = - size * 4;
		vertices[3][0] = - size * 4;
		vertices[3][1] = - size * 4;
		coords[0][0] = (7) / 128.0f;
		coords[0][1] = (37 + 63) / 128.0f;
		coords[1][0] = (7 + 114) / 128.0f;
		coords[1][1] = (37 + 63) / 128.0f;
		coords[2][0] = (7 + 114) / 128.0f;
		coords[2][1] = (37) / 128.0f;
		coords[3][0] = (7) / 128.0f;
		coords[3][1] = (37) / 128.0f;

		/* affine transformation */
		for (i = 0; i < 4; i++) {
			const float dx = vertices[i][0];
			const float dy = vertices[i][1];
			vertices[i][0] = pos[0] + dx * sin(pov) + dy * cos(pov);
			vertices[i][1] = pos[1] + dx * cos(pov) - dy * sin(pov);
		}

		UI_RadarNodeGetActorColor(le, color);
		if (LE_IsSelected(le)) {
			color[3] *= 0.75;
		} else {
			color[3] = 0.1f;
		}
		UI_RadarNodeDrawArrays(color, coords, vertices, image);
	}

	if (LE_IsDead(le))
		tilePos = 4;
	else if (LE_IsSelected(le))
		tilePos = 66;
	else
		tilePos = 36;

	/* a 0,0 centered square */
	vertices[0][0] = - size;
	vertices[0][1] = + size;
	vertices[1][0] = + size;
	vertices[1][1] = + size;
	vertices[2][0] = + size;
	vertices[2][1] = - size;
	vertices[3][0] = - size;
	vertices[3][1] = - size;
	coords[0][0] = (tilePos) / 128.0f;
	coords[0][1] = (5 + tileSize) / 128.0f;
	coords[1][0] = (tilePos + tileSize) / 128.0f;
	coords[1][1] = (5 + tileSize) / 128.0f;
	coords[2][0] = (tilePos + tileSize) / 128.0f;
	coords[2][1] = (5) / 128.0f;
	coords[3][0] = (tilePos) / 128.0f;
	coords[3][1] = (5) / 128.0f;

	/* affine transformation */
	for (i = 0; i < 4; i++) {
		const float dx = vertices[i][0];
		const float dy = vertices[i][1];
		vertices[i][0] = pos[0] + dx * sin(pov) + dy * cos(pov);
		vertices[i][1] = pos[1] + dx * cos(pov) - dy * sin(pov);
	}

	UI_RadarNodeGetActorColor(le, color);
	UI_RadarNodeDrawArrays(color, coords, vertices, image);
}
Example #7
0
/**
 * @brief Shoot with weapon.
 * @sa CL_ActorShoot
 * @sa CL_ActorShootHidden
 * @todo Improve detection of left- or right animation.
 * @sa EV_ACTOR_SHOOT
 */
void CL_ActorDoShoot (const eventRegister_t* self, dbuffer* msg)
{
	vec3_t muzzle, impact;
	int flags, normal, shooterEntnum, victimEntnum;
	int objIdx;
	int first;
	weaponFireDefIndex_t weapFdsIdx;
	fireDefIndex_t fdIdx;
	int surfaceFlags;
	shoot_types_t shootType;

	/* read data */
	NET_ReadFormat(msg, self->formatString, &shooterEntnum, &victimEntnum, &first, &objIdx, &weapFdsIdx, &fdIdx, &shootType, &flags, &surfaceFlags, &muzzle, &impact, &normal);

	le_t* leVictim;
	if (victimEntnum != SKIP_LOCAL_ENTITY) {
		leVictim = LE_Get(victimEntnum);
		if (!leVictim)
			LE_NotFoundError(victimEntnum);
	} else {
		leVictim = nullptr;
	}

	/* get shooter le */
	le_t* leShooter = LE_Get(shooterEntnum);

	/* get the fire def */
	const objDef_t* obj = INVSH_GetItemByIDX(objIdx);
	const fireDef_t* fd = FIRESH_GetFiredef(obj, weapFdsIdx, fdIdx);

	CL_ActorGetMuzzle(leShooter, muzzle, shootType);

	/* add effect le */
	LE_AddProjectile(fd, flags, muzzle, impact, normal, leVictim);

	/* start the sound */
	if ((first || !fd->soundOnce) && fd->fireSound != nullptr && !(flags & SF_BOUNCED))
		S_LoadAndPlaySample(fd->fireSound, muzzle, fd->fireAttenuation, SND_VOLUME_WEAPONS);

	/* do actor related stuff */
	if (!leShooter)
		return; /* maybe hidden or inuse is false? */

	if (!LE_IsActor(leShooter))
		Com_Error(ERR_DROP, "Can't shoot, LE not an actor (type: %i)", leShooter->type);

	/* no animations for hidden actors */
	if (leShooter->type == ET_ACTORHIDDEN)
		return;

	if (LE_IsDead(leShooter)) {
		Com_DPrintf(DEBUG_CLIENT, "Can't shoot, actor dead or stunned.\n");
		return;
	}

	/* Animate - we have to check if it is right or left weapon usage. */
	if (IS_SHOT_RIGHT(shootType)) {
		R_AnimChange(&leShooter->as, leShooter->model1, LE_GetAnim("shoot", leShooter->right, leShooter->left, leShooter->state));
		R_AnimAppend(&leShooter->as, leShooter->model1, LE_GetAnim("stand", leShooter->right, leShooter->left, leShooter->state));
	} else if (IS_SHOT_LEFT(shootType)) {
		R_AnimChange(&leShooter->as, leShooter->model1, LE_GetAnim("shoot", leShooter->left, leShooter->right, leShooter->state));
		R_AnimAppend(&leShooter->as, leShooter->model1, LE_GetAnim("stand", leShooter->left, leShooter->right, leShooter->state));
	} else if (IS_SHOT_HEADGEAR(shootType)) {
		if (fd->irgoggles) {
			leShooter->state |= RF_IRGOGGLESSHOT;
			if (LE_IsSelected(leShooter))
				refdef.rendererFlags |= RDF_IRGOGGLES;
		}
	} else {
		/* no animation for headgear (yet) */
		Com_Error(ERR_DROP, "CL_ActorDoShoot: Invalid shootType given (entnum: %i, shootType: %i).\n", shootType, shooterEntnum);
	}
}
Example #8
0
/**
 * @brief Adds an UGV to the render entities.
 * @param[in] le The local entity the UGV should be created from
 * @param[out] ent
 * @sa CL_AddActor
 */
bool CL_AddUGV (le_t * le, entity_t * ent)
{
	entity_t add;

	if (!LE_IsDead(le)) {
		/* add weapon */
		if (le->left != NONE) {
			OBJZERO(add);

			add.model = cls.modelPool[le->left];

			add.tagent = R_GetFreeEntity() + 2 + (le->right != NONE);
			add.tagname = "tag_lweapon";

			R_AddEntity(&add);
		}

		/* add weapon */
		if (le->right != NONE) {
			OBJZERO(add);

			add.alpha = le->alpha;
			add.model = cls.modelPool[le->right];

			add.tagent = R_GetFreeEntity() + 2;
			add.tagname = "tag_rweapon";

			R_AddEntity(&add);
		}
	}

	/* add head */
	OBJZERO(add);

	add.alpha = le->alpha;
	add.model = le->model2;
	add.skinnum = le->bodySkin;

	/** @todo */
	add.tagent = R_GetFreeEntity() + 1;
	add.tagname = "tag_head";

	R_AddEntity(&add);

	/* add actor special effects */
	ent->flags |= RF_SHADOW;
	ent->flags |= RF_ACTOR;

	if (!LE_IsDead(le)) {
		if (LE_IsSelected(le))
			ent->flags |= RF_SELECTED;
		if (le->team == cls.team) {
			if (le->pnum == cl.pnum)
				ent->flags |= RF_MEMBER;
			if (le->pnum != cl.pnum)
				ent->flags |= RF_ALLIED;
		}
		if (le->team == TEAM_CIVILIAN)
			ent->flags |= RF_NEUTRAL;
	}

	return true;
}
Example #9
0
/**
 * @brief Kills an actor (all that is needed is the local entity state set to STATE_DEAD).
 * @note Also changes the animation to a random death sequence and appends the dead animation
 * @param[in] msg The netchannel message
 * @param[in] self Pointer to the event structure that is currently executed
 */
void CL_ActorDie (const eventRegister_t *self, dbuffer *msg)
{
	le_t *le;
	int entnum, state, playerNum;

	NET_ReadFormat(msg, self->formatString, &entnum, &state, &playerNum);

	/* get les */
	le = LE_Get(entnum);

	if (!le)
		LE_NotFoundError(entnum);

	if (!LE_IsLivingActor(le))
		Com_Error(ERR_DROP, "CL_ActorDie: Can't kill, LE is not an actor (type: %i)", le->type);

	if (!LE_IsStunned(le) && LE_IsDead(le))
		Com_Error(ERR_DROP, "CL_ActorDie: Can't kill, actor already dead");

	LE_Lock(le);

	/* set relevant vars */
	FLOOR(le) = NULL;

	le->state = state;

	/* count spotted aliens */
	cl.numEnemiesSpotted = CL_CountVisibleEnemies();

	/* play animation */
	LE_SetThink(le, NULL);
	R_AnimChange(&le->as, le->model1, va("death%i", LE_GetAnimationIndexForDeath(le)));
	R_AnimAppend(&le->as, le->model1, va("dead%i", LE_GetAnimationIndexForDeath(le)));

	/* Print some info about the death or stun. */
	if (le->team == cls.team) {
		if (playerNum != le->pnum) {
			const char *playerName = CL_PlayerGetName(playerNum);
			char tmpbuf[128];
			Com_sprintf(tmpbuf, lengthof(tmpbuf), _("%s lost a soldier\n"), playerName);
			HUD_DisplayMessage(tmpbuf);
		} else {
			const character_t *chr = CL_ActorGetChr(le);
			if (chr) {
				char tmpbuf[128];
				if (LE_IsStunned(le)) {
					Com_sprintf(tmpbuf, lengthof(tmpbuf), _("%s was stunned\n"), chr->name);
				} else {
					Com_sprintf(tmpbuf, lengthof(tmpbuf), _("%s was killed\n"), chr->name);
				}
				HUD_DisplayMessage(tmpbuf);
			}
		}
	} else {
		switch (le->team) {
		case (TEAM_CIVILIAN):
			if (LE_IsStunned(le))
				HUD_DisplayMessage(_("A civilian was stunned."));
			else
				HUD_DisplayMessage(_("A civilian was killed."));
			break;
		case (TEAM_ALIEN):
			if (LE_IsStunned(le))
				HUD_DisplayMessage(_("An alien was stunned."));
			else
				HUD_DisplayMessage(_("An alien was killed."));
			break;
		case (TEAM_PHALANX):
			if (LE_IsStunned(le))
				HUD_DisplayMessage(_("A soldier was stunned."));
			else
				HUD_DisplayMessage(_("A soldier was killed."));
			break;
		default:
			if (LE_IsStunned(le))
				HUD_DisplayMessage(va(_("A member of team %i was stunned."), le->team));
			else
				HUD_DisplayMessage(va(_("A member of team %i was killed."), le->team));
			break;
		}
	}

	/**
	 * @todo CHRSH_IsTeamDefRobot: spawn smoke particles for robots
	 */

	CL_ActorPlaySound(le, SND_DEATH);

	VectorCopy(player_dead_maxs, le->maxs);
	if (!LE_IsStunned(le))
		le->contents = CONTENTS_DEADACTOR;
	CL_ActorRemoveFromTeamList(le);

	/* update pathing as we maybe can walk onto the dead actor now */
	CL_ActorConditionalMoveCalc(selActor);
	LE_Unlock(le);
}
/**
 * @sa CL_ActorAddToTeamList
 * @sa G_AppearPerishEvent
 * @sa CL_ActorAdd
 * @note EV_ACTOR_APPEAR
 */
void CL_ActorAppear (const eventRegister_t *self, struct dbuffer *msg)
{
	le_t *le, *leResponsible;
	int entnum, entnumResponsible, modelnum1, modelnum2;
	int teamDefID = -1;

	/* check if the actor is already visible */
	entnum = NET_ReadShort(msg);
	entnumResponsible = NET_ReadShort(msg);
	le = LE_Get(entnum);
	leResponsible = LE_Get(entnumResponsible);

	if (entnumResponsible != SKIP_LOCAL_ENTITY && !leResponsible)
		LE_NotFoundError(entnumResponsible);

	/* mission start - no actor is spawned yet - so create it */
	if (!le)
		le = LE_Add(entnum);

	/* Locking should be unnecessary if CL_CheckDefault filters this call, since this event starts and
	 * ends in this function only.  Adding lock/unlock just to be sure. */
	LE_Lock(le);

	/* maybe added via CL_ActorAdd before */
	le->invis = false;

	/* get the info */
	NET_ReadFormat(msg, self->formatString,
			&le->team, &teamDefID, &le->gender, &le->ucn, &le->pnum, &le->pos,
			&le->angle, &le->right, &le->left,
			&modelnum1, &modelnum2, &le->bodySkin, &le->headSkin,
			&le->state, &le->fieldSize,
			&le->maxTU, &le->maxMorale, &le->maxHP);

	if (teamDefID < 0 || teamDefID > csi.numTeamDefs)
		Com_Printf("CL_ActorAppear: Invalid teamDef index\n");
	else
		le->teamDef = &csi.teamDef[teamDefID];

	switch (le->fieldSize) {
	case ACTOR_SIZE_NORMAL:
		le->addFunc = CL_AddActor;
		le->type = ET_ACTOR;
		break;
	case ACTOR_SIZE_2x2:
		le->addFunc = CL_AddUGV;
		le->type = ET_ACTOR2x2;
		break;
	default:
		Com_Error(ERR_DROP, "Unknown fieldSize for le in CL_ActorAppear (EV_ACTOR_APPEAR)");
	}
	le->modelnum1 = modelnum1;
	le->modelnum2 = modelnum2;
	le->model1 = LE_GetDrawModel(modelnum1);
	le->model2 = LE_GetDrawModel(modelnum2);
	Grid_PosToVec(cl.mapData->map, le->fieldSize, le->pos, le->origin);
	le->angles[YAW] = directionAngles[le->angle];

	if (LE_IsDead(le) && !LE_IsStunned(le))
		le->contents = CONTENTS_DEADACTOR;
	else
		le->contents = CONTENTS_ACTOR;
	VectorCopy(player_mins, le->mins);
	if (LE_IsDead(le))
		VectorCopy(player_dead_maxs, le->maxs);
	else
		VectorCopy(player_maxs, le->maxs);

	LE_SetThink(le, LET_StartIdle);

	/* count spotted aliens (also stunned) */
	cl.numEnemiesSpotted = CL_CountVisibleEnemies();

	if (LE_IsLivingActor(le)) {
		if (cl.actTeam != cls.team) {
			/* center view (if wanted) */
			LE_CenterView(le);
		}

		/* draw line of sight */
		if (le->team != cls.team) {
			if (leResponsible)
				CL_DrawLineOfSight(leResponsible, le);

			/* message */
			if (le->team != TEAM_CIVILIAN) {
				if (GAME_TeamIsKnown(le->teamDef)) {
					char tmpbuf[128];
					Com_sprintf(tmpbuf, sizeof(tmpbuf), _("Enemy spotted: %s!"), _(le->teamDef->name));
					HUD_DisplayMessage(tmpbuf);
				} else
					HUD_DisplayMessage(_("Unknown enemy spotted!"));
			} else
				HUD_DisplayMessage(_("Civilian spotted."));

			/* update pathing as new actor could block path */
			CL_ActorConditionalMoveCalc(leResponsible ? leResponsible : selActor);
		}
	}

	/* add team members to the actor list */
	CL_ActorAddToTeamList(le);
	LE_Unlock(le);
}
Example #11
0
/**
 * @brief Checks whether the given le is a living actor (but might be hidden)
 * @param[in] le The local entity to perform the check for
 * @sa G_IsLivingActor
 * @sa LE_IsActor
 */
bool LE_IsLivingActor (const le_t* le)
{
	assert(le);
	return LE_IsActor(le) && (LE_IsStunned(le) || !LE_IsDead(le));
}