prop_rope: Now a shared (client/server) entity instead of just client. Will

now respect parenting so you can have very dynamic rope attachments in
the world.
This commit is contained in:
Marco Cawthorne 2022-03-22 16:38:31 -07:00
parent 143a00e94e
commit 750bb413e9
Signed by: eukara
GPG key ID: C196CD8BA993248A
8 changed files with 180 additions and 54 deletions

View file

@ -124,6 +124,9 @@ Entity_EntityUpdate(float type, float new)
}
ips.ReceiveEntity(new, readfloat());
break;
case ENT_PROPROPE:
prop_rope_readentity(new);
break;
default:
//error(sprintf("Unknown entity type update received. (%d)\n", t));
}

View file

@ -391,6 +391,11 @@ CSQC_UpdateView(float w, float h, float focus)
CSQC_RenderScene();
RenderTarget_Monitor_Update();
if (g_iCubeProcess == TRUE) {
cl.PostFrame();
continue;
}
/* all 2D operations happen after this point */
for (entity b = world; (b = findfloat(b, ::isCSQC, 1));) {
NSEntity pf = (NSEntity) b;

View file

@ -22,6 +22,5 @@ client/infodecal.qc
client/sky_camera.qc
client/info_notnull.qc
client/point_message.qc
client/prop_rope.qc
client/prop_static.qc
#endlist

View file

@ -88,6 +88,10 @@ CMap_Shoot(void)
print("^3Cubemap processing...\n");
g_vecCubePos = tmp.origin;
g_dCubeSize = (float)tmp.m_iSize;
setproperty(VF_CL_VIEWANGLES, [0,0,0]);
setproperty(VF_ANGLES, [0,0,0]);
strReflectcube = sprintf(
"env/%s_%d_%d_%d",
mapname,
@ -133,8 +137,9 @@ CMap_Build
void
CMap_Build(void)
{
/* prevent command spam */
if (g_iCubeProcess == TRUE) {
return;
return;
}
localcmd("r_speeds 0\n");

View file

@ -174,7 +174,7 @@ env_sun_lensflare(vector m_vecLensPos, float m_flLensAlpha, vector vecColor)
vector player_pos = getproperty(VF_ORIGIN);
vector player_angle = getproperty(VF_CL_VIEWANGLES);
m_flLensAlpha *= 0.15f;
m_flLensAlpha *= 0.5f;
if (m_flLensAlpha <= 0.0f) {
return;
@ -201,12 +201,12 @@ env_sun_lensflare(vector m_vecLensPos, float m_flLensAlpha, vector vecColor)
player_angle[0] *= -1;
vector test1, test2;
makevectors(vectoangles(m_vecLensPos - player_pos));
test1 = v_forward;
makevectors(player_angle);
test2 = v_forward;
test1 = project(m_vecLensPos);
test2 = video_res / 2;
vector c = (test2 - test1) * 1.25f;
m_flLensAlpha = bound(0.0, 1.0 - (vlen(c) / 350), 1.0f) * m_flLensAlpha;
vector c = (test1 - test2) * 512;
drawpic(lens_1, "textures/sfx/flare1", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 - c * 0.1, "textures/sfx/flare2", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 + c * 0.2, "textures/sfx/flare3", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);

View file

@ -28,5 +28,6 @@ shared/trigger_camera.qc
shared/trigger_gravity.qc
shared/info_particle_system.qc
shared/prop_vehicle_driveable.qc
shared/prop_rope.qc
shared/worldspawn.qc
#endlist

View file

@ -32,6 +32,16 @@ ROPE_HALF : Only draw the first half of the rope, useful for vertical setups.
This entity was introduced in The Wastes (2018).
*/
typedef enumflags
{
PROPROPE_CHANGED_MAT,
PROPROPE_CHANGED_SAG,
PROPROPE_CHANGED_SWING,
PROPROPE_CHANGED_SEGMENTS,
PROPROPE_CHANGED_ORIGIN,
PROPROPE_CHANGED_TARGET
};
#define ROPE_RIBBON
void(float radius, vector texcoordbias) R_EndPolygonRibbon = #0;
@ -41,20 +51,26 @@ var int autocvar_rope_debug = FALSE;
class prop_rope:NSEntity
{
string m_strShader;
float m_flSag;
float m_flSwingFactor;
int m_iSegments;
PREDICTED_FLOAT(m_flSag);
PREDICTED_FLOAT(m_flSwingFactor);
PREDICTED_INT(m_iSegments);
PREDICTED_VECTOR(m_vecTarget);
void(void) prop_rope;
virtual float() predraw;
virtual void(string, string) SpawnKey;
virtual void(void) RendererRestarted;
#ifndef ROPE_RIBBON
virtual void(vector, vector, int) draw_segment;
#ifdef CLIENT
virtual float() predraw;
virtual void(float,float) ReadEntity;
#else
virtual void(void) Respawn;
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
virtual void(string, string) SpawnKey;
#endif
};
#ifdef CLIENT
#ifndef ROPE_RIBBON
void
prop_rope::draw_segment(vector start, vector end, int flip)
@ -118,8 +134,6 @@ prop_rope::predraw(void)
float sc;
vector vecPlayer;
entity x = find(world, ::targetname, target);
int s = (float)getproperty(VF_ACTIVESEAT);
pSeat = &g_seats[s];
vecPlayer = pSeat->m_vecPredictedOrigin;
@ -127,26 +141,17 @@ prop_rope::predraw(void)
if (checkpvs(vecPlayer, this) == FALSE)
return (PREDRAW_NEXT);
if (!x) {
#ifdef GS_DEVELOPER
print(sprintf("%s::predraw: Unknown target '%s'\n",
this.classname, target));
#endif
remove(this);
return (PREDRAW_NEXT);
}
/* draw the start/end without segments */
if (autocvar_rope_debug == TRUE) {
R_BeginPolygon("", 0, 0);
R_PolygonVertex(origin, [0,1], [0,1,0], 1.0f);
R_PolygonVertex(x.origin, [1,1], [0,1,0], 1.0f);
R_PolygonVertex(m_vecTarget, [1,1], [0,1,0], 1.0f);
R_EndPolygon();
}
segments = m_iSegments;
travel = vlen(origin - x.origin) / segments;
travel = vlen(origin - m_vecTarget) / segments;
sc = 0;
pos1 = origin;
@ -154,7 +159,7 @@ prop_rope::predraw(void)
float sag = cos(sc) * m_flSag;
/* get the direction */
makevectors(vectoangles(x.origin - origin));
makevectors(vectoangles(m_vecTarget - origin));
/* travel further and sag */
pos2 = pos1 + (v_forward * travel) + (v_up * -sag) + ((v_right * sin(time)) * m_flSwingFactor);
@ -183,12 +188,12 @@ prop_rope::predraw(void)
}
sc = 0;
pos1 = x.origin;
pos1 = m_vecTarget;
for (float i = 0; i < segments / 2; i++) {
float sag = cos(sc) * m_flSag;
/* get the direction */
makevectors(vectoangles(origin - x.origin));
makevectors(vectoangles(origin - m_vecTarget));
/* travel further and sag */
pos2 = pos1 + (v_forward * travel) + (v_up * -sag) - ((v_right * sin(time)) * m_flSwingFactor);
@ -215,42 +220,149 @@ prop_rope::predraw(void)
}
void
prop_rope::SpawnKey(string strField, string strKey)
prop_rope::ReadEntity(float flSendFlags, float new)
{
switch (strField) {
case "sag":
m_flSag = stof(strKey);
break;
case "segments":
m_iSegments = stoi(strKey);
break;
case "shader":
m_strShader = strKey;
break;
case "swingfactor":
m_flSwingFactor = stof(strKey);
break;
default:
super::SpawnKey(strField, strKey);
if (flSendFlags & PROPROPE_CHANGED_MAT)
m_strShader = readstring();
if (flSendFlags & PROPROPE_CHANGED_SAG)
m_flSag = readfloat();
if (flSendFlags & PROPROPE_CHANGED_SWING)
m_flSwingFactor = readfloat();
if (flSendFlags & PROPROPE_CHANGED_SEGMENTS)
m_iSegments = readint();
if (flSendFlags & PROPROPE_CHANGED_ORIGIN) {
origin[0] = readcoord();
origin[1] = readcoord();
origin[2] = readcoord();
setsize(this, [0,0,0], [0,0,0]);
setorigin(this, origin);
}
if (flSendFlags & PROPROPE_CHANGED_TARGET) {
m_vecTarget[0] = readcoord();
m_vecTarget[1] = readcoord();
m_vecTarget[2] = readcoord();
}
}
#else
void
prop_rope::Respawn(void)
{
SetOrigin(GetSpawnOrigin());
SetSize([0,0,0], [0,0,0]);
}
void
prop_rope::EvaluateEntity(void)
{
entity eFind = find(world, ::targetname, target);
if (!eFind) {
print(sprintf("prop_rope: Unable to find target %S\n", target));
return;
}
m_vecTarget = eFind.origin;
if (ATTR_CHANGED(m_flSag)) {
SetSendFlags(PROPROPE_CHANGED_SAG);
}
if (ATTR_CHANGED(m_flSwingFactor)) {
SetSendFlags(PROPROPE_CHANGED_SWING);
}
if (ATTR_CHANGED(m_iSegments)) {
SetSendFlags(PROPROPE_CHANGED_SEGMENTS);
}
if (ATTR_CHANGED(origin)) {
SetSendFlags(PROPROPE_CHANGED_ORIGIN);
}
if (ATTR_CHANGED(m_vecTarget)) {
SetSendFlags(PROPROPE_CHANGED_TARGET);
}
SAVE_STATE(m_flSag);
SAVE_STATE(m_flSwingFactor);
SAVE_STATE(m_iSegments);
SAVE_STATE(origin);
SAVE_STATE(m_vecTarget);
}
float
prop_rope::SendEntity(entity ePVEnt, float flSendFlags)
{
WriteByte(MSG_ENTITY, ENT_PROPROPE);
WriteFloat(MSG_ENTITY, flSendFlags);
if (flSendFlags & PROPROPE_CHANGED_MAT)
WriteString(MSG_ENTITY, m_strShader);
if (flSendFlags & PROPROPE_CHANGED_SAG)
WriteFloat(MSG_ENTITY, m_flSag);
if (flSendFlags & PROPROPE_CHANGED_SWING)
WriteFloat(MSG_ENTITY, m_flSwingFactor);
if (flSendFlags & PROPROPE_CHANGED_SEGMENTS)
WriteInt(MSG_ENTITY, m_iSegments);
if (flSendFlags & PROPROPE_CHANGED_ORIGIN) {
WriteCoord(MSG_ENTITY, origin[0]);
WriteCoord(MSG_ENTITY, origin[1]);
WriteCoord(MSG_ENTITY, origin[2]);
}
if (flSendFlags & PROPROPE_CHANGED_TARGET) {
WriteCoord(MSG_ENTITY, m_vecTarget[0]);
WriteCoord(MSG_ENTITY, m_vecTarget[1]);
WriteCoord(MSG_ENTITY, m_vecTarget[2]);
}
return 1;
}
void
prop_rope::RendererRestarted(void)
prop_rope::SpawnKey(string strKey, string strValue)
{
precache_pic(m_strShader);
switch (strKey) {
case "sag":
m_flSag = stof(strValue);
break;
case "segments":
m_iSegments = stoi(strValue);
break;
case "shader":
m_strShader = strValue;
break;
case "swingfactor":
m_flSwingFactor = stof(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
#endif
void
prop_rope::prop_rope(void)
{
#ifdef SERVER
m_flSwingFactor = random();
m_flSag = 15.0f;
m_iSegments = 16;
m_strShader = "textures/props/wire_default";
super::NSEntity();
#else
/* this is empty for a good reason */
drawmask = MASK_ENGINE;
Init();
RendererRestarted();
setsize(this, [0,0,0], [0,0,0]);
setorigin(this, origin);
#endif
}
#ifdef CLIENT
void
prop_rope_readentity(float isnew)
{
prop_rope rope = (prop_rope)self;
float flags = readfloat();
if (isnew)
spawnfunc_prop_rope();
rope.ReadEntity(flags, isnew);
}
#endif

View file

@ -37,5 +37,6 @@ enum
ENT_VEHICLE,
ENT_VEH_TANKMORTAR,
ENT_VEH_4WHEEL,
ENT_PROPROPE,
ENT_SEPARATOR,
};