openmohaa/code/cgame/cg_parsemsg.cpp
2023-05-04 21:07:44 +02:00

496 lines
15 KiB
C++

/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
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
#include "cg_local.h"
#include "cg_parsemsg.h"
#include "cg_specialfx.h"
#include "str.h"
extern int current_entity_number;
typedef struct {
vec3_t i_vBarrel;
vec3_t i_vStart;
vec3_t* i_vEnd;
int i_iNumBullets;
qboolean iLarge;
int iTracerVisible;
qboolean bIgnoreEntities;
} bullet_tracer_t;
#define MAX_BULLET_TRACERS 32
#define MAX_BULLET_TRACE_BULLETS 1024
#define MAX_IMPACTS 64
static int bullet_tracers_count;
static int bullet_tracer_bullets_count;
static int wall_impact_count;
static int flesh_impact_count;
static bullet_tracer_t bullet_tracers[MAX_BULLET_TRACERS];
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];
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) {
bullet_tracer_t* bullet_tracer;
int i;
if (bullet_tracer_bullets_count > MAX_BULLET_TRACERS) {
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);
bullet_tracer->i_vEnd = &bullet_tracer_bullets[bullet_tracers_count];
bullet_tracer->i_iNumBullets = i_iNumBullets;
for (i = 0; i < i_iNumBullets; ++i)
{
bullet_tracer_bullets[bullet_tracers_count][0] = (*i_vEnd)[i];
bullet_tracer_bullets[bullet_tracers_count][1] = (*i_vEnd)[i + 1];
bullet_tracer_bullets[bullet_tracers_count++][2] = (*i_vEnd)[i + 2];
}
bullet_tracer->iLarge = iLarge;
bullet_tracer->iTracerVisible = iTracerVisible;
bullet_tracer->bIgnoreEntities = bIgnoreEntities;
}
static void CG_MakeBubbleTrail(vec3_t i_vStart, vec3_t i_vEnd, int iLarge) {
// FIXME: unimplemented
}
void CG_AddBulletTracers()
{
// FIXME: unimplemented
}
void CG_AddBulletImpacts()
{
// FIXME: unimplemented
}
void CG_MakeExplosionEffect(float* vPos, int iType) {
// FIXME: unimplemented
}
void CG_ParseCGMessage()
{
int i;
int iType;
int iLarge;
int iInfo;
int iCount;
char* szTmp;
vec3_t vStart, vEnd, vTmp;
vec3_t vEndArray[MAX_IMPACTS];
qboolean bMoreCGameMessages = qtrue;
while (bMoreCGameMessages) {
iType = cgi.MSG_ReadBits(6);
switch (iType)
{
case 1:
case 2:
case 5:
if (iType == 1)
{
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 != 1)
{
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(1);
if (iType == 1) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
}
else if (iType == 2) {
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
}
else {
CG_MakeBubbleTrail(vStart, vEndArray[0], iLarge);
}
break;
case 3:
case 4:
if (iType == 3)
{
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(1);
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);
}
break;
case 6:
case 7:
case 8:
case 9:
case 10:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
iLarge = cgi.MSG_ReadBits(1);
switch (iType)
{
case 6:
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] = 0;
wall_impact_count++;
}
break;
case 7:
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 8:
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 9:
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] = (iLarge != 0) + 2;
wall_impact_count++;
}
break;
case 10:
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] = (iLarge != 0) + 4;
wall_impact_count++;
}
break;
default:
continue;
}
break;
case 11:
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 12:
case 13:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
CG_MakeExplosionEffect(vStart, iType);
break;
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
vStart[0] = cgi.MSG_ReadCoord();
vStart[1] = cgi.MSG_ReadCoord();
vStart[2] = cgi.MSG_ReadCoord();
cgi.MSG_ReadDir(vEnd);
sfxManager.MakeEffect_Normal(iType + 67, vStart, vEnd);
break;
case 23:
case 24:
{
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
itoa(iLarge, cTmp, 10);
iLarge = cgi.MSG_ReadByte();
if (iType == 23) {
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 25:
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(1);
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue);
break;
case 26:
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);
CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue);
break;
case 27:
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 28:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].iHorizontalAlign = cgi.MSG_ReadBits(2);
cgi.HudDrawElements[iInfo].iVerticalAlign = cgi.MSG_ReadBits(2);
break;
case 29:
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 30:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].bVirtualScreen = cgi.MSG_ReadBits(1);
break;
case 31:
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 32:
cgi.HudDrawElements[iInfo].vColor[3] = cgi.MSG_ReadByte() / 255.0;
break;
case 33:
iInfo = cgi.MSG_ReadByte();
cgi.HudDrawElements[iInfo].hShader = 0;
strcpy(cgi.HudDrawElements[iInfo].string, cgi.MSG_ReadString());
break;
case 34:
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 35:
case 36:
{
int iOldEnt;
iOldEnt = current_entity_number;
current_entity_number = cg.snap->ps.clientNum;
if (iType == 36) {
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 37:
{
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;
}
bMoreCGameMessages = cgi.MSG_ReadBits(1);
}
// FIXME: unimplemented
}