openmohaa/code/cgame/cg_parsemsg.cpp

2068 lines
68 KiB
C++
Raw Normal View History

2023-04-30 14:15:14 +02:00
/*
===========================================================================
Copyright (C) 2024 the OpenMoHAA team
2023-04-30 14:15:14 +02:00
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// DESCRIPTION:
// CGM buffer parser
2023-05-01 00:08:43 +02:00
#include "cg_local.h"
#include "cg_parsemsg.h"
2023-05-04 20:30:52 +02:00
#include "cg_specialfx.h"
#include "str.h"
extern int current_entity_number;
typedef struct {
2023-07-05 21:24:23 +02:00
vec3_t i_vBarrel;
vec3_t i_vStart;
vec3_t *i_vEnd;
int i_iNumBullets;
2023-05-04 20:30:52 +02:00
qboolean iLarge;
float alpha;
2023-07-05 21:24:23 +02:00
int iTracerVisible;
2023-05-04 20:30:52 +02:00
qboolean bIgnoreEntities;
} bullet_tracer_t;
2023-07-05 21:24:23 +02:00
#define MAX_BULLET_TRACERS 32
2023-05-04 21:07:44 +02:00
#define MAX_BULLET_TRACE_BULLETS 1024
2023-07-05 21:24:23 +02:00
#define MAX_IMPACTS 64
static constexpr unsigned int BULLET_TRAVEL_DIST = 9216;
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
static int bullet_tracers_count;
static int bullet_tracer_bullets_count;
static int wall_impact_count;
static int flesh_impact_count;
2023-05-04 21:07:44 +02:00
static bullet_tracer_t bullet_tracers[MAX_BULLET_TRACERS];
2023-07-05 21:24:23 +02:00
static vec3_t bullet_tracer_bullets[MAX_BULLET_TRACE_BULLETS];
static vec3_t wall_impact_pos[MAX_IMPACTS];
static vec3_t wall_impact_norm[MAX_IMPACTS];
static int wall_impact_large[MAX_IMPACTS];
static int wall_impact_type[MAX_IMPACTS];
static vec3_t flesh_impact_pos[MAX_IMPACTS];
static vec3_t flesh_impact_norm[MAX_IMPACTS];
static int flesh_impact_large[MAX_IMPACTS];
void CG_MakeBulletHoleSound(const vec3_t i_vPos, const vec3_t i_vNorm, int iLarge, trace_t *pPreTrace)
{
int iSurfType;
float fVolume;
str sSoundName;
vec3_t vFrom, vDest;
2023-07-10 23:58:05 +02:00
trace_t trace;
if (pPreTrace) {
trace = *pPreTrace;
} else {
2023-07-10 23:58:05 +02:00
VectorMA(i_vPos, 2.0f, i_vNorm, vFrom);
VectorMA(i_vPos, -4.0f, i_vNorm, vDest);
CG_Trace(
&trace, vFrom, vec_zero, vec_zero, vDest, ENTITYNUM_NONE, MASK_SHOT, qfalse, qtrue, "CG_MakeBulletHole"
);
2023-07-10 23:58:05 +02:00
}
iSurfType = trace.surfaceFlags & MASK_SURF_TYPE;
if (trace.contents & CONTENTS_WATER) {
iSurfType = SURF_PUDDLE;
}
if (trace.fraction == 1.0f || trace.startsolid || (trace.surfaceFlags & SURF_SKY)) {
return;
}
VectorAdd(trace.endpos, trace.plane.normal, vFrom);
sSoundName = "snd_bh_";
switch (iSurfType) {
case SURF_FOLIAGE:
sSoundName += "foliage";
break;
case SURF_SNOW:
sSoundName += "snow";
break;
case SURF_CARPET:
sSoundName += "carpet";
break;
case SURF_SAND:
sSoundName += "sand";
break;
case SURF_PUDDLE:
sSoundName += "puddle";
break;
case SURF_GLASS:
sSoundName += "glass";
break;
case SURF_GRAVEL:
sSoundName += "gravel";
break;
case SURF_MUD:
sSoundName += "mud";
break;
case SURF_DIRT:
sSoundName += "dirt";
break;
case SURF_GRILL:
sSoundName += "grill";
break;
case SURF_GRASS:
sSoundName += "grass";
break;
case SURF_ROCK:
sSoundName += "stone";
break;
case SURF_PAPER:
sSoundName += "paper";
break;
case SURF_WOOD:
sSoundName += "wood";
break;
case SURF_METAL:
sSoundName += "metal";
break;
default:
sSoundName += "stone";
break;
}
if (iLarge) {
fVolume = 1.0f;
} else {
fVolume = 0.75f;
}
commandManager.PlaySound(sSoundName, vFrom, -1, fVolume, -1.f, -1.f, 1);
}
static void CG_MakeBulletHoleType(
const vec3_t i_vPos, const vec3_t i_vNorm, int iLarge, int iEffectNum, float fRadius, qboolean bMakeSound
)
{
if (bMakeSound) {
str sBulletHole = "snd_bh_";
float fVolume;
switch (iEffectNum) {
2024-02-12 00:17:30 +01:00
case SFX_BHIT_PAPER_LITE:
sBulletHole += "paper";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_WOOD_LITE:
sBulletHole += "wood";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_METAL_LITE:
sBulletHole += "metal";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_STONE_LITE:
sBulletHole += "stone";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_DIRT_LITE:
sBulletHole += "dirt";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_GRILL_LITE:
sBulletHole += "grill";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_GRASS_LITE:
sBulletHole += "grass";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_MUD_LITE:
sBulletHole += "mud";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_PUDDLE_LITE:
sBulletHole += "puddle";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_GLASS_LITE:
sBulletHole += "glass";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_GRAVEL_LITE:
sBulletHole += "gravel";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_SAND_LITE:
sBulletHole += "sand";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_FOLIAGE_LITE:
sBulletHole += "foliage";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_SNOW_LITE:
sBulletHole += "snow";
break;
2024-02-12 00:17:30 +01:00
case SFX_BHIT_CARPET_LITE:
sBulletHole += "carpet";
break;
default:
sBulletHole += "stone";
break;
}
if (iLarge) {
fVolume = 1.0f;
} else {
fVolume = 0.75f;
}
commandManager.PlaySound(sBulletHole, i_vPos, -1, fVolume, -1.f, -1.f, 1);
}
if (iLarge) {
iEffectNum++;
}
sfxManager.MakeEffect_Normal(iEffectNum, i_vPos, i_vNorm);
}
static void
CG_MakeBulletHole(const vec3_t i_vPos, const vec3_t i_vNorm, int iLarge, trace_t *pPreTrace, qboolean bMakeSound)
{
int iSurfType;
int iEffect;
float fRadius;
str sEffectModel;
str sBulletHole;
vec3_t vFrom, vDest;
trace_t trace;
if (pPreTrace) {
trace = *pPreTrace;
} else {
VectorMA(i_vPos, 2.0f, i_vNorm, vFrom);
VectorMA(i_vPos, -4.0f, i_vNorm, vDest);
CG_Trace(
&trace, vFrom, vec_zero, vec_zero, vDest, ENTITYNUM_NONE, MASK_SHOT, qfalse, qtrue, "CG_MakeBulletHole"
);
}
iSurfType = trace.surfaceFlags & MASK_SURF_TYPE;
if (trace.contents & CONTENTS_WATER) {
iSurfType = SURF_PUDDLE;
}
2023-07-10 23:58:05 +02:00
if (trace.fraction == 1.0f || trace.startsolid || (trace.surfaceFlags & SURF_SKY)) {
return;
}
VectorAdd(trace.endpos, trace.plane.normal, vFrom);
fRadius = 2.0f;
sBulletHole = "bhole_";
switch (iSurfType) {
case SURF_FOLIAGE:
fRadius = 0.f;
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_FOLIAGE_LITE;
break;
case SURF_SNOW:
sBulletHole += "snow";
iEffect = SFX_BHIT_SNOW_LITE;
break;
case SURF_CARPET:
sBulletHole += "carpet";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_CARPET_LITE;
break;
case SURF_SAND:
fRadius = 0.f;
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_SAND_LITE;
break;
case SURF_PUDDLE:
fRadius = 0.f;
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_PUDDLE_LITE;
break;
case SURF_GLASS:
sBulletHole += "glass";
2024-02-12 00:18:18 +01:00
iEffect = SFX_BHIT_GLASS_LITE;
break;
case SURF_GRAVEL:
fRadius = 0.f;
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_GRAVEL_LITE;
break;
case SURF_MUD:
sBulletHole += "mud";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_MUD_LITE;
break;
case SURF_DIRT:
sBulletHole += "dirt";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_DIRT_LITE;
break;
case SURF_GRILL:
sBulletHole += "grill";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_GRILL_LITE;
break;
case SURF_GRASS:
sBulletHole += "grass";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_GRASS_LITE;
break;
case SURF_ROCK:
sBulletHole += "stone";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_STONE_LITE;
break;
case SURF_PAPER:
sBulletHole += "paper";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_PAPER_LITE;
break;
case SURF_WOOD:
sBulletHole += "wood";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_WOOD_LITE;
break;
case SURF_METAL:
fRadius -= 0.25f;
sBulletHole += "metal";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_METAL_LITE;
break;
default:
sBulletHole += "stone";
2023-07-22 17:35:02 +02:00
iEffect = SFX_BHIT_STONE_LITE;
break;
}
if (fRadius && CG_CheckMakeMarkOnEntity(trace.entityNum)) {
2023-07-18 00:09:02 +02:00
fRadius *= 1.f + crandom() * 0.2f;
CG_ImpactMarkSimple(
cgi.R_RegisterShader(sBulletHole.c_str()),
trace.endpos,
trace.plane.normal,
0.f,
fRadius,
1.f,
1.f,
1.f,
1.f,
qfalse,
qfalse,
qtrue,
qfalse
);
}
CG_MakeBulletHoleType(vFrom, i_vNorm, iLarge, iEffect, fRadius, bMakeSound);
}
static void CG_MakeBubbleTrail(const vec3_t i_vStart, const vec3_t i_vEnd, int iLarge, float alpha = 1.0f)
{
vec3_t vDir;
vec3_t vPos;
float fDist;
float fMove;
VectorSubtract(i_vEnd, i_vStart, vDir);
fDist = VectorNormalize(vDir);
VectorCopy(i_vStart, vPos);
fMove = random() * 8.f * alpha;
fDist -= fMove;
while (fDist > 0.f) {
VectorMA(vPos, fMove, vDir, vPos);
2024-02-12 00:17:30 +01:00
sfxManager.MakeEffect_Angles(SFX_WATER_TRAIL_BUBBLE, vPos, vec_zero);
fMove = 16.f + crandom() * 8.f * alpha;
fDist -= fMove;
}
}
static void CG_BulletTracerEffect(const vec3_t i_vStart, const vec3_t i_vEnd, int iLarge, float alpha)
{
int iLife;
int iTracerLength;
float fLength, fDist;
vec4_t fTracerColor;
vec3_t vDir, vNewStart;
float alphaMult;
float scale;
iTracerLength = 450.0f + random() * 150.f;
VectorSubtract(i_vEnd, i_vStart, vDir);
fLength = VectorNormalize(vDir);
if (iLarge > 1) {
alphaMult = random() * 0.2f + 0.9f;
scale = iLarge * 2;
} else {
alphaMult = 1;
scale = 1;
}
fDist = 450.0f + random() * 150.f;
if (fLength < fDist + 150.f) {
float fFrac;
if (fLength < 150.f) {
return;
}
fFrac = fLength / (fDist + 150.0);
iTracerLength = (int)((float)iTracerLength * fFrac + 0.5f);
fDist *= fFrac;
}
iLife = (int)((fLength - fDist) / 12000.f * 1000.f / (alpha * alphaMult));
if (iLife < 20) {
iLife = 20;
}
VectorMA(i_vStart, fDist, vDir, vNewStart);
fTracerColor[0] = 1.f;
fTracerColor[1] = 1.f;
fTracerColor[2] = 1.f;
fTracerColor[3] = 1.f;
CG_CreateBeam(
vNewStart,
vec_zero,
0,
1,
1.0,
1.0,
BEAM_INVERTED,
1000.0,
iLife,
qtrue,
i_vEnd,
0,
0,
0,
1,
0,
"tracer",
fTracerColor,
0,
0.0,
iTracerLength,
1.0,
0,
"tracereffect"
);
}
2023-07-05 21:24:23 +02:00
static void CG_MakeBulletTracerInternal(
const vec3_t i_vBarrel,
const vec3_t i_vStart,
const vec3_t *i_vEnd,
int i_iNumBullets,
qboolean iLarge,
int iTracerVisible,
qboolean bIgnoreEntities,
float alpha
2023-07-05 21:24:23 +02:00
)
{
vec3_t vPos;
int iBullet;
int iContinueCount;
int iDist;
int iHeadDist;
int iTravelDist;
float fLen, fDist;
trace_t trace;
qboolean bStartInWater, bInWater;
qboolean bBulletDone;
qboolean bMadeTracer;
vec3_t vDir;
vec3_t vTrailStart;
vec3_t vTraceStart;
vec3_t vTraceEnd;
vec3_t vTmp;
int iNumImpacts;
trace_t tImpacts[128];
float fImpSndDistRA;
static float fImpSndDistLA;
float fImpSndDistRB;
float fImpSndDistLB;
int iImpSndIndexRA;
int iImpSndIndexRB;
int iImpSndIndexLB;
float fVolume;
float fPitch;
float fZingDistA, fZingDistB, fZingDistC;
vec3_t vZingPosA, vZingPosB, vZingPosC;
fZingDistB = 9999.0;
fZingDistA = 9999.0;
fZingDistC = 9999.0;
iNumImpacts = 0;
// check to see if it starts in water
bStartInWater = (cgi.CM_PointContents(i_vStart, 0) & CONTENTS_FLUID) != 0;
for (iBullet = 0; iBullet < i_iNumBullets; iBullet++) {
bInWater = bStartInWater;
VectorCopy(i_vBarrel, vTrailStart);
VectorSubtract(i_vEnd[iBullet], i_vStart, vDir);
fLen = VectorNormalize(vDir);
trace.fraction = 0;
iDist = (int)fLen + 32;
bBulletDone = qfalse;
iContinueCount = 0;
if (bStartInWater) {
bMadeTracer = qtrue;
} else if (!iTracerVisible) {
bMadeTracer = qtrue;
} else {
bMadeTracer = qfalse;
}
iTravelDist = 0;
VectorCopy(i_vStart, vTraceEnd);
if (iDist > 0) {
do {
if (iDist > BULLET_TRAVEL_DIST) {
iTravelDist += BULLET_TRAVEL_DIST;
iDist -= BULLET_TRAVEL_DIST;
} else {
iTravelDist += iDist;
iDist = 0;
}
memset(&trace, 0, sizeof(trace));
2023-07-10 23:58:05 +02:00
VectorCopy(vTraceEnd, vTraceStart);
VectorMA(i_vStart, iTravelDist, vDir, vTraceEnd);
while (trace.fraction < 1) {
if (bIgnoreEntities) {
2024-02-12 00:17:30 +01:00
cgi.CM_BoxTrace(&trace, vTraceStart, vTraceEnd, vec_zero, vec_zero, 0, MASK_SHOT_FLUID, qfalse);
if (trace.fraction == 1.0f) {
trace.entityNum = ENTITYNUM_NONE;
} else {
trace.entityNum = ENTITYNUM_WORLD;
}
if (trace.startsolid) {
trace.entityNum = ENTITYNUM_WORLD;
}
} else {
CG_Trace(
&trace,
vTraceStart,
vec_zero,
vec_zero,
vTraceStart,
ENTITYNUM_NONE,
2024-02-12 00:18:18 +01:00
MASK_SHOT_FLUID,
qfalse,
qfalse,
"CG_MakeBulletTracerInternal"
);
}
if (trace.contents & CONTENTS_FLUID) {
fDist = DotProduct(vDir, trace.plane.normal) * -2.0f;
VectorMA(vDir, fDist, trace.plane.normal, vTmp);
2024-02-12 00:17:30 +01:00
VectorMA(trace.plane.normal, 2.0, vTmp, trace.plane.normal);
VectorNormalizeFast(trace.plane.normal);
}
2024-02-12 00:17:30 +01:00
if (!bInWater && trace.fraction < 1.0f && iNumImpacts < ARRAY_LEN(tImpacts)) {
memcpy(&tImpacts[iNumImpacts], &trace, sizeof(trace_t));
iNumImpacts++;
}
if (iTracerVisible && !bMadeTracer) {
CG_BulletTracerEffect(vTrailStart, trace.endpos, iLarge, alpha);
bMadeTracer = qtrue;
}
if (trace.fraction < 1.0f) {
if (((trace.surfaceFlags & (SURF_HINT | SURF_NODLIGHT | SURF_SNOW | SURF_FOLIAGE | SURF_DIRT))
|| (trace.contents & CONTENTS_WATER))
&& iContinueCount < 5) {
if (bInWater) {
VectorSubtract(trace.endpos, vDir, vTmp);
if (!(trace.contents & CONTENTS_FLUID) && !(trace.surfaceFlags & SURF_PUDDLE)
&& !(cgi.CM_PointContents(vTmp, 0) & CONTENTS_FLUID)) {
CG_MakeBubbleTrail(vTrailStart, trace.endpos, iLarge, alpha);
VectorCopy(trace.endpos, vTrailStart);
bInWater = qfalse;
}
} else if ((trace.contents & CONTENTS_FLUID) || (trace.surfaceFlags & SURF_PUDDLE)) {
VectorCopy(trace.endpos, vTrailStart);
bInWater = qtrue;
}
VectorAdd(vDir, vDir, vTraceStart);
VectorAdd(vTraceStart, vTraceStart, trace.endpos);
iContinueCount++;
} else {
trace.fraction = 1.0f;
bBulletDone = qtrue;
}
}
}
} while (!bBulletDone && iDist > 0);
}
if (bInWater) {
CG_MakeBubbleTrail(vTraceStart, trace.endpos, iLarge, alpha);
}
if (iTracerVisible) {
iTracerVisible--;
}
fLen = ProjectPointOnLine(i_vStart, i_vEnd[iBullet], cg.SoundOrg, vPos);
iHeadDist = (int)Distance(vPos, cg.SoundOrg);
if (iHeadDist > 255) {
continue;
}
if (iHeadDist >= fZingDistA && iHeadDist >= fZingDistB && iHeadDist >= fZingDistC) {
continue;
}
fDist = Distance(i_vStart, i_vEnd[iBullet]);
if (fLen <= 128.0f || fLen >= fDist - 128.0f) {
continue;
}
if (fLen < 0.f) {
VectorCopy(i_vStart, vPos);
} else if (fDist >= fLen) {
VectorCopy(i_vEnd[iBullet], vPos);
}
if (iHeadDist < fZingDistA) {
VectorCopy(vZingPosB, vZingPosC);
VectorCopy(vZingPosA, vZingPosB);
fZingDistC = fZingDistB;
fZingDistB = fZingDistA;
VectorCopy(vPos, vZingPosA);
fZingDistA = iHeadDist;
} else if (iHeadDist < fZingDistB) {
VectorCopy(vZingPosB, vZingPosC);
fZingDistC = fZingDistB;
VectorCopy(vPos, vZingPosB);
fZingDistB = iHeadDist;
} else {
VectorCopy(vPos, vZingPosC);
fZingDistC = iHeadDist;
}
}
if (iNumImpacts > 2) {
fImpSndDistRA = 9999.0f;
fImpSndDistRB = 9999.0f;
iImpSndIndexRA = 0;
iImpSndIndexRB = 0;
fImpSndDistLB = 9999.0f;
iImpSndIndexLB = 0;
for (iBullet = 0; iBullet < iNumImpacts; iBullet++) {
CG_MakeBulletHole(
tImpacts[iImpSndIndexLB].endpos,
tImpacts[iImpSndIndexLB].plane.normal,
iLarge,
&tImpacts[iImpSndIndexLB],
qfalse
);
VectorSubtract(tImpacts[iImpSndIndexLB].endpos, cg.SoundOrg, vTmp);
iHeadDist = VectorLength(vTmp);
if (DotProduct(vTmp, cg.SoundAxis[1]) <= 0.f) {
if (iHeadDist < 9999.0f || iHeadDist < fImpSndDistLB) {
if (iHeadDist < 9999.0f) {
fImpSndDistRA = iHeadDist;
fImpSndDistLB = 9999.0;
iImpSndIndexRA = iBullet;
} else if (iHeadDist < fImpSndDistLB) {
fImpSndDistLB = iHeadDist;
}
}
} else {
if (iHeadDist < fImpSndDistRA || iHeadDist < fImpSndDistRB) {
if (iHeadDist < fImpSndDistRA) {
iImpSndIndexRB = iImpSndIndexRA;
iImpSndIndexRA = iBullet;
} else if (iHeadDist < fImpSndDistRB) {
fImpSndDistRB = iHeadDist;
iImpSndIndexRB = iBullet;
}
}
}
iImpSndIndexLB++;
}
if (fImpSndDistRA < 9999.0f) {
CG_MakeBulletHoleSound(
tImpacts[iImpSndIndexRA].endpos,
tImpacts[iImpSndIndexRA].plane.normal,
iLarge,
&tImpacts[iImpSndIndexRA]
);
if (fImpSndDistRB < 9999.0f) {
CG_MakeBulletHoleSound(
tImpacts[iImpSndIndexRB].endpos,
tImpacts[iImpSndIndexRB].plane.normal,
iLarge,
&tImpacts[iImpSndIndexRB]
);
}
}
} else {
for (iBullet = 0; iBullet < iNumImpacts; iBullet++) {
CG_MakeBulletHole(
tImpacts[iBullet].endpos, tImpacts[iBullet].plane.normal, iNumImpacts, &tImpacts[iBullet], qtrue
);
}
}
if (fZingDistA < 9999.0f) {
if (iLarge) {
fVolume = 1.0f;
fPitch = 0.8f;
} else {
fVolume = 0.8f;
fPitch = 1.0f;
}
commandManager.PlaySound("snd_b_zing", vZingPosA, -1, fVolume, -1.0f, fPitch, 1);
commandManager.PlaySound("snd_b_zing", vZingPosB, -1, fVolume, -1.0f, fPitch, 1);
commandManager.PlaySound("snd_b_zing", vZingPosC, -1, fVolume, -1.0f, fPitch, 1);
}
}
2023-07-05 21:24:23 +02:00
static void CG_MakeBulletTracer(
vec3_t i_vBarrel,
vec3_t i_vStart,
vec3_t *i_vEnd,
int i_iNumBullets,
qboolean iLarge,
int iTracerVisible,
qboolean bIgnoreEntities,
float alpha = 1.0f
)
{
bullet_tracer_t *bullet_tracer;
int i;
2023-05-04 21:07:44 +02:00
2023-05-04 23:26:17 +02:00
if (bullet_tracer_bullets_count >= MAX_BULLET_TRACERS) {
2023-05-04 21:07:44 +02:00
Com_Printf("CG_MakeBulletTracer: MAX_BULLET_TRACERS exceeded\n");
return;
}
if (i_iNumBullets + bullet_tracers_count >= MAX_BULLET_TRACE_BULLETS) {
Com_Printf("CG_MakeBulletTracerInternal: MAX_BULLET_TRACE_BULLETS exceeded\n");
return;
}
bullet_tracer = &bullet_tracers[bullet_tracer_bullets_count++];
VectorCopy(i_vBarrel, bullet_tracer->i_vBarrel);
VectorCopy(i_vStart, bullet_tracer->i_vStart);
2023-07-05 21:24:23 +02:00
bullet_tracer->i_vEnd = &bullet_tracer_bullets[bullet_tracers_count];
2023-05-04 21:07:44 +02:00
bullet_tracer->i_iNumBullets = i_iNumBullets;
for (i = 0; i < i_iNumBullets; i++, bullet_tracers_count++) {
bullet_tracer_bullets[bullet_tracers_count][0] = i_vEnd[i][0];
bullet_tracer_bullets[bullet_tracers_count][1] = i_vEnd[i][1];
bullet_tracer_bullets[bullet_tracers_count][2] = i_vEnd[i][2];
2023-05-04 21:07:44 +02:00
}
2023-07-05 21:24:23 +02:00
bullet_tracer->iLarge = iLarge;
bullet_tracer->alpha = alpha;
2023-07-05 21:24:23 +02:00
bullet_tracer->iTracerVisible = iTracerVisible;
2023-05-04 21:07:44 +02:00
bullet_tracer->bIgnoreEntities = bIgnoreEntities;
2023-05-04 20:30:52 +02:00
}
2023-05-01 15:10:26 +02:00
void CG_AddBulletTracers()
{
int i;
for (i = 0; i < bullet_tracer_bullets_count; ++i) {
CG_MakeBulletTracerInternal(
bullet_tracers[i].i_vBarrel,
bullet_tracers[i].i_vStart,
bullet_tracers[i].i_vEnd,
bullet_tracers[i].i_iNumBullets,
bullet_tracers[i].iLarge,
bullet_tracers[i].iTracerVisible,
bullet_tracers[i].bIgnoreEntities,
bullet_tracers[i].alpha
);
}
bullet_tracer_bullets_count = 0;
2023-07-05 21:24:23 +02:00
bullet_tracers_count = 0;
2023-05-01 15:10:26 +02:00
}
void CG_AddBulletImpacts()
{
int i;
int iHeadDist;
float fVolume;
float fImpSndDistRA;
static float fImpSndDistLA = 9999.f;
float fImpSndDistRB;
float fImpSndDistLB;
int iImpSndIndexRA;
int iImpSndIndexRB;
int iImpSndIndexLB;
vec3_t vTmp;
str sSoundName;
if (wall_impact_count) {
if (wall_impact_count > 4) {
fImpSndDistRA = fImpSndDistLA;
fImpSndDistRB = fImpSndDistLA;
fImpSndDistLB = fImpSndDistLA;
iImpSndIndexRA = 0;
iImpSndIndexRB = 0;
iImpSndIndexLB = 0;
for (i = 0; i < wall_impact_count; i++) {
VectorSubtract(wall_impact_pos[i], cg.SoundOrg, vTmp);
iHeadDist = VectorLength(vTmp);
if (DotProduct(vTmp, cg.SoundAxis[1]) > 0.f) {
if (iHeadDist < fImpSndDistRA || iHeadDist < fImpSndDistRB) {
if (iHeadDist < fImpSndDistRA) {
fImpSndDistRB = fImpSndDistRA;
fImpSndDistRA = iHeadDist;
iImpSndIndexRB = iImpSndIndexRA;
iImpSndIndexRA = i;
} else if (iHeadDist < fImpSndDistRB) {
fImpSndDistRB = iHeadDist;
iImpSndIndexRB = i;
}
}
} else {
if (iHeadDist < fImpSndDistLA || iHeadDist < fImpSndDistLB) {
if (iHeadDist < fImpSndDistLA) {
fImpSndDistRA = iHeadDist;
fImpSndDistLB = fImpSndDistLA;
iImpSndIndexLB = 0;
iImpSndIndexRA = i;
} else if (iHeadDist < fImpSndDistLB) {
fImpSndDistLB = iHeadDist;
iImpSndIndexLB = i;
}
}
}
}
if (fImpSndDistRA < fImpSndDistLA) {
if (wall_impact_type[iImpSndIndexRA] != SFX_BHIT_PAPER_LITE) {
if (wall_impact_large[iImpSndIndexRA]) {
fVolume = 1.f;
} else {
fVolume = 0.75f;
}
2024-09-10 19:40:53 +02:00
if (wall_impact_type[iImpSndIndexRA] == SFX_BHIT_WOOD_LITE
|| wall_impact_type[iImpSndIndexRA] == SFX_BHIT_WOOD_HARD) {
sSoundName = "snd_bh_metal";
} else {
sSoundName = "snd_bh_wood";
}
commandManager.PlaySound(sSoundName, wall_impact_pos[iImpSndIndexRA], -1, fVolume, -1, -1, 1);
sfxManager.MakeEffect_Normal(
wall_impact_type[iImpSndIndexRA],
wall_impact_pos[iImpSndIndexRA],
wall_impact_norm[iImpSndIndexRA]
);
} else {
CG_MakeBulletHole(
wall_impact_pos[iImpSndIndexRA],
wall_impact_norm[iImpSndIndexRA],
wall_impact_large[iImpSndIndexRA],
NULL,
qtrue
);
}
if (fImpSndDistRB < fImpSndDistLA) {
if (wall_impact_type[iImpSndIndexRB]) {
if (wall_impact_large[iImpSndIndexRB]) {
fVolume = 1.f;
} else {
fVolume = 0.75f;
}
2024-09-10 19:40:53 +02:00
if (wall_impact_type[iImpSndIndexRB] == SFX_BHIT_WOOD_LITE
|| wall_impact_type[iImpSndIndexRB] == SFX_BHIT_WOOD_HARD) {
sSoundName = "snd_bh_metal";
} else {
sSoundName = "snd_bh_wood";
}
commandManager.PlaySound(sSoundName, wall_impact_pos[iImpSndIndexRB], -1, fVolume, -1, -1, 1);
sfxManager.MakeEffect_Normal(
wall_impact_type[iImpSndIndexRB],
wall_impact_pos[iImpSndIndexRB],
wall_impact_norm[iImpSndIndexRB]
);
} else {
CG_MakeBulletHole(
wall_impact_pos[iImpSndIndexRB],
wall_impact_norm[iImpSndIndexRB],
wall_impact_large[iImpSndIndexRB],
NULL,
qtrue
);
}
}
}
if (fImpSndDistLA > 9999.0f) {
if (wall_impact_type[0] != SFX_BHIT_PAPER_LITE) {
if (wall_impact_large[0]) {
fVolume = 1.f;
} else {
fVolume = 0.75f;
}
if (wall_impact_type[0] == SFX_BHIT_WOOD_LITE || wall_impact_type[0] == SFX_BHIT_WOOD_HARD) {
sSoundName = "snd_bh_metal";
} else {
sSoundName = "snd_bh_wood";
}
commandManager.PlaySound(sSoundName, wall_impact_pos[0], -1, fVolume, -1, -1, 1);
sfxManager.MakeEffect_Normal(wall_impact_type[0], wall_impact_pos[0], wall_impact_norm[0]);
} else {
CG_MakeBulletHole(wall_impact_pos[0], wall_impact_norm[0], wall_impact_large[0], NULL, qtrue);
}
}
if (fImpSndDistLB < fImpSndDistLA) {
if (wall_impact_type[iImpSndIndexLB] != SFX_BHIT_PAPER_LITE) {
if (wall_impact_large[iImpSndIndexLB]) {
fVolume = 1.f;
} else {
fVolume = 0.75f;
}
2024-09-10 19:40:53 +02:00
if (wall_impact_type[iImpSndIndexLB] == SFX_BHIT_WOOD_LITE
|| wall_impact_type[iImpSndIndexLB] == SFX_BHIT_WOOD_HARD) {
sSoundName = "snd_bh_metal";
} else {
sSoundName = "snd_bh_wood";
}
commandManager.PlaySound(sSoundName, wall_impact_pos[iImpSndIndexLB], -1, fVolume, -1, -1, 1);
sfxManager.MakeEffect_Normal(
wall_impact_type[iImpSndIndexLB],
wall_impact_pos[iImpSndIndexLB],
wall_impact_norm[iImpSndIndexLB]
);
} else {
CG_MakeBulletHole(
wall_impact_pos[iImpSndIndexLB],
wall_impact_norm[iImpSndIndexLB],
wall_impact_large[iImpSndIndexLB],
NULL,
qtrue
);
}
}
} else {
for (i = 0; i < wall_impact_count; i++) {
CG_MakeBulletHole(wall_impact_pos[i], wall_impact_norm[i], wall_impact_large[i], NULL, qtrue);
}
}
2023-07-10 23:58:05 +02:00
wall_impact_count = 0;
}
if (flesh_impact_count) {
if (flesh_impact_count > 1) {
fImpSndDistRA = 9999.0;
2024-08-31 17:57:28 +02:00
fImpSndDistRB = 9999.0;
iImpSndIndexRA = 0;
2024-08-31 17:57:28 +02:00
iImpSndIndexRB = 0;
for (i = 0; i < flesh_impact_count; i++) {
2024-08-31 17:57:28 +02:00
VectorSubtract(flesh_impact_pos[i], cg.SoundOrg, vTmp);
iHeadDist = VectorLength(vTmp);
if (DotProduct(vTmp, cg.SoundAxis[1]) > 0.f) {
2024-08-31 17:57:28 +02:00
if (iHeadDist < fImpSndDistRB) {
fImpSndDistRA = iHeadDist;
iImpSndIndexRA = i;
}
} else if (iHeadDist < fImpSndDistLA) {
fImpSndDistRA = iHeadDist;
iImpSndIndexRA = i;
}
}
2024-08-31 17:57:28 +02:00
if (fImpSndDistRA < 9999) {
sfxManager.MakeEffect_Normal(
flesh_impact_large[iImpSndIndexRA] ? SFX_BHIT_HUMAN_UNIFORM_HARD : SFX_BHIT_HUMAN_UNIFORM_LITE,
flesh_impact_pos[iImpSndIndexRA],
flesh_impact_norm[iImpSndIndexRA]
);
}
if (fImpSndDistRB < 9999) {
sfxManager.MakeEffect_Normal(
flesh_impact_large[iImpSndIndexRB] ? SFX_BHIT_HUMAN_UNIFORM_HARD : SFX_BHIT_HUMAN_UNIFORM_LITE,
flesh_impact_pos[iImpSndIndexRB],
flesh_impact_norm[iImpSndIndexRB]
);
}
} else {
for (i = 0; i < flesh_impact_count; i++) {
sfxManager.MakeEffect_Normal(
flesh_impact_large[i] ? SFX_BHIT_HUMAN_UNIFORM_HARD : SFX_BHIT_HUMAN_UNIFORM_LITE,
flesh_impact_pos[i],
flesh_impact_norm[i]
);
}
}
2023-07-10 23:58:05 +02:00
flesh_impact_count = 0;
}
2023-05-01 15:10:26 +02:00
}
2023-07-18 00:09:02 +02:00
void CG_MakeExplosionEffect(const vec3_t vPos, int iType)
2023-07-05 21:24:23 +02:00
{
int iSurfType;
int iBaseEffect;
int iSurfEffect;
float fRadius;
vec3_t vEnd;
str sMark;
trace_t trace;
qhandle_t shader;
vEnd[0] = vPos[0];
vEnd[1] = vPos[1];
vEnd[2] = vPos[2] - 64.0;
fRadius = 64.0;
2023-07-05 21:24:23 +02:00
if ((CG_PointContents(vPos, 0)) & MASK_WATER) {
2023-07-22 17:35:02 +02:00
iBaseEffect = SFX_EXP_GREN_PUDDLE;
sfxManager.MakeEffect_Normal(iBaseEffect, vPos, Vector(0, 0, 1));
return;
}
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
switch (iType) {
case CGM_EXPLOSION_EFFECT_1:
iBaseEffect = SFX_EXP_GREN_BASE;
break;
case CGM_EXPLOSION_EFFECT_2:
iBaseEffect = SFX_EXP_BAZOOKA_BASE;
break;
case CGM_EXPLOSION_EFFECT_3:
iBaseEffect = SFX_EXP_HEAVYSHELL_BASE;
break;
case CGM_EXPLOSION_EFFECT_4:
iBaseEffect = SFX_EXP_TANK_BASE;
break;
default:
iBaseEffect = SFX_EXP_GREN_BASE;
break;
}
} else {
switch (iType) {
case CGM6_EXPLOSION_EFFECT_2:
iBaseEffect = SFX_EXP_BAZOOKA_BASE;
break;
default:
iBaseEffect = SFX_EXP_GREN_BASE;
break;
}
}
CG_Trace(
2023-07-05 21:24:23 +02:00
&trace, vPos, vec_zero, vec_zero, vEnd, ENTITYNUM_NONE, MASK_EXPLOSION, qfalse, qtrue, "CG_MakeExplosionEffect"
);
2023-07-05 21:24:23 +02:00
if (trace.fraction == 1.0 || trace.startsolid) {
// exploded in the air
sfxManager.MakeEffect_Normal(iBaseEffect, vPos, Vector(0, 0, 1));
return;
}
2023-07-18 00:09:02 +02:00
VectorMA(trace.endpos, 32.0, trace.plane.normal, vEnd);
iSurfType = trace.surfaceFlags & MASK_SURF_TYPE;
2023-07-05 21:24:23 +02:00
switch (iSurfType) {
case SURF_FOLIAGE:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_FOLIAGE;
2023-07-05 21:24:23 +02:00
fRadius = 0;
break;
case SURF_SNOW:
switch (iBaseEffect) {
2023-07-22 17:35:02 +02:00
case SFX_EXP_TANK_BASE:
iSurfEffect = SFX_EXP_TANK_SNOW;
break;
case SFX_EXP_BAZOOKA_BASE:
iSurfEffect = SFX_EXP_BAZOOKA_SNOW;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
case SFX_EXP_HEAVYSHELL_BASE:
iSurfEffect = SFX_EXP_HEAVYSHELL_SNOW;
break;
default:
iSurfEffect = SFX_EXP_GREN_SNOW;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
}
fRadius = 0;
break;
case SURF_CARPET:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_CARPET;
break;
case SURF_SAND:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_SAND;
2023-07-05 21:24:23 +02:00
fRadius = 0;
break;
case SURF_PUDDLE:
iSurfEffect = -1;
2023-07-05 21:24:23 +02:00
fRadius = 0;
break;
case SURF_GLASS:
iSurfEffect = -1;
2023-07-05 21:24:23 +02:00
fRadius = 0;
break;
case SURF_GRAVEL:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_GRAVEL;
break;
case SURF_MUD:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_MUD;
2023-07-05 21:24:23 +02:00
fRadius = 0;
break;
case SURF_DIRT:
switch (iBaseEffect) {
2023-07-22 17:35:02 +02:00
case SFX_EXP_TANK_BASE:
iSurfEffect = SFX_EXP_TANK_DIRT;
break;
case SFX_EXP_BAZOOKA_BASE:
iSurfEffect = SFX_EXP_BAZOOKA_DIRT;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
case SFX_EXP_HEAVYSHELL_BASE:
iSurfEffect = SFX_EXP_HEAVYSHELL_DIRT;
break;
default:
iSurfEffect = SFX_EXP_GREN_DIRT;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
}
fRadius = 0;
break;
case SURF_GRILL:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_GRILL;
2023-07-05 21:24:23 +02:00
fRadius = 0;
break;
case SURF_GRASS:
switch (iBaseEffect) {
2023-07-22 17:35:02 +02:00
case SFX_EXP_TANK_BASE:
iSurfEffect = SFX_EXP_TANK_DIRT;
break;
case SFX_EXP_BAZOOKA_BASE:
iSurfEffect = SFX_EXP_BAZOOKA_DIRT;
break;
case SFX_EXP_HEAVYSHELL_BASE:
iSurfEffect = SFX_EXP_HEAVYSHELL_DIRT;
break;
default:
iSurfEffect = SFX_EXP_GREN_GRASS;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
}
fRadius = 0;
break;
case SURF_ROCK:
switch (iBaseEffect) {
2023-07-22 17:35:02 +02:00
case SFX_EXP_TANK_BASE:
iSurfEffect = SFX_EXP_TANK_STONE;
break;
case SFX_EXP_BAZOOKA_BASE:
iSurfEffect = SFX_EXP_BAZOOKA_STONE;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
case SFX_EXP_HEAVYSHELL_BASE:
iSurfEffect = SFX_EXP_HEAVYSHELL_STONE;
break;
default:
iSurfEffect = SFX_EXP_GREN_STONE;
if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) {
iBaseEffect = -1;
}
2023-07-22 17:35:02 +02:00
break;
}
break;
case SURF_PAPER:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_PAPER;
break;
case SURF_WOOD:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_WOOD;
break;
case SURF_METAL:
2023-07-22 17:35:02 +02:00
iSurfEffect = SFX_EXP_GREN_METAL;
break;
default:
iSurfEffect = -1;
break;
}
sMark = "blastmark";
2023-07-05 21:24:23 +02:00
if (fRadius) {
2023-07-18 00:09:02 +02:00
fRadius *= 1.f + crandom() * 0.1;
shader = cgi.R_RegisterShader(sMark.c_str());
CG_ImpactMarkSimple(
shader,
trace.endpos,
trace.plane.normal,
random() * 360.0,
fRadius,
2023-07-05 21:24:23 +02:00
1,
1,
1,
1,
qfalse,
qfalse,
qtrue,
qfalse
);
}
2023-07-18 00:09:02 +02:00
VectorMA(vEnd, 1.0, trace.plane.normal, vEnd);
2023-07-05 21:24:23 +02:00
if (iSurfEffect != -1) {
sfxManager.MakeEffect_Normal(
2023-07-05 21:24:23 +02:00
iSurfEffect, Vector(trace.endpos) + Vector(trace.plane.normal), trace.plane.normal
);
}
if (iBaseEffect != -1) {
sfxManager.MakeEffect_Normal(iBaseEffect, vEnd, trace.plane.normal);
}
}
2023-07-05 21:24:23 +02:00
void CG_MakeVehicleEffect(vec3_t i_vStart, vec3_t i_vEnd, vec3_t i_vDir)
{
vec3_t vDir, vFrom, vDest;
trace_t trace;
VectorSubtract(i_vEnd, i_vStart, vDir);
VectorNormalizeFast(vDir);
VectorMA(i_vEnd, -16.0, vDir, vFrom);
VectorMA(i_vEnd, 16.0, vDir, vDest);
2023-07-05 21:24:23 +02:00
CG_Trace(
&trace, vFrom, vec_zero, vec_zero, vDest, ENTITYNUM_NONE, MASK_PLAYERSOLID, qfalse, qtrue, "CG_MakeBulletHole"
);
cgi.R_DebugLine(vFrom, trace.endpos, 1.0, 1.0, 1.0, 1.0);
2023-05-04 20:30:52 +02:00
}
void CG_ParseCGMessage_ver_15()
{
2023-07-05 21:24:23 +02:00
int i;
int iType;
int iLarge;
int iInfo;
int iCount;
char *szTmp;
vec3_t vStart, vEnd, vTmp;
vec3_t vEndArray[MAX_IMPACTS];
float alpha;
qboolean bMoreCGameMessages = qtrue;
while (bMoreCGameMessages) {
iType = cgi.MSG_ReadBits(6);
switch (iType) {
case CGM_BULLET_1:
case CGM_BULLET_2:
case CGM_BULLET_5:
if (iType == CGM_BULLET_1) {
2023-07-05 21:24:23 +02:00
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
}
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
if (iType != CGM_BULLET_1) {
2023-07-05 21:24:23 +02:00
vTmp[0] = vStart[0];
vTmp[1] = vStart[1];
vTmp[2] = vStart[2];
}
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(2);
if (cgi.MSG_ReadBits(1)) {
int iAlpha = cgi.MSG_ReadBits(10);
2023-07-05 21:24:23 +02:00
alpha = (float)iAlpha / 512.0;
if (alpha < 0.002f) {
alpha = 0.002f;
}
} else {
alpha = 1.0f;
}
if (iType == CGM_BULLET_1) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue, alpha);
} else if (iType == CGM_BULLET_2) {
2023-07-05 21:24:23 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue, alpha);
} else {
CG_MakeBubbleTrail(vStart, vEndArray[0], iLarge, alpha);
}
break;
case CGM_BULLET_3:
case CGM_BULLET_4:
if (iType == CGM_BULLET_3) {
2023-07-05 21:24:23 +02:00
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
iInfo = cgi.MSG_ReadBits(6);
} else {
iInfo = 0;
}
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(2);
if (cgi.MSG_ReadBits(1)) {
int iAlpha = cgi.MSG_ReadBits(10);
alpha = (float)iAlpha / 512.0;
if (alpha < 0.002f) {
alpha = 0.002f;
2023-07-05 21:24:23 +02:00
}
} else {
alpha = 1.0f;
}
iCount = cgi.MSG_ReadBits(6);
for (i = 0; i < iCount; ++i) {
vEndArray[i][0] = cgi.MSG_ReadCoord();
vEndArray[i][1] = cgi.MSG_ReadCoord();
vEndArray[i][2] = cgi.MSG_ReadCoord();
}
if (iCount) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, iCount, iLarge, iInfo, qtrue, alpha);
}
break;
case CGM_BULLET_6:
case CGM_BULLET_7:
case CGM_BULLET_8:
case CGM_BULLET_9:
case CGM_BULLET_10:
case CGM_BULLET_11:
2023-07-05 21:24:23 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
iLarge = cgi.MSG_ReadBits(2);
switch (iType) {
case CGM_BULLET_6:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = -1;
wall_impact_count++;
}
break;
case CGM_BULLET_7:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = SFX_BHIT_STONE_LITE;
2023-07-05 21:24:23 +02:00
wall_impact_count++;
}
break;
case CGM_BULLET_8:
2023-07-05 21:24:23 +02:00
if (flesh_impact_count < MAX_IMPACTS) {
// negative
VectorNegate(vEnd, vEnd);
VectorCopy(vStart, flesh_impact_pos[flesh_impact_count]);
VectorCopy(vEnd, flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case CGM_BULLET_9:
2023-07-05 21:24:23 +02:00
if (flesh_impact_count < MAX_IMPACTS) {
// negative
VectorNegate(vEnd, vEnd);
VectorCopy(vStart, flesh_impact_pos[flesh_impact_count]);
VectorCopy(vEnd, flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case CGM_BULLET_10:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = SFX_BHIT_WOOD_LITE;
2023-07-05 21:24:23 +02:00
wall_impact_count++;
}
break;
case CGM_BULLET_11:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = SFX_BHIT_METAL_LITE;
2023-07-05 21:24:23 +02:00
wall_impact_count++;
}
break;
default:
continue;
}
break;
case CGM_MELEE_IMPACT:
2023-07-05 21:24:23 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEnd[0] = cgi.MSG_ReadCoord();
vEnd[1] = cgi.MSG_ReadCoord();
vEnd[2] = cgi.MSG_ReadCoord();
CG_MeleeImpact(vStart, vEnd);
break;
case CGM_EXPLOSION_EFFECT_1:
case CGM_EXPLOSION_EFFECT_2:
case CGM_EXPLOSION_EFFECT_3:
case CGM_EXPLOSION_EFFECT_4:
2023-07-05 21:24:23 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
CG_MakeExplosionEffect(vStart, iType);
break;
case CGM_MAKE_EFFECT_1:
case CGM_MAKE_EFFECT_2:
case CGM_MAKE_EFFECT_3:
case CGM_MAKE_EFFECT_4:
case CGM_MAKE_EFFECT_5:
case CGM_MAKE_EFFECT_6:
case CGM_MAKE_EFFECT_7:
case CGM_MAKE_EFFECT_8:
2023-07-05 21:24:23 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
sfxManager.MakeEffect_Normal(SFX_EXP_GREN_PUDDLE + iType, vStart, vEnd);
2023-07-05 21:24:23 +02:00
break;
case CGM_MAKE_CRATE_DEBRIS:
case CGM_MAKE_WINDOW_DEBRIS:
2023-07-05 21:24:23 +02:00
{
str sEffect;
char cTmp[8];
vec3_t axis[3];
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadByte();
// get the integer as string
snprintf(cTmp, sizeof(cTmp), "%d", iLarge);
if (iType == CGM_MAKE_CRATE_DEBRIS) {
2023-07-05 21:24:23 +02:00
sEffect = "models/fx/crates/debris_";
} else {
sEffect = "models/fx/windows/debris_";
}
sEffect += cTmp;
sEffect += ".tik";
VectorSet(axis[0], 0, 0, 1);
VectorSet(axis[1], 0, 1, 0);
VectorSet(axis[2], 1, 0, 0);
cgi.R_SpawnEffectModel(sEffect.c_str(), vStart, axis);
}
break;
case CGM_BULLET_NO_BARREL_1:
2023-07-05 21:24:23 +02:00
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(2);
2023-07-05 21:24:23 +02:00
if (cgi.MSG_ReadBits(1)) {
int iAlpha = cgi.MSG_ReadBits(10);
alpha = (float)iAlpha / 512.0;
if (alpha < 0.002f) {
alpha = 0.002f;
2023-07-05 21:24:23 +02:00
}
} else {
alpha = 1.0f;
}
2023-07-05 21:24:23 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue, alpha);
break;
case CGM_BULLET_NO_BARREL_2:
2023-07-05 21:24:23 +02:00
memset(vTmp, 0, sizeof(vTmp));
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
2023-07-05 21:24:23 +02:00
if (cgi.MSG_ReadBits(1)) {
int iAlpha = cgi.MSG_ReadBits(10);
alpha = (float)iAlpha / 512.0;
if (alpha < 0.002f) {
alpha = 0.002f;
2023-07-05 21:24:23 +02:00
}
} else {
alpha = 1.0f;
}
2023-07-05 21:24:23 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue, alpha);
break;
case CGM_HUDDRAW_SHADER:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
strcpy(cgi.HudDrawElements[iInfo].shaderName, cgi.MSG_ReadString());
cgi.HudDrawElements[iInfo].string[0] = 0;
cgi.HudDrawElements[iInfo].pFont = NULL;
cgi.HudDrawElements[iInfo].fontName[0] = 0;
// set the shader
CG_HudDrawShader(iInfo);
break;
case CGM_HUDDRAW_ALIGN:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].iHorizontalAlign = cgi.MSG_ReadBits(2);
cgi.HudDrawElements[iInfo].iVerticalAlign = cgi.MSG_ReadBits(2);
break;
case CGM_HUDDRAW_RECT:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].iX = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iY = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iWidth = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iHeight = cgi.MSG_ReadShort();
break;
case CGM_HUDDRAW_VIRTUALSIZE:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].bVirtualScreen = cgi.MSG_ReadBits(1);
break;
case CGM_HUDDRAW_COLOR:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].vColor[0] = cgi.MSG_ReadByte() / 255.0;
cgi.HudDrawElements[iInfo].vColor[1] = cgi.MSG_ReadByte() / 255.0;
cgi.HudDrawElements[iInfo].vColor[2] = cgi.MSG_ReadByte() / 255.0;
break;
case CGM_HUDDRAW_ALPHA:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].vColor[3] = cgi.MSG_ReadByte() / 255.0;
break;
case CGM_HUDDRAW_STRING:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].hShader = 0;
strcpy(cgi.HudDrawElements[iInfo].string, cgi.MSG_ReadString());
break;
case CGM_HUDDRAW_FONT:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
strcpy(cgi.HudDrawElements[iInfo].fontName, cgi.MSG_ReadString());
cgi.HudDrawElements[iInfo].hShader = 0;
cgi.HudDrawElements[iInfo].shaderName[0] = 0;
// load the font
CG_HudDrawFont(iInfo);
break;
case CGM_NOTIFY_KILL:
case CGM_NOTIFY_HIT:
2023-07-05 21:24:23 +02:00
{
int iOldEnt;
iOldEnt = current_entity_number;
current_entity_number = cg.snap->ps.clientNum;
if (iType == CGM_NOTIFY_HIT) {
2023-07-05 21:24:23 +02:00
commandManager.PlaySound("dm_kill_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1);
} else {
commandManager.PlaySound("dm_hit_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1);
}
current_entity_number = iOldEnt;
}
break;
case CGM_VOICE_CHAT:
2023-07-05 21:24:23 +02:00
{
int iOldEnt;
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
iInfo = cgi.MSG_ReadBits(6);
szTmp = cgi.MSG_ReadString();
iOldEnt = current_entity_number;
if (iLarge) {
current_entity_number = iInfo;
commandManager.PlaySound(szTmp, vStart, CHAN_LOCAL, -1, -1, -1, 0);
} else {
current_entity_number = cg.snap->ps.clientNum;
commandManager.PlaySound(szTmp, vStart, CHAN_AUTO, -1, -1, -1, 1);
}
current_entity_number = iOldEnt;
}
break;
case CGM_FENCEPOST:
2024-09-10 19:40:53 +02:00
{
int iHalf;
vec3_t vForward, vRight, vUp;
float fLength;
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
vEnd[0] = cgi.MSG_ReadCoord();
vEnd[1] = cgi.MSG_ReadCoord();
vEnd[2] = cgi.MSG_ReadCoord();
iHalf = cgi.MSG_ReadByte();
cgi.MSG_ReadByte();
2024-09-10 19:40:53 +02:00
VectorSubtract(vEnd, vStart, vForward);
fLength = VectorNormalize(vForward);
iCount = fLength / 2.0;
MakeNormalVectors(vForward, vRight, vUp);
for (i = 0; i < iCount; i++) {
vec3_t vOrg;
vec3_t vNormal;
VectorCopy(vStart, vOrg);
VectorMA(vOrg, random(), vForward, vOrg);
VectorMA(vOrg, crandom() * iHalf, vRight, vOrg);
VectorMA(vOrg, crandom() * iHalf, vUp, vOrg);
//
// Spawn the fence wood effect
//
VectorSubtract(vStart, vOrg, vNormal);
VectorNormalize(vNormal);
sfxManager.MakeEffect_Normal(SFX_FENCE_WOOD, vOrg, vNormal);
}
// FIXME: unimplemented
// ?? can't figure out what is this
}
2023-07-05 21:24:23 +02:00
break;
default:
cgi.Error(ERR_DROP, "CG_ParseCGMessage: Unknown CGM message type");
break;
}
bMoreCGameMessages = cgi.MSG_ReadBits(1);
}
}
void CG_ParseCGMessage_ver_6()
2023-05-01 00:08:43 +02:00
{
2023-07-05 21:24:23 +02:00
int i;
int iType;
int iLarge;
int iInfo;
int iCount;
char *szTmp;
2023-05-04 20:30:52 +02:00
vec3_t vStart, vEnd, vTmp;
vec3_t vEndArray[MAX_IMPACTS];
qboolean bMoreCGameMessages = qtrue;
while (bMoreCGameMessages) {
iType = cgi.MSG_ReadBits(6);
2023-07-05 21:24:23 +02:00
switch (iType) {
case CGM6_BULLET_1:
case CGM6_BULLET_2:
case CGM6_BULLET_5:
if (iType == CGM6_BULLET_1) {
2023-05-04 20:30:52 +02:00
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
}
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
if (iType != CGM6_BULLET_1) {
2023-05-04 20:30:52 +02:00
vTmp[0] = vStart[0];
vTmp[1] = vStart[1];
vTmp[2] = vStart[2];
}
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
2023-07-05 21:24:23 +02:00
iLarge = cgi.MSG_ReadBits(1);
2023-05-04 20:30:52 +02:00
if (iType == CGM6_BULLET_1) {
2024-09-02 00:18:49 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue);
} else if (iType == CGM6_BULLET_2) {
2023-05-04 20:30:52 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
2023-07-05 21:24:23 +02:00
} else {
2023-05-04 20:30:52 +02:00
CG_MakeBubbleTrail(vStart, vEndArray[0], iLarge);
}
break;
case CGM6_BULLET_3:
case CGM6_BULLET_4:
if (iType == CGM6_BULLET_3) {
2023-05-04 20:30:52 +02:00
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadBits(6);
} else {
2023-05-04 20:30:52 +02:00
iInfo = 0;
}
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
2023-07-05 21:24:23 +02:00
iLarge = cgi.MSG_ReadBits(1);
iCount = cgi.MSG_ReadBits(6);
for (i = 0; i < iCount; ++i) {
2023-05-04 20:30:52 +02:00
vEndArray[i][0] = cgi.MSG_ReadCoord();
vEndArray[i][1] = cgi.MSG_ReadCoord();
vEndArray[i][2] = cgi.MSG_ReadCoord();
}
if (iCount) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, iCount, iLarge, iInfo, qtrue);
}
break;
case CGM6_BULLET_6:
case CGM6_BULLET_7:
case CGM6_BULLET_8:
case CGM6_BULLET_9:
case CGM6_BULLET_10:
2023-05-04 20:30:52 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
iLarge = cgi.MSG_ReadBits(1);
2023-07-05 21:24:23 +02:00
switch (iType) {
case CGM6_BULLET_6:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
2023-05-04 20:30:52 +02:00
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = SFX_BHIT_PAPER_LITE;
2023-05-04 20:30:52 +02:00
wall_impact_count++;
}
break;
case CGM6_BULLET_7:
2023-07-05 21:24:23 +02:00
if (flesh_impact_count < MAX_IMPACTS) {
2023-05-04 20:30:52 +02:00
// negative
VectorNegate(vEnd, vEnd);
VectorCopy(vStart, flesh_impact_pos[flesh_impact_count]);
VectorCopy(vEnd, flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case CGM6_BULLET_8:
2023-07-05 21:24:23 +02:00
if (flesh_impact_count < MAX_IMPACTS) {
2023-05-04 20:30:52 +02:00
// negative
VectorNegate(vEnd, vEnd);
VectorCopy(vStart, flesh_impact_pos[flesh_impact_count]);
VectorCopy(vEnd, flesh_impact_norm[flesh_impact_count]);
flesh_impact_large[flesh_impact_count] = iLarge;
flesh_impact_count++;
}
break;
case CGM6_BULLET_9:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
2023-05-04 20:30:52 +02:00
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = iLarge ? SFX_BHIT_WOOD_HARD : SFX_BHIT_WOOD_LITE;
2023-05-04 20:30:52 +02:00
wall_impact_count++;
}
break;
case CGM6_BULLET_10:
2023-07-05 21:24:23 +02:00
if (wall_impact_count < MAX_IMPACTS) {
2023-05-04 20:30:52 +02:00
VectorCopy(vStart, wall_impact_pos[wall_impact_count]);
VectorCopy(vEnd, wall_impact_norm[wall_impact_count]);
wall_impact_large[wall_impact_count] = iLarge;
wall_impact_type[wall_impact_count] = iLarge ? SFX_BHIT_METAL_HARD : SFX_BHIT_METAL_LITE;
2023-05-04 20:30:52 +02:00
wall_impact_count++;
}
break;
default:
continue;
}
break;
case CGM6_MELEE_IMPACT:
2023-05-04 20:30:52 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
2023-07-05 21:24:23 +02:00
vEnd[0] = cgi.MSG_ReadCoord();
vEnd[1] = cgi.MSG_ReadCoord();
vEnd[2] = cgi.MSG_ReadCoord();
2023-05-04 20:30:52 +02:00
CG_MeleeImpact(vStart, vEnd);
break;
case CGM6_EXPLOSION_EFFECT_1:
case CGM6_EXPLOSION_EFFECT_2:
2023-05-04 20:30:52 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
CG_MakeExplosionEffect(vStart, iType);
break;
case CGM6_MAKE_EFFECT_1:
case CGM6_MAKE_EFFECT_2:
case CGM6_MAKE_EFFECT_3:
case CGM6_MAKE_EFFECT_4:
case CGM6_MAKE_EFFECT_5:
case CGM6_MAKE_EFFECT_6:
case CGM6_MAKE_EFFECT_7:
case CGM6_MAKE_EFFECT_8:
2023-05-04 20:30:52 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
sfxManager.MakeEffect_Normal(SFX_EXP_GREN_PUDDLE + iType, vStart, vEnd);
2023-05-04 20:30:52 +02:00
break;
case CGM6_MAKE_CRATE_DEBRIS:
case CGM6_MAKE_WINDOW_DEBRIS:
2023-07-05 21:24:23 +02:00
{
str sEffect;
char cTmp[8];
vec3_t axis[3];
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadByte();
// get the integer as string
snprintf(cTmp, sizeof(cTmp), "%d", iLarge);
if (iType == CGM6_MAKE_CRATE_DEBRIS) {
2023-07-05 21:24:23 +02:00
sEffect = "models/fx/crates/debris_";
} else {
sEffect = "models/fx/windows/debris_";
}
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
sEffect += cTmp;
sEffect += ".tik";
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
VectorSet(axis[0], 0, 0, 1);
VectorSet(axis[1], 0, 1, 0);
VectorSet(axis[2], 1, 0, 0);
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
cgi.R_SpawnEffectModel(sEffect.c_str(), vStart, axis);
}
break;
2023-05-04 20:30:52 +02:00
case CGM6_BULLET_NO_BARREL_1:
2023-07-05 21:24:23 +02:00
vTmp[0] = cgi.MSG_ReadCoord();
vTmp[1] = cgi.MSG_ReadCoord();
vTmp[2] = cgi.MSG_ReadCoord();
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
2023-05-04 20:30:52 +02:00
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
2023-07-05 21:24:23 +02:00
iLarge = cgi.MSG_ReadBits(1);
2023-05-04 20:30:52 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue);
break;
case CGM6_BULLET_NO_BARREL_2:
2023-05-04 20:30:52 +02:00
memset(vTmp, 0, sizeof(vTmp));
2023-07-05 21:24:23 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
2023-05-04 20:30:52 +02:00
vEndArray[0][0] = cgi.MSG_ReadCoord();
vEndArray[0][1] = cgi.MSG_ReadCoord();
vEndArray[0][2] = cgi.MSG_ReadCoord();
2023-07-05 21:24:23 +02:00
iLarge = cgi.MSG_ReadBits(1);
2023-05-04 20:30:52 +02:00
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
break;
case CGM6_HUDDRAW_SHADER:
2023-05-04 20:30:52 +02:00
iInfo = cgi.MSG_ReadByte();
strcpy(cgi.HudDrawElements[iInfo].shaderName, cgi.MSG_ReadString());
2023-07-05 21:24:23 +02:00
cgi.HudDrawElements[iInfo].string[0] = 0;
cgi.HudDrawElements[iInfo].pFont = NULL;
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].fontName[0] = 0;
// set the shader
CG_HudDrawShader(iInfo);
break;
case CGM6_HUDDRAW_ALIGN:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].iHorizontalAlign = cgi.MSG_ReadBits(2);
2023-07-05 21:24:23 +02:00
cgi.HudDrawElements[iInfo].iVerticalAlign = cgi.MSG_ReadBits(2);
2023-05-04 20:30:52 +02:00
break;
case CGM6_HUDDRAW_RECT:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].iX = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iY = cgi.MSG_ReadShort();
cgi.HudDrawElements[iInfo].iWidth = cgi.MSG_ReadShort();
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].iHeight = cgi.MSG_ReadShort();
break;
case CGM6_HUDDRAW_VIRTUALSIZE:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].bVirtualScreen = cgi.MSG_ReadBits(1);
break;
case CGM6_HUDDRAW_COLOR:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].vColor[0] = cgi.MSG_ReadByte() / 255.0;
cgi.HudDrawElements[iInfo].vColor[1] = cgi.MSG_ReadByte() / 255.0;
cgi.HudDrawElements[iInfo].vColor[2] = cgi.MSG_ReadByte() / 255.0;
break;
case CGM6_HUDDRAW_ALPHA:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].vColor[3] = cgi.MSG_ReadByte() / 255.0;
break;
case CGM6_HUDDRAW_STRING:
2023-07-05 21:24:23 +02:00
iInfo = cgi.MSG_ReadByte();
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].hShader = 0;
strcpy(cgi.HudDrawElements[iInfo].string, cgi.MSG_ReadString());
break;
case CGM6_HUDDRAW_FONT:
2023-05-04 20:30:52 +02:00
iInfo = cgi.MSG_ReadByte();
strcpy(cgi.HudDrawElements[iInfo].fontName, cgi.MSG_ReadString());
2023-07-05 21:24:23 +02:00
cgi.HudDrawElements[iInfo].hShader = 0;
2023-05-04 20:30:52 +02:00
cgi.HudDrawElements[iInfo].shaderName[0] = 0;
// load the font
CG_HudDrawFont(iInfo);
break;
case CGM6_NOTIFY_KILL:
case CGM6_NOTIFY_HIT:
2023-07-05 21:24:23 +02:00
{
int iOldEnt;
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
iOldEnt = current_entity_number;
current_entity_number = cg.snap->ps.clientNum;
if (iType == CGM6_NOTIFY_HIT) {
2023-07-05 21:24:23 +02:00
commandManager.PlaySound("dm_kill_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1);
} else {
commandManager.PlaySound("dm_hit_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1);
}
current_entity_number = iOldEnt;
}
break;
2023-05-04 20:30:52 +02:00
case CGM6_VOICE_CHAT:
2023-07-05 21:24:23 +02:00
{
int iOldEnt;
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
iLarge = cgi.MSG_ReadBits(1);
iInfo = cgi.MSG_ReadBits(6);
szTmp = cgi.MSG_ReadString();
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
iOldEnt = current_entity_number;
2023-05-04 20:30:52 +02:00
2023-07-05 21:24:23 +02:00
if (iLarge) {
current_entity_number = iInfo;
commandManager.PlaySound(szTmp, vStart, CHAN_LOCAL, -1, -1, -1, 0);
} else {
current_entity_number = cg.snap->ps.clientNum;
commandManager.PlaySound(szTmp, vStart, CHAN_AUTO, -1, -1, -1, 1);
}
current_entity_number = iOldEnt;
}
2023-05-04 20:30:52 +02:00
break;
default:
cgi.Error(ERR_DROP, "CG_ParseCGMessage: Unknown CGM message type");
break;
2023-05-04 20:30:52 +02:00
}
2023-05-04 21:07:44 +02:00
bMoreCGameMessages = cgi.MSG_ReadBits(1);
2023-05-04 20:30:52 +02:00
}
2023-05-01 00:08:43 +02:00
}
2023-07-05 21:24:23 +02:00
void CG_InitCGMessageAPI(clientGameExport_t *cge)
2023-07-02 19:18:37 +02:00
{
if (cg_protocol >= PROTOCOL_MOHTA_MIN) {
2023-07-05 21:24:23 +02:00
cge->CG_ParseCGMessage = &CG_ParseCGMessage_ver_15;
} else {
2023-07-05 21:24:23 +02:00
cge->CG_ParseCGMessage = &CG_ParseCGMessage_ver_6;
}
}