ambient_generic: Restructure and network more efficiently.

Client: add support for modelevent 1008 (CHAN_VOICE sound) and 1005 (plays Sentence)
This commit is contained in:
Marco Cawthorne 2022-04-30 14:02:25 -07:00
parent 59d46e1f63
commit cdfae26413
Signed by: eukara
GPG Key ID: C196CD8BA993248A
16 changed files with 387 additions and 75 deletions

View File

@ -82,7 +82,7 @@ Entity_EntityUpdate(float type, float new)
Decal_Parse();
break;
case ENT_AMBIENTSOUND:
Sound_ParseLoopingEntity(self, new);
ambient_generic_ReadEntity(new);
break;
case ENT_OLDCAMERA:
trigger_camera tc = (trigger_camera)self;

View File

@ -3,7 +3,6 @@ fog.qc
font.qc
sky.qc
music.qc
sound.qc
sentences.qc
prints.qc
voice.qc

View File

@ -28,7 +28,20 @@ Event_ProcessModel(float flTimeStamp, int iCode, string strData)
{
switch(iCode) {
case 1004:
sound(self, CHAN_BODY, strData, 1.0f, ATTN_NORM);
if (substring(strData, 0, 1) == "*")
sound(self, CHAN_BODY, substring(strData, 1, -1), 1.0f, ATTN_NORM);
else
sound(self, CHAN_BODY, strData, 1.0f, ATTN_NORM);
break;
case 1005:
NSTalkMonster targ = (NSTalkMonster)self;
targ.Sentence(strData);
break;
case 1008:
if (substring(strData, 0, 1) == "*")
sound(self, CHAN_VOICE, substring(strData, 1, -1), 1.0f, ATTN_NORM);
else
sound(self, CHAN_VOICE, strData, 1.0f, ATTN_NORM);
break;
case 5004: /* view model sound */
localsound(strData, CHAN_AUTO, 1.0);
@ -53,6 +66,8 @@ Event_ProcessModel(float flTimeStamp, int iCode, string strData)
pSeat->m_eMuzzleflash.scale = 0.25;
pSeat->m_eMuzzleflash.skin = pSeat->m_iVMBones + 3;
break;
default:
print(sprintf("Unknown model event: %f %i %S\n", flTimeStamp, iCode, strData));
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class CCSAmbientSound {
float m_flVolume;
float m_flAttn;
float m_flPitch;
string m_strSample;
};
void
Sound_ParseLoopingEntity(entity sndent, float isNew)
{
float flFlags;
CCSAmbientSound new = (CCSAmbientSound)sndent;
if (isNew) {
spawnfunc_CCSAmbientSound();
}
flFlags = readfloat();
if (flFlags & 1) {
new.origin[0] = readcoord();
new.origin[1] = readcoord();
new.origin[2] = readcoord();
setorigin(new, new.origin);
new.m_flVolume = readfloat();
new.m_flAttn = readbyte();
new.m_flPitch = readfloat();
}
if (flFlags & 2) {
new.m_strSample = readstring();
}
sound(new, CHAN_VOICE, new.m_strSample, new.m_flVolume, new.m_flAttn, new.m_flPitch);
}

View File

@ -11,7 +11,6 @@ server/info_null.qc
server/info_notnull.qc
server/info_intermission.qc
server/button_target.qc
server/ambient_generic.qc
server/cycler.qc
server/cycler_sprite.qc
server/env_beam.qc

View File

@ -15,6 +15,7 @@ shared/NSVehicle.qc
shared/NSMonster.qc
shared/NSTalkMonster.qc
shared/NSProjectile.qc
shared/ambient_generic.qc
shared/decals.qc
shared/spraylogo.qc
shared/func_friction.qc

View File

@ -41,7 +41,7 @@ class NSVehicle:NSSurfacePropEntity
virtual bool(void) IsLocalDriver;
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
virtual void(float, float) ReadEntity;
virtual void(float, float) ReceiveEntity;
virtual void(void) UpdateView;
virtual bool(void) HideViewWeapon;
virtual bool(void) HideCrosshair;

View File

@ -104,7 +104,7 @@ NSVehicle::PredictPostFrame(void)
}
void
NSVehicle::ReadEntity(float fChanged, float new)
NSVehicle::ReceiveEntity(float fChanged, float new)
{
if (fChanged & VEHFL_CHANGED_ORIGIN) {
origin[0] = readcoord();
@ -416,6 +416,6 @@ basevehicle_readentity(float isnew)
if (isnew)
spawnfunc_NSVehicle();
veh.ReadEntity(flags, isnew);
veh.ReceiveEntity(flags, isnew);
}
#endif

View File

@ -0,0 +1,348 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*QUAKED ambient_generic (1 1 1) (-8 -8 -8) (8 8 8) AS_ARADIUS AS_SRADIUS AS_MRADIUS AS_LRADIUS AS_SILENT AS_NOTTOGGLED
Plays a sound sample of whatever format the engine is configured to support.
-------- KEYS --------
"targetname" : Name
"target" : Target when triggered.
"killtarget" : Target to kill when triggered.
"message" : Sound file to play
"volume" : Playback volume from 0.0 to 1.0
"pitch" : Playback pitch from 0.0 to 2.0
-------- SPAWNFLAGS --------
AS_ARADIUS : Plays the sound everywhere. Heard by everyone.
AS_SRADIUS : Small playback radius.
AS_MRADIUS : Medium playback radius.
AS_LRADIUS : Large playback radius.
AS_SILENT : Start silent, trigger to make it play!
AS_NOTTOGGLED : Don't toggle playback. When triggered, only play the sample once.
-------- NOTES --------
If you want it to loop, you have to give the file itself a loop flag.
-------- TRIVIA --------
This entity was introduced in Half-Life (1998).
*/
enumflags
{
AS_ARADIUS,
AS_SRADIUS,
AS_MRADIUS,
AS_LRADIUS,
AS_SILENT,
AS_NOTTOGGLED
};
enumflags
{
AMBIENT_PATH,
AMBIENT_VOLUME,
AMBIENT_RADIUS,
AMBIENT_PITCH,
AMBIENT_ORIGIN
};
class ambient_generic:NSPointTrigger
{
/* networked attributes */
PREDICTED_STRING(m_strActivePath);
PREDICTED_FLOAT(m_flVolume);
PREDICTED_FLOAT(m_flRadius);
PREDICTED_FLOAT(m_flPitch);
bool m_bToggle;
bool m_bLoops;
/* spawn values */
string m_strSpawnPath;
float m_flSpawnVolume;
float m_flSpawnPitch;
void(void) ambient_generic;
/* overrides */
#ifdef SERVER
virtual void(float) Save;
virtual void(string, string) Restore;
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
virtual void(void) Respawn;
virtual void(entity, int) UseNormal;
virtual void(entity, int) UseLoop;
#else
virtual void(float, float) ReceiveEntity;
#endif
virtual void(string, string) SpawnKey;
virtual void(void) OnRemoveEntity;
};
void
ambient_generic::OnRemoveEntity(void)
{
sound(this, CHAN_VOICE, "common/null.wav", 0.1f, 0);
}
#ifdef SERVER
void
ambient_generic::Save(float handle)
{
SaveString(handle, "activepath", m_strActivePath);
SaveString(handle, "soundpath", m_strSpawnPath);
SaveFloat(handle, "volume", m_flVolume);
SaveFloat(handle, "radius", m_flRadius);
SaveFloat(handle, "pitch", m_flPitch);
SaveInt(handle, "toggleswitch", m_bToggle);
SaveInt(handle, "loop", m_bLoops);
super::Save(handle);
}
void
ambient_generic::Restore(string strKey, string strValue)
{
switch (strKey) {
case "loop":
m_bLoops = ReadInt(strValue);
break;
case "toggleswitch":
m_bToggle = ReadInt(strValue);
break;
case "pitch":
m_flPitch = ReadFloat(strValue);
break;
case "radius":
m_flRadius = ReadFloat(strValue);
break;
case "volume":
m_flVolume = ReadFloat(strValue);
break;
case "soundpath":
m_strSpawnPath = ReadString(strValue);
break;
case "activepath":
m_strActivePath = ReadString(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
void
ambient_generic::UseNormal(entity act, int state)
{
dprint(sprintf("Sound once: %S Volume: %f; Radius: %d; Pitch: %d\n", \
m_strActivePath, m_flVolume, m_flRadius, m_flPitch));
sound(this, CHAN_VOICE, m_strActivePath, m_flVolume, m_flRadius, m_flPitch);
}
void
ambient_generic::UseLoop(entity act, int state)
{
if (m_bToggle == TRUE) {
dprint(sprintf("^2ambient_generic::^3UseLoop^7: %s stops `%s`\n",
target, m_strActivePath));
m_strActivePath = "common/null.wav";
} else {
m_strActivePath = m_strSpawnPath;
dprint(sprintf("^2ambient_generic::^3UseLoop^7: %s plays `%s`\n",
target, m_strActivePath));
}
m_bToggle = 1 - m_bToggle;
}
void
ambient_generic::Respawn(void)
{
SetSize([0,0,0], [0,0,0]);
SetOrigin(GetSpawnOrigin());
m_strActivePath = m_strSpawnPath;
m_flPitch = m_flSpawnPitch;
m_flVolume = m_flSpawnVolume;
/* handle volume */
if (!m_flSpawnVolume) {
m_flVolume = 1.0f;
}
/* attenuation */
if (HasSpawnFlags(AS_ARADIUS)) {
m_flRadius = ATTN_NONE;
} else if (HasSpawnFlags(AS_SRADIUS)) {
m_flRadius = ATTN_IDLE;
} else if (HasSpawnFlags(AS_MRADIUS)) {
m_flRadius = ATTN_STATIC;
} else if (HasSpawnFlags(AS_LRADIUS)) {
m_flRadius = ATTN_NORM;
} else {
m_flRadius = ATTN_STATIC;
}
pvsflags = PVSF_USEPHS;
if (HasSpawnFlags(AS_NOTTOGGLED)) {
Trigger = UseNormal;
m_bLoops = false;
} else {
m_bLoops = true;
/* set our sample up */
if (HasSpawnFlags(AS_SILENT)) {
m_bToggle = false;
m_strActivePath = "common/null.wav";
} else {
m_bToggle = true;
m_strActivePath = m_strSpawnPath;
}
Trigger = UseLoop;
}
}
void
ambient_generic::EvaluateEntity(void)
{
if (ATTR_CHANGED(origin))
SetSendFlags(AMBIENT_ORIGIN);
if (ATTR_CHANGED(m_strActivePath))
SetSendFlags(AMBIENT_PATH);
if (ATTR_CHANGED(m_flVolume))
SetSendFlags(AMBIENT_VOLUME);
if (ATTR_CHANGED(m_flRadius))
SetSendFlags(AMBIENT_RADIUS);
if (ATTR_CHANGED(m_flPitch))
SetSendFlags(AMBIENT_PITCH);
SAVE_STATE(origin);
SAVE_STATE(m_strActivePath);
SAVE_STATE(m_flVolume);
SAVE_STATE(m_flRadius);
SAVE_STATE(m_flPitch);
}
float
ambient_generic::SendEntity(entity ePEnt, float flChanged)
{
/* only override when we're doing the toggle guff */
if (m_bLoops == false)
return (0);
WriteByte(MSG_ENTITY, ENT_AMBIENTSOUND);
WriteFloat(MSG_ENTITY, flChanged);
if (flChanged & AMBIENT_ORIGIN) {
WriteCoord(MSG_ENTITY, origin[0]);
WriteCoord(MSG_ENTITY, origin[1]);
WriteCoord(MSG_ENTITY, origin[2]);
}
if (flChanged & AMBIENT_PATH)
WriteString(MSG_ENTITY, m_strActivePath);
if (flChanged & AMBIENT_VOLUME)
WriteFloat(MSG_ENTITY, m_flVolume);
if (flChanged & AMBIENT_RADIUS)
WriteByte(MSG_ENTITY, m_flRadius);
if (flChanged & AMBIENT_PITCH)
WriteFloat(MSG_ENTITY, m_flPitch);
return (1);
}
#else
void
ambient_generic::ReceiveEntity(float isnew, float flChanged)
{
if (flChanged & AMBIENT_ORIGIN) {
origin[0] = readcoord();
origin[1] = readcoord();
origin[2] = readcoord();
setsize(this, [0,0,0], [0,0,0]);
setorigin(this, origin);
}
if (flChanged & AMBIENT_PATH)
m_strActivePath = readstring();
if (flChanged & AMBIENT_VOLUME)
m_flVolume = readfloat();
if (flChanged & AMBIENT_RADIUS)
m_flRadius = readbyte();
if (flChanged & AMBIENT_PITCH)
m_flPitch = readfloat();
dprint(sprintf("Sound received: %S Volume: %f; Radius: %d; Pitch: %d\n", m_strActivePath, m_flVolume, m_flRadius, m_flPitch));
//sound(this, CHAN_VOICE, m_strActivePath, m_flVolume, m_flRadius, m_flPitch);
soundupdate(this, CHAN_VOICE, m_strActivePath, m_flVolume, m_flRadius, m_flPitch, 0, 0);
}
#endif
void
ambient_generic::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "message":
m_strSpawnPath = strValue;
precache_sound(m_strSpawnPath);
message = __NULL__;
break;
case "volume":
m_flSpawnVolume = stof(strValue);
break;
case "pitch":
m_flSpawnPitch = stof(strValue);
break;
/* backwards compat */
case "health":
m_flSpawnVolume = stof(strValue) * 0.1f;
break;
/* TODO: currently unimplemented */
case "preset":
case "volstart":
case "fadein":
case "fadeout":
case "pitchstart":
case "spinup":
case "spindown":
case "lfotype":
case "lforate":
case "lfomodpitch":
case "lfomodvol":
case "cspinup":
break;
default:
super::SpawnKey(strKey, strValue);
break;
}
}
void
ambient_generic::ambient_generic(void)
{
super::NSPointTrigger();
}
#ifdef CLIENT
void
ambient_generic_ReadEntity(float new)
{
ambient_generic me = (ambient_generic)self;
if (new) {
spawnfunc_ambient_generic();
}
me.ReceiveEntity(new, readfloat());
}
#endif

View File

@ -89,7 +89,7 @@ env_fog_controller:NSPointTrigger
virtual float(void) FogRender;
virtual void(void) FogUpdate;
virtual void(void) RendererRestarted;
virtual void(float,float) ReadEntity;
virtual void(float,float) ReceiveEntity;
#else
/* main spawn attributes */
int m_iSpawnEnable;
@ -200,7 +200,7 @@ env_fog_controller::RendererRestarted(void)
}
void
env_fog_controller::ReadEntity(float flSendFlags, float flNew)
env_fog_controller::ReceiveEntity(float flSendFlags, float flNew)
{
if (flSendFlags & ENVFOG_CHANGED_ACTIVE)
m_iFogActive = readbyte();
@ -539,6 +539,6 @@ env_fog_controller_readentity(float isnew)
if (isnew)
spawnfunc_env_fog_controller();
fog.ReadEntity(flags, isnew);
fog.ReceiveEntity(flags, isnew);
}
#endif

View File

@ -90,7 +90,7 @@ class func_tankmortar:NSVehicle
#ifdef CLIENT
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
virtual void(float, float) ReadEntity;
virtual void(float, float) ReceiveEntity;
virtual void(void) UpdateView;
#else
virtual float(entity, float) SendEntity;
@ -123,7 +123,7 @@ func_tankmortar::PredictPostFrame(void)
}
void
func_tankmortar::ReadEntity(float fChanged, float new)
func_tankmortar::ReceiveEntity(float fChanged, float new)
{
if (fChanged & VEHFL_CHANGED_ORIGIN) {
origin[0] = readcoord();
@ -457,6 +457,6 @@ func_tankmortar_readentity(float isnew)
if (isnew)
spawnfunc_func_tankmortar();
veh.ReadEntity(flags, isnew);
veh.ReceiveEntity(flags, isnew);
}
#endif

View File

@ -61,7 +61,7 @@ class prop_rope:NSEntity
#ifdef CLIENT
virtual float() predraw;
virtual void(float,float) ReadEntity;
virtual void(float,float) ReceiveEntity;
virtual void(vector, vector, vector) DrawSegment;
#else
virtual void(void) Respawn;
@ -146,7 +146,7 @@ prop_rope::predraw(void)
}
void
prop_rope::ReadEntity(float flSendFlags, float new)
prop_rope::ReceiveEntity(float flSendFlags, float new)
{
if (flSendFlags & PROPROPE_CHANGED_MAT)
m_strShader = readstring();
@ -301,6 +301,6 @@ prop_rope_readentity(float isnew)
if (isnew)
spawnfunc_prop_rope();
rope.ReadEntity(flags, isnew);
rope.ReceiveEntity(flags, isnew);
}
#endif

View File

@ -110,7 +110,7 @@ class prop_vehicle_driveable:NSVehicle
virtual bool(void) HideViewWeapon;
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
virtual void(float, float) ReadEntity;
virtual void(float, float) ReceiveEntity;
virtual void(void) UpdateView;
#else
virtual void(void) Respawn;
@ -684,7 +684,7 @@ prop_vehicle_driveable::Respawn(void)
#ifdef CLIENT
void
prop_vehicle_driveable::ReadEntity(float flSendFlags, float flNew)
prop_vehicle_driveable::ReceiveEntity(float flSendFlags, float flNew)
{
if (flSendFlags & VEHFL_DRIVER) {
driver_entnum = readentitynum();
@ -899,6 +899,6 @@ prop_vehicle_driveable_readentity(float isnew)
if (isnew)
spawnfunc_prop_vehicle_driveable();
veh.ReadEntity(flags, isnew);
veh.ReceiveEntity(flags, isnew);
}
#endif

View File

@ -43,11 +43,9 @@ Mapcycle_Init(void)
/* read the lines in, see if the map exists and define an enumerated alias */
while ((temp = fgets(fs_mapcycle))) {
#if 0
print(sprintf( "checking for map %s whichpack result: %S\n", strcat("maps/", temp, ".bsp"), whichpack(strcat("maps/", temp, ".bsp"))));
if (!whichpack(strcat("maps/", temp, ".bsp")))
if not (whichpack(strcat("maps/", temp, ".bsp")))
continue;
#endif
readcmd(sprintf("alias m%i \"map %s;alias nextmap m%i\"\n", mapcount, temp, mapcount + 1i));
if (mapname == lastmap)

View File

@ -258,10 +258,10 @@ CSEv_CallVote_s(string text)
tokenize(text);
switch (argv(0)) {
case "map":
/*if (whichpack(sprintf("maps/%s.bsp", argv(1))) == __NULL__) {
if not (whichpack(sprintf("maps/%s.bsp", argv(1)))) {
sprint(self, PRINT_CHAT, sprintf("Map '%s' not available on server.\n", argv(1)));
break;
}*/
}
case "kick":
case "slowmo":
case "timelimit":

View File

@ -19,10 +19,12 @@
#define PREDICTED_FLOAT(x) float x; float x ##_net
#define PREDICTED_VECTOR(x) vector x; vector x ##_net
#define PREDICTED_ENT(x) entity x; entity x ##_net
#define PREDICTED_STRING(x) string x; string x ##_net
#define PREDICTED_INT_N(x) int x ##_net
#define PREDICTED_FLOAT_N(x) float x ##_net
#define PREDICTED_VECTOR_N(x) vector x ##_net
#define PREDICTED_STRING_N(x) string x ##_net
#define ROLL_BACK(x) x = x ##_net
#define SAVE_STATE(x) x ##_net = x