2019-09-01 02:18:15 +00:00
|
|
|
/*
|
2020-04-07 12:46:23 +00:00
|
|
|
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
|
2019-09-01 02:18:15 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2019-03-13 20:56:43 +00:00
|
|
|
|
2020-04-22 18:33:15 +00:00
|
|
|
/* a lot of the rendering info is assembled with the following url:
|
|
|
|
* https://sites.google.com/site/svenmanor/rendermodes
|
|
|
|
* for reference. I thank thee fellow soldiers at sven manor! */
|
|
|
|
|
2020-04-20 04:44:47 +00:00
|
|
|
var int autocvar_cl_showtriggers = FALSE;
|
|
|
|
|
2019-03-13 20:56:43 +00:00
|
|
|
string __fullspawndata;
|
2020-03-26 11:19:27 +00:00
|
|
|
string Sentences_GetSamples(string);
|
2019-03-13 20:56:43 +00:00
|
|
|
|
2019-03-19 19:01:24 +00:00
|
|
|
class CBaseEntity
|
|
|
|
{
|
2020-03-30 14:22:24 +00:00
|
|
|
#ifdef GS_RENDERFX
|
|
|
|
int m_iRenderFX;
|
|
|
|
float m_iRenderMode;
|
|
|
|
float m_flRenderAmt;
|
|
|
|
vector m_vecRenderColor;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int m_iBody;
|
2020-03-26 11:19:27 +00:00
|
|
|
float m_flSentenceTime;
|
|
|
|
sound_t *m_pSentenceQue;
|
|
|
|
int m_iSentenceCount;
|
|
|
|
int m_iSentencePos;
|
|
|
|
|
2019-03-13 20:56:43 +00:00
|
|
|
string targetname;
|
|
|
|
string target;
|
2020-03-23 16:25:03 +00:00
|
|
|
float spawnflags;
|
2019-03-19 19:01:24 +00:00
|
|
|
|
2020-04-12 13:50:42 +00:00
|
|
|
void(void) CBaseEntity;
|
|
|
|
virtual void(void) Init;
|
|
|
|
virtual void(void) Initialized;
|
2019-03-13 20:56:43 +00:00
|
|
|
virtual void(string, string) SpawnKey;
|
2020-03-26 11:19:27 +00:00
|
|
|
virtual void(string) Sentence;
|
2020-04-12 13:50:42 +00:00
|
|
|
virtual void(void) ProcessWordQue;
|
2020-01-16 04:43:12 +00:00
|
|
|
virtual void(float flChanged) ReadEntity;
|
2020-03-03 21:44:35 +00:00
|
|
|
virtual float(void) predraw;
|
2020-04-12 13:50:42 +00:00
|
|
|
virtual void(void) postdraw;
|
2020-03-30 14:22:24 +00:00
|
|
|
|
|
|
|
#ifdef GS_RENDERFX
|
2020-04-12 13:50:42 +00:00
|
|
|
virtual void(void) RenderFXPass;
|
2020-03-30 14:22:24 +00:00
|
|
|
#endif
|
2019-03-13 20:56:43 +00:00
|
|
|
};
|
|
|
|
|
2020-03-30 14:22:24 +00:00
|
|
|
#ifdef GS_RENDERFX
|
|
|
|
void
|
|
|
|
CBaseEntity::RenderFXPass(void)
|
|
|
|
{
|
2020-03-30 14:56:00 +00:00
|
|
|
colormod = m_vecRenderColor;
|
|
|
|
alpha = m_flRenderAmt;
|
2020-03-30 14:22:24 +00:00
|
|
|
|
|
|
|
switch (m_iRenderMode) {
|
|
|
|
case RM_NORMAL:
|
2020-03-30 14:56:00 +00:00
|
|
|
alpha = 1.0f;
|
2020-03-30 14:22:24 +00:00
|
|
|
break;
|
|
|
|
case RM_COLOR:
|
|
|
|
break;
|
|
|
|
case RM_TEXTURE:
|
|
|
|
break;
|
|
|
|
case RM_GLOW:
|
2020-05-04 03:48:19 +00:00
|
|
|
vector vecPlayer;
|
|
|
|
#ifdef WASTES
|
|
|
|
vecPlayer = [0,0,0];
|
|
|
|
#else
|
2020-05-02 04:38:02 +00:00
|
|
|
int s = (float)getproperty(VF_ACTIVESEAT);
|
|
|
|
pSeat = &g_seats[s];
|
2020-05-04 03:48:19 +00:00
|
|
|
vecPlayer = pSeat->m_vecPredictedOrigin;
|
|
|
|
#endif
|
2020-05-02 04:38:02 +00:00
|
|
|
|
|
|
|
if (checkpvs(vecPlayer, this) == FALSE) {
|
|
|
|
alpha -= clframetime;
|
|
|
|
}
|
|
|
|
|
|
|
|
other = world;
|
|
|
|
traceline(this.origin, vecPlayer, MOVE_OTHERONLY, this);
|
|
|
|
|
|
|
|
/* If we can't trace against the player, or are two close, fade out */
|
|
|
|
if (trace_fraction < 1.0f || vlen(origin - vecPlayer) < 128) {
|
|
|
|
alpha -= clframetime;
|
|
|
|
} else {
|
|
|
|
alpha += clframetime;
|
|
|
|
}
|
|
|
|
|
|
|
|
alpha = bound(0, alpha, 1.0f);
|
|
|
|
effects = EF_ADDITIVE | EF_FULLBRIGHT;
|
|
|
|
|
|
|
|
if (alpha > 0) {
|
|
|
|
float falpha;
|
|
|
|
|
|
|
|
/* Scale the glow somewhat with the players distance */
|
|
|
|
scale = bound(1, vlen(vecPlayer - origin) / 256, 4);
|
|
|
|
|
|
|
|
/* Fade out when the player is starting to move away */
|
|
|
|
falpha = 1 - bound(0, vlen(vecPlayer - origin) / 1024, 1);
|
|
|
|
falpha *= alpha;
|
|
|
|
|
|
|
|
/* Clamp the alpha by the glows' renderamt value */
|
|
|
|
alpha = bound(0, falpha, m_flRenderAmt);
|
|
|
|
}
|
2020-03-30 14:22:24 +00:00
|
|
|
break;
|
|
|
|
case RM_SOLID:
|
|
|
|
break;
|
|
|
|
case RM_ADDITIVE:
|
2020-04-24 03:39:06 +00:00
|
|
|
effects = EF_ADDITIVE | EF_FULLBRIGHT;
|
2020-03-30 14:22:24 +00:00
|
|
|
break;
|
2020-04-28 08:27:20 +00:00
|
|
|
case RM_FULLBRIGHT:
|
|
|
|
effects = EF_FULLBRIGHT;
|
|
|
|
break;
|
2020-04-20 04:44:47 +00:00
|
|
|
case RM_TRIGGER:
|
|
|
|
if (autocvar_cl_showtriggers) {
|
|
|
|
effects = EF_FULLBRIGHT;
|
|
|
|
alpha = 0.75f;
|
|
|
|
colormod = [1,0,0];
|
|
|
|
} else {
|
|
|
|
alpha = 0.0f;
|
|
|
|
}
|
|
|
|
break;
|
2020-03-30 14:22:24 +00:00
|
|
|
}
|
|
|
|
|
2020-03-30 14:56:00 +00:00
|
|
|
/* messy hologram imitation */
|
|
|
|
if (m_iRenderFX == RFX_HOLOGRAM) {
|
|
|
|
float dist;
|
|
|
|
float r;
|
|
|
|
|
|
|
|
r = random() * 0.5f;
|
|
|
|
makevectors(angles);
|
2020-03-30 16:04:45 +00:00
|
|
|
|
2020-03-30 14:56:00 +00:00
|
|
|
if (cltime & 1) {
|
|
|
|
v_right *= 0.75 + r;
|
|
|
|
renderflags |= RF_USEAXIS;
|
|
|
|
} else if (cltime & 2) {
|
|
|
|
v_up *= 1.0 - (random() * 0.2f);
|
|
|
|
renderflags |= RF_USEAXIS;
|
|
|
|
}
|
2020-03-30 16:04:45 +00:00
|
|
|
|
2020-03-30 14:56:00 +00:00
|
|
|
dist = vlen(getproperty(VF_ORIGIN) - origin);
|
|
|
|
if (dist < 256) {
|
|
|
|
float distalpha = dist / 256;
|
|
|
|
alpha = 1.0 - distalpha;
|
|
|
|
alpha -= r;
|
|
|
|
alpha *= m_flRenderAmt;
|
|
|
|
} else {
|
|
|
|
alpha = 0.00001f;
|
|
|
|
}
|
|
|
|
colormod *= 0.5;
|
|
|
|
effects = EF_ADDITIVE;
|
|
|
|
}
|
2020-03-30 14:22:24 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-26 11:19:27 +00:00
|
|
|
float
|
|
|
|
CBaseEntity::predraw(void)
|
2020-03-03 21:44:35 +00:00
|
|
|
{
|
2020-03-31 07:04:05 +00:00
|
|
|
if (!modelindex) {
|
|
|
|
return PREDRAW_NEXT;
|
|
|
|
}
|
|
|
|
|
2020-03-30 14:22:24 +00:00
|
|
|
#ifdef GS_RENDERFX
|
|
|
|
RenderFXPass();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* mouth flapping action */
|
|
|
|
bonecontrol5 = getchannellevel(this, CHAN_VOICE) * 20;
|
2020-03-03 21:44:35 +00:00
|
|
|
frame1time += clframetime;
|
2020-03-26 11:19:27 +00:00
|
|
|
ProcessWordQue();
|
2020-03-30 14:56:00 +00:00
|
|
|
|
|
|
|
if (alpha > 0.0)
|
|
|
|
addentity(this);
|
|
|
|
|
2020-03-03 21:44:35 +00:00
|
|
|
return PREDRAW_NEXT;
|
|
|
|
}
|
|
|
|
|
2020-03-26 11:19:27 +00:00
|
|
|
void
|
|
|
|
CBaseEntity::ProcessWordQue(void)
|
|
|
|
{
|
|
|
|
if (time < 1 || !m_iSentenceCount) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_flSentenceTime > time) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-07 00:47:21 +00:00
|
|
|
/* hack to get vox working. */
|
|
|
|
string sndpath;
|
|
|
|
int c = tokenizebyseparator(m_pSentenceQue[m_iSentencePos].m_strSnd, "/");
|
|
|
|
if (c > 1) {
|
|
|
|
sndpath = argv(0);
|
|
|
|
} else {
|
|
|
|
sndpath = "vox";
|
|
|
|
}
|
|
|
|
|
|
|
|
sound(this, CHAN_VOICE, sprintf("%s/%s", sndpath, argv(1)), 1.0, ATTN_NORM, 100, SOUNDFLAG_FOLLOW);
|
2020-03-31 07:04:05 +00:00
|
|
|
dprint(sprintf("^2CBaseEntity::^3ProcessWordQue^7: Speaking %s\n", m_pSentenceQue[m_iSentencePos].m_strSnd));
|
2020-03-26 11:19:27 +00:00
|
|
|
m_iSentencePos++;
|
|
|
|
|
|
|
|
if (m_iSentenceCount == m_iSentenceCount) {
|
|
|
|
memfree(m_pSentenceQue);
|
|
|
|
m_iSentenceCount = 0;
|
|
|
|
m_iSentencePos = 0;
|
|
|
|
m_pSentenceQue = 0;
|
|
|
|
} else {
|
2020-04-02 20:43:37 +00:00
|
|
|
m_flSentenceTime = time + m_pSentenceQue[m_iSentenceCount - 1].m_flLength;
|
2020-03-26 11:19:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we'll pass it a sentences.txt word (e.g. !BA_TEST) and start queing it */
|
|
|
|
void
|
|
|
|
CBaseEntity::Sentence(string msg)
|
|
|
|
{
|
|
|
|
/* not defined */
|
|
|
|
if (msg == "") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_iSentenceCount) {
|
|
|
|
memfree(m_pSentenceQue);
|
|
|
|
m_iSentenceCount = 0;
|
|
|
|
m_pSentenceQue = 0;
|
|
|
|
m_iSentencePos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_iSentenceCount = tokenize(Sentences_GetSamples(msg));
|
|
|
|
m_pSentenceQue = memalloc(sizeof(sound_t) * m_iSentenceCount);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_iSentenceCount; i++) {
|
|
|
|
m_pSentenceQue[i].m_strSnd = sprintf("%s.wav", argv(i));
|
2020-04-02 20:43:37 +00:00
|
|
|
m_pSentenceQue[i].m_flLength = soundlength(m_pSentenceQue[i].m_strSnd);
|
2020-03-26 11:19:27 +00:00
|
|
|
m_pSentenceQue[i].m_flPitch = 100;
|
|
|
|
}
|
|
|
|
m_flSentenceTime = time;
|
|
|
|
}
|
|
|
|
|
2020-01-16 04:43:12 +00:00
|
|
|
void CBaseEntity::ReadEntity(float flChanged)
|
|
|
|
{
|
|
|
|
if (flChanged & BASEFL_CHANGED_ORIGIN) {
|
|
|
|
origin[0] = readcoord();
|
|
|
|
origin[1] = readcoord();
|
|
|
|
origin[2] = readcoord();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_ANGLES) {
|
|
|
|
angles[0] = readfloat();
|
|
|
|
angles[1] = readfloat();
|
|
|
|
angles[2] = readfloat();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_MODELINDEX) {
|
|
|
|
modelindex = readshort();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_SOLID) {
|
|
|
|
solid = readbyte();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_MOVETYPE) {
|
|
|
|
movetype = readbyte();
|
2020-01-20 18:35:57 +00:00
|
|
|
|
|
|
|
if (movetype == MOVETYPE_PHYSICS) {
|
|
|
|
movetype = MOVETYPE_NONE;
|
|
|
|
}
|
2020-01-16 04:43:12 +00:00
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_SIZE) {
|
|
|
|
mins[0] = readcoord();
|
|
|
|
mins[1] = readcoord();
|
|
|
|
mins[2] = readcoord();
|
|
|
|
maxs[0] = readcoord();
|
|
|
|
maxs[1] = readcoord();
|
|
|
|
maxs[2] = readcoord();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_FRAME) {
|
2020-03-03 21:44:35 +00:00
|
|
|
frame1time = 0.0;
|
2020-01-16 04:43:12 +00:00
|
|
|
frame = readbyte();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_SKIN) {
|
2020-03-24 07:02:36 +00:00
|
|
|
skin = readbyte() - 128;
|
2020-01-16 04:43:12 +00:00
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_EFFECTS) {
|
|
|
|
effects = readfloat();
|
|
|
|
}
|
2020-03-30 14:22:24 +00:00
|
|
|
if (flChanged & BASEFL_CHANGED_BODY) {
|
|
|
|
m_iBody = readbyte();
|
|
|
|
setcustomskin(this, "", sprintf("geomset 1 %i\n", m_iBody));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GS_RENDERFX
|
|
|
|
if (flChanged & BASEFL_CHANGED_RENDERFX) {
|
|
|
|
m_iRenderFX = readbyte();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_RENDERMODE) {
|
|
|
|
m_iRenderMode = readbyte();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_RENDERCOLOR) {
|
|
|
|
m_vecRenderColor[0] = readfloat();
|
|
|
|
m_vecRenderColor[1] = readfloat();
|
|
|
|
m_vecRenderColor[2] = readfloat();
|
|
|
|
}
|
|
|
|
if (flChanged & BASEFL_CHANGED_RENDERAMT) {
|
|
|
|
m_flRenderAmt = readfloat();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (flChanged & BASEFL_CHANGED_ALPHA) {
|
|
|
|
alpha = readfloat();
|
|
|
|
}
|
|
|
|
#endif
|
2020-01-16 04:43:12 +00:00
|
|
|
|
2020-01-20 18:35:57 +00:00
|
|
|
if (modelindex) {
|
|
|
|
drawmask = MASK_ENGINE;
|
|
|
|
} else {
|
|
|
|
drawmask = 0;
|
|
|
|
}
|
|
|
|
|
2020-01-16 04:43:12 +00:00
|
|
|
setorigin(this, origin);
|
|
|
|
setsize(this, mins, maxs);
|
|
|
|
}
|
|
|
|
|
2019-03-19 19:01:24 +00:00
|
|
|
void CBaseEntity::SpawnKey(string strField, string strKey)
|
|
|
|
{
|
|
|
|
switch (strField) {
|
2020-03-23 16:25:03 +00:00
|
|
|
/* compiler specific stuff */
|
|
|
|
case "angle":
|
|
|
|
case "_minlight":
|
|
|
|
case "_cs":
|
|
|
|
break;
|
2020-03-03 21:44:35 +00:00
|
|
|
case "shadows":
|
|
|
|
if (stof(strKey) == 1) {
|
|
|
|
effects &= ~EF_NOSHADOW;
|
|
|
|
}
|
|
|
|
break;
|
2019-03-13 20:56:43 +00:00
|
|
|
case "targetname":
|
|
|
|
targetname = strKey;
|
|
|
|
break;
|
|
|
|
case "target":
|
|
|
|
target = strKey;
|
|
|
|
break;
|
|
|
|
case "origin":
|
2019-03-19 19:01:24 +00:00
|
|
|
origin = stov(strKey);
|
|
|
|
setorigin(this, origin);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
|
|
|
case "angles":
|
2019-03-19 19:01:24 +00:00
|
|
|
angles = stov(strKey);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
|
|
|
case "model":
|
|
|
|
model = strKey;
|
|
|
|
break;
|
|
|
|
case "style":
|
2019-03-19 19:01:24 +00:00
|
|
|
style = stof(strKey);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
|
|
|
case "color":
|
2019-03-19 19:01:24 +00:00
|
|
|
color = stov(strKey);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
|
|
|
case "movetype":
|
2019-03-19 19:01:24 +00:00
|
|
|
movetype = stof(strKey);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
|
|
|
case "solid":
|
2019-03-19 19:01:24 +00:00
|
|
|
solid = stof(strKey);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
|
|
|
case "scale":
|
2019-03-19 19:01:24 +00:00
|
|
|
scale = stof(strKey);
|
2019-03-13 20:56:43 +00:00
|
|
|
break;
|
2020-03-23 16:25:03 +00:00
|
|
|
case "spawnflags":
|
|
|
|
spawnflags = stof(strKey);
|
|
|
|
break;
|
2019-03-13 20:56:43 +00:00
|
|
|
default:
|
2020-03-23 16:25:03 +00:00
|
|
|
#ifdef GS_DEVELOPER
|
2020-04-12 13:50:42 +00:00
|
|
|
print(sprintf("%s::SpawnKey: Unknown '%s' value '%s'\n",
|
|
|
|
this.classname, strField, strKey));
|
2020-03-23 16:25:03 +00:00
|
|
|
#endif
|
2019-03-13 20:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 13:50:42 +00:00
|
|
|
void CBaseEntity::postdraw(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-03-13 20:56:43 +00:00
|
|
|
void CBaseEntity::Init(void)
|
|
|
|
{
|
2020-04-12 13:50:42 +00:00
|
|
|
isCSQC = TRUE;
|
2020-03-03 21:44:35 +00:00
|
|
|
effects |= EF_NOSHADOW;
|
2019-03-13 20:56:43 +00:00
|
|
|
for (int i = 0; i < (tokenize(__fullspawndata) - 1); i += 2) {
|
|
|
|
SpawnKey(argv(i), argv(i+1));
|
|
|
|
}
|
2019-03-14 19:13:02 +00:00
|
|
|
Initialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBaseEntity::Initialized(void)
|
|
|
|
{
|
2019-03-13 20:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CBaseEntity::CBaseEntity(void)
|
|
|
|
{
|
|
|
|
}
|
2020-03-26 11:19:27 +00:00
|
|
|
|
|
|
|
/* our EV_SENTENCE event */
|
|
|
|
void
|
|
|
|
CBaseEntity_ParseSentence(void)
|
|
|
|
{
|
|
|
|
entity ent;
|
|
|
|
CBaseEntity targ;
|
|
|
|
string sentence;
|
|
|
|
float e;
|
|
|
|
|
|
|
|
/* parse packets */
|
|
|
|
e = readentitynum();
|
|
|
|
sentence = readstring();
|
|
|
|
|
|
|
|
ent = findfloat(world, entnum, e);
|
|
|
|
|
|
|
|
if (ent) {
|
|
|
|
targ = (CBaseEntity)ent;
|
|
|
|
targ.Sentence(sentence);
|
|
|
|
} else {
|
2020-03-31 07:04:05 +00:00
|
|
|
print(sprintf("^3CBaseNPC_ParseSentence^7: Entity %d not in PVS\n", e));
|
2020-03-26 11:19:27 +00:00
|
|
|
}
|
|
|
|
}
|