UFO: Alien Invasion
Loading...
Searching...
No Matches
e_event_actorshoot.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "../../../../client.h"
29#include "e_event_actorshoot.h"
30
36int CL_ActorDoShootTime (const eventRegister_t* self, dbuffer* msg, eventTiming_t* eventTiming)
37{
38 int flags, dummy;
39 int objIdx, surfaceFlags;
40 int weap_fds_idx, fd_idx;
41 shoot_types_t shootType;
42 vec3_t muzzle, impact;
43 int eventTime = eventTiming->shootTime;
44
45 /* read data */
46 NET_ReadFormat(msg, self->formatString, &dummy, &dummy, &dummy, &objIdx, &weap_fds_idx, &fd_idx, &shootType, &flags,
47 &surfaceFlags, &muzzle, &impact, &dummy);
48
49 const objDef_t* obj = INVSH_GetItemByIDX(objIdx);
50 const fireDef_t* fd = FIRESH_GetFiredef(obj, weap_fds_idx, fd_idx);
51
52 if (!(flags & SF_BOUNCED)) {
53 /* shooting */
54 if (fd->speed > 0.0 && !CL_OutsideMap(impact, UNIT_SIZE * 10)) {
55 eventTiming->impactTime = eventTiming->shootTime + 1000 * VectorDist(muzzle, impact) / fd->speed;
56 } else {
57 eventTiming->impactTime = eventTiming->shootTime;
58 }
59 if (!cls.isOurRound())
60 eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->impactTime + 1400);
61 else
62 eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->impactTime + 400);
63 if (fd->delayBetweenShots > 0.0)
64 eventTiming->shootTime += 1000 / fd->delayBetweenShots;
65 } else {
66 /* only a bounced shot */
67 eventTime = eventTiming->impactTime;
68 if (fd->speed > 0.0) {
69 eventTiming->impactTime += 1000 * VectorDist(muzzle, impact) / fd->speed;
70 eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->impactTime);
71 }
72 }
73 eventTiming->parsedDeath = false;
74
75 return eventTime;
76}
77
88static void CL_ActorGetMuzzle (const le_t* actor, vec3_t muzzle, shoot_types_t shootType)
89{
90 if (actor == nullptr)
91 return;
92
93 const Item* weapon;
94 const char* tag;
95 if (IS_SHOT_RIGHT(shootType)) {
96 tag = "tag_rweapon";
97 weapon = actor->getRightHandItem();
98 } else {
99 tag = "tag_lweapon";
100 weapon = actor->getLeftHandItem();
101 }
102
103 if (!weapon || !weapon->def())
104 return;
105
106 const objDef_t* od = weapon->def();
107 const model_t* model = cls.modelPool[od->idx];
108 if (!model)
109 Com_Error(ERR_DROP, "Model for item %s is not precached", od->id);
110
111 /* not every weapon has a muzzle tag assigned */
112 if (R_GetTagIndexByName(model, "tag_muzzle") == -1)
113 return;
114
115 float modifiedMatrix[16];
116 if (!R_GetTagMatrix(actor->model1, tag, actor->as.frame, modifiedMatrix))
117 Com_Error(ERR_DROP, "Could not find tag %s for actor model %s", tag, actor->model1->name);
118
119 float mc[16];
120 GLMatrixAssemble(actor->origin, actor->angles, mc);
121
122 float matrix[16];
123 GLMatrixMultiply(mc, modifiedMatrix, matrix);
124
125 R_GetTagMatrix(model, "tag_muzzle", 0, modifiedMatrix);
126 GLMatrixMultiply(matrix, modifiedMatrix, mc);
127
128 muzzle[0] = mc[12];
129 muzzle[1] = mc[13];
130 muzzle[2] = mc[14];
131}
132
141{
142 vec3_t muzzle, impact;
143 int flags, normal, shooterEntnum, victimEntnum;
144 int objIdx;
145 int first;
146 weaponFireDefIndex_t weapFdsIdx;
147 fireDefIndex_t fdIdx;
148 int surfaceFlags;
149 shoot_types_t shootType;
150
151 /* read data */
152 NET_ReadFormat(msg, self->formatString, &shooterEntnum, &victimEntnum, &first, &objIdx, &weapFdsIdx, &fdIdx, &shootType, &flags, &surfaceFlags, &muzzle, &impact, &normal);
153
154 le_t* leVictim;
155 if (victimEntnum != SKIP_LOCAL_ENTITY) {
156 leVictim = LE_Get(victimEntnum);
157 if (!leVictim)
158 LE_NotFoundError(victimEntnum);
159 } else {
160 leVictim = nullptr;
161 }
162
163 /* get shooter le */
164 le_t* leShooter = LE_Get(shooterEntnum);
165
166 /* get the fire def */
167 const objDef_t* obj = INVSH_GetItemByIDX(objIdx);
168 const fireDef_t* fd = FIRESH_GetFiredef(obj, weapFdsIdx, fdIdx);
169
170 CL_ActorGetMuzzle(leShooter, muzzle, shootType);
171
172 /* add effect le */
173 LE_AddProjectile(fd, flags, muzzle, impact, normal, leVictim);
174
175 /* start the sound */
176 if ((first || !fd->soundOnce) && fd->fireSound != nullptr && !(flags & SF_BOUNCED))
178
179 /* do actor related stuff */
180 if (!leShooter)
181 return; /* maybe hidden or inuse is false? */
182
183 if (!LE_IsActor(leShooter))
184 Com_Error(ERR_DROP, "Can't shoot, LE not an actor (type: %i)", leShooter->type);
185
186 /* no animations for hidden actors */
187 if (leShooter->type == ET_ACTORHIDDEN)
188 return;
189
190 if (LE_IsDead(leShooter)) {
191 Com_DPrintf(DEBUG_CLIENT, "Can't shoot, actor dead or stunned.\n");
192 return;
193 }
194
195 /* Animate - we have to check if it is right or left weapon usage. */
196 if (IS_SHOT_RIGHT(shootType)) {
197 R_AnimChange(&leShooter->as, leShooter->model1, LE_GetAnim("shoot", leShooter->right, leShooter->left, leShooter->state));
198 R_AnimAppend(&leShooter->as, leShooter->model1, LE_GetAnim("stand", leShooter->right, leShooter->left, leShooter->state));
199 } else if (IS_SHOT_LEFT(shootType)) {
200 R_AnimChange(&leShooter->as, leShooter->model1, LE_GetAnim("shoot", leShooter->left, leShooter->right, leShooter->state));
201 R_AnimAppend(&leShooter->as, leShooter->model1, LE_GetAnim("stand", leShooter->left, leShooter->right, leShooter->state));
202 } else if (IS_SHOT_HEADGEAR(shootType)) {
203 if (fd->irgoggles) {
204 leShooter->state |= RF_IRGOGGLESSHOT;
205 if (LE_IsSelected(leShooter))
206 refdef.rendererFlags |= RDF_IRGOGGLES;
207 }
208 } else {
209 /* no animation for headgear (yet) */
210 Com_Error(ERR_DROP, "CL_ActorDoShoot: Invalid shootType given (entnum: %i, shootType: %i).\n", shootType, shooterEntnum);
211 }
212}
bool CL_OutsideMap(const vec3_t position, const float delta)
Checks whether give position is still inside the map borders.
void LE_AddProjectile(const fireDef_t *fd, int flags, const vec3_t muzzle, const vec3_t impact, int normal, le_t *leVictim)
le_t * LE_Get(int entnum)
Searches all local entities for the one with the searched entnum.
bool LE_IsActor(const le_t *le)
Checks whether the given le is a living actor.
const char * LE_GetAnim(const char *anim, int right, int left, int state)
Get the correct animation for the given actor state and weapons.
#define LE_IsDead(le)
#define LE_IsSelected(le)
#define LE_NotFoundError(entnum)
client_static_t cls
Definition cl_main.cpp:83
#define RDF_IRGOGGLES
Definition cl_renderer.h:35
rendererData_t refdef
Definition r_main.cpp:45
item instance data, with linked list capability
Definition inv_shared.h:402
const objDef_t * def(void) const
Definition inv_shared.h:469
Primary header for client.
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
#define ERR_DROP
Definition common.h:211
#define DEBUG_CLIENT
Definition defines.h:59
#define UNIT_SIZE
Definition defines.h:121
int CL_ActorDoShootTime(const eventRegister_t *self, dbuffer *msg, eventTiming_t *eventTiming)
Decides if following events should be delayed. If the projectile has a speed value assigned,...
void CL_ActorDoShoot(const eventRegister_t *self, dbuffer *msg)
Shoot with weapon.
static void CL_ActorGetMuzzle(const le_t *actor, vec3_t muzzle, shoot_types_t shootType)
Calculates the muzzle for the current weapon the actor is shooting with.
int CL_GetNextTime(const eventRegister_t *event, eventTiming_t *eventTiming, int nextTime)
Definition e_main.cpp:203
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
const fireDef_t * FIRESH_GetFiredef(const objDef_t *obj, const weaponFireDefIndex_t weapFdsIdx, const fireDefIndex_t fdIdx)
Get the fire definitions for a given object.
int32_t weaponFireDefIndex_t
Definition inv_shared.h:77
int32_t fireDefIndex_t
Definition inv_shared.h:78
void GLMatrixAssemble(const vec3_t origin, const vec3_t angles, float *matrix)
Builds an opengl translation and rotation matrix.
Definition mathlib.cpp:325
void GLMatrixMultiply(const float a[16], const float b[16], float c[16])
Multiply 4*4 matrix by 4*4 matrix.
Definition mathlib.cpp:350
void NET_ReadFormat(dbuffer *buf, const char *format,...)
The user-friendly version of NET_ReadFormat that reads variable arguments from a buffer according to ...
Definition netpack.cpp:533
#define SKIP_LOCAL_ENTITY
Definition q_shared.h:255
#define IS_SHOT_RIGHT(x)
Determine whether the selected shoot type is for the item in the right hand, either shooting or react...
Definition q_shared.h:243
#define SF_BOUNCED
Definition q_shared.h:251
#define IS_SHOT_HEADGEAR(x)
Determine whether the selected shoot type is for the item in the headgear slot.
Definition q_shared.h:245
@ ET_ACTORHIDDEN
Definition q_shared.h:163
int32_t shoot_types_t
Available shoot types - also see the ST_ constants.
Definition q_shared.h:206
#define IS_SHOT_LEFT(x)
Determine whether the selected shoot type is for the item in the left hand, either shooting or reacti...
Definition q_shared.h:241
#define RF_IRGOGGLESSHOT
Definition r_entity.h:52
bool R_GetTagMatrix(const model_t *mod, const char *tagName, int frame, float matrix[16])
Definition r_mesh.cpp:189
int R_GetTagIndexByName(const model_t *mod, const char *tagName)
Searches the tag data for the given name.
Definition r_mesh.cpp:247
void R_AnimChange(animState_t *as, const model_t *mod, const char *name)
Changes the animation for md2 models.
void R_AnimAppend(animState_t *as, const model_t *mod, const char *name)
Appends a new animation to the current running one.
bool S_LoadAndPlaySample(const char *s, const vec3_t origin, float attenuation, float volume)
does what the name implies in just one function to avoid exposing s_sample_t
Definition s_main.cpp:307
#define SND_VOLUME_WEAPONS
Definition s_main.h:43
Struct that defines one particular event with all its callbacks and data.
Definition e_main.h:42
const char * formatString
The format string that is used to write and parse this event.
Definition e_main.h:54
CL_ParseEvent timers and vars.
Definition e_main.h:30
int shootTime
Definition e_main.h:32
int nextTime
Definition e_main.h:31
int impactTime
Definition e_main.h:33
bool parsedDeath
Definition e_main.h:35
this is a fire definition for our weapons/ammo
Definition inv_shared.h:110
float fireAttenuation
Definition inv_shared.h:120
const char * fireSound
Definition inv_shared.h:117
bool irgoggles
Definition inv_shared.h:140
float speed
Definition inv_shared.h:143
float delayBetweenShots
Definition inv_shared.h:155
bool soundOnce
Definition inv_shared.h:135
a local entity
int state
Item * getLeftHandItem() const
float angles[3]
vec3_t origin
Item * getRightHandItem() const
animState_t as
model_t * model1
entity_type_t type
char name[MAX_QPATH]
Definition r_model.h:44
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
const char * id
Definition inv_shared.h:268
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorDist(a, b)
Definition vector.h:69