/** * @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); } }
/** * @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); }