From 472e2c8d13e42d3b540e8d2ed8c0848169dbf4bd Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Mon, 4 Sep 2023 15:23:27 +0100 Subject: [PATCH] Fixed web hit detection Fix for issue #94. Gorge web strands now have hit detection which matches their visible component. This is for both ensnaring marines, and for cutting them with a welder. This has the following impacts: * Webs are easier for marines to avoid since they can safely jump or duck under angled strands, however... * Webs are harder for marines to cut as they can no longer clear a while corridor with a single click but have to actually aim at each strand --- main/source/mod/AvHEntities.cpp | 53 +++++++++++++++++++-------- main/source/mod/AvHEntities.h | 1 + main/source/mod/AvHWelder.cpp | 21 ++++++++++- main/source/util/MathUtil.cpp | 63 +++++++++++++++++++++++++++++++++ main/source/util/MathUtil.h | 3 ++ 5 files changed, 125 insertions(+), 16 deletions(-) diff --git a/main/source/mod/AvHEntities.cpp b/main/source/mod/AvHEntities.cpp index 5d4d27d6..ad34181d 100644 --- a/main/source/mod/AvHEntities.cpp +++ b/main/source/mod/AvHEntities.cpp @@ -1712,32 +1712,55 @@ void AvHWebStrand::Spawn(void) CBeam::Spawn(); // Spawn code - this->SetTouch(&AvHWebStrand::StrandTouch); - this->pev->solid = SOLID_TRIGGER; - //this->pev->solid = SOLID_BBOX; + this->SetTouch(NULL); + this->pev->solid = SOLID_NOT; this->pev->health = kWebHitPoints; this->pev->takedamage = DAMAGE_YES; this->mSolid=false; - this->pev->nextthink = gpGlobals->time + BALANCE_VAR(kWebWarmupTime); + this->mHardenTime = gpGlobals->time + BALANCE_VAR(kWebWarmupTime); + this->pev->nextthink = gpGlobals->time + kWebThinkInterval; SetThink(&AvHWebStrand::StrandThink); - //SetBits(this->pev->flags, FL_MONSTER); - this->RelinkBeam(); EMIT_SOUND(ENT(this->pev), CHAN_AUTO, kWebStrandFormSound, 1.0, ATTN_IDLE); - //SetThink(StrandExpire); - //this->pev->nextthink = gpGlobals->time + kWebStrandLifetime; + } void AvHWebStrand::StrandThink() { - EMIT_SOUND(ENT(this->pev), CHAN_AUTO, kWebStrandHardenSound, 1.0, ATTN_IDLE); - this->SetBrightness( 32 ); - this->SetColor( 255, 255, 255 ); - this->SetFrame(1); - this->mSolid=true; - SetThink(NULL); + TraceResult Hit; + + Vector StartTrace = this->GetStartPos(); + Vector EndTrace = this->GetEndPos(); + + UTIL_TraceLine(StartTrace, EndTrace, dont_ignore_monsters, nullptr, &Hit); + + if (!FNullEnt(Hit.pHit)) + { + edict_t* webbedEdict = Hit.pHit; + AvHPlayer* theWebbedPlayer = dynamic_cast(CBaseEntity::Instance(webbedEdict)); + + if (theWebbedPlayer) + { + StrandTouch(theWebbedPlayer); + } + } + + if (!this->mSolid) + { + if (gpGlobals->time >= this->mHardenTime) + { + EMIT_SOUND(ENT(this->pev), CHAN_AUTO, kWebStrandHardenSound, 1.0, ATTN_IDLE); + this->SetBrightness(32); + this->SetColor(255, 255, 255); + this->SetFrame(1); + this->mSolid = true; + } + } + + this->pev->nextthink = gpGlobals->time + kWebThinkInterval; + } void AvHWebStrand::StrandExpire() { @@ -1749,7 +1772,7 @@ void AvHWebStrand::StrandTouch( CBaseEntity *pOther ) { // Webs can never break on friendlies //if(GetGameRules()->CanEntityDoDamageTo(this, pOther)) - if(pOther->pev->team != this->pev->team) + if (pOther->pev->team != this->pev->team) { if ( this->mSolid ) { AvHPlayer* thePlayer = dynamic_cast(pOther); diff --git a/main/source/mod/AvHEntities.h b/main/source/mod/AvHEntities.h index efa7a3f3..60d7a441 100644 --- a/main/source/mod/AvHEntities.h +++ b/main/source/mod/AvHEntities.h @@ -526,6 +526,7 @@ public: private: bool mSolid; + float mHardenTime; }; class AvHFuncResource : public CBaseAnimating diff --git a/main/source/mod/AvHWelder.cpp b/main/source/mod/AvHWelder.cpp index 03ec331a..6ab2fd8d 100644 --- a/main/source/mod/AvHWelder.cpp +++ b/main/source/mod/AvHWelder.cpp @@ -51,6 +51,7 @@ #include "AvHMarineEquipmentConstants.h" #include "AvHWeldable.h" #include "AvHSpecials.h" +#include "MathUtil.h" #ifdef AVH_SERVER #include "AvHPlayerUpgrade.h" @@ -179,16 +180,34 @@ void AvHWelder::FireProjectiles(void) } } + + // Scan area for webs, and clear them. I can't make the webs solid, and it seems like the welder might do this, so why not? Also // adds neat element of specialization where a guy with a welder might be needed to clear an area before an attack, kinda RPS const float kWebClearingRadius = 75; + const float kWebCuttingDistance = 10.0f; CBaseEntity* thePotentialWebStrand = NULL; while((thePotentialWebStrand = UTIL_FindEntityInSphere(thePotentialWebStrand, theWelderBarrel, kWebClearingRadius)) != NULL) { AvHWebStrand* theWebStrand = dynamic_cast(thePotentialWebStrand); if(theWebStrand) { - theWebStrand->Break(); + //theWebStrand->Break(); + + Vector WelderCheckPoint; + VectorGetMidPointOnLine(theWelderBarrel, vecEnd, WelderCheckPoint); + + Vector ClosestPointOnStrand; + VectorGetClosestPointOnLine(theWebStrand->GetStartPos(), theWebStrand->GetEndPos(), WelderCheckPoint, ClosestPointOnStrand); + + float DistCuttingLineToStrand = VectorDistanceFromLine(theWelderBarrel, vecEnd, ClosestPointOnStrand); + + if (DistCuttingLineToStrand <= kWebCuttingDistance) + { + theWebStrand->Break(); + } + + } } diff --git a/main/source/util/MathUtil.cpp b/main/source/util/MathUtil.cpp index 77612b1e..b14c43e1 100644 --- a/main/source/util/MathUtil.cpp +++ b/main/source/util/MathUtil.cpp @@ -349,6 +349,69 @@ double VectorDistance2D(const float* in1, const float* in2) return sqrt(theXDiff*theXDiff + theYDiff*theYDiff); } +// Added by Neoptolemus + +void VectorGetClosestPointOnLine(const float* inLineFrom, const float* inLineTo, const float* inTestPosition, float *outClosestPoint) +{ + + float vVector1[3]; + VectorSubtract(inTestPosition, inLineFrom, vVector1); + + float vVector2[3]; + VectorSubtract(inLineTo, inLineFrom, vVector2); + + VectorNormalize(vVector2); + + float d = VectorDistance(inLineTo, inLineFrom); + float t = DotProduct(vVector2, vVector1); + + if (t <= 0) + { + outClosestPoint[0] = inLineFrom[0]; + outClosestPoint[1] = inLineFrom[1]; + outClosestPoint[2] = inLineFrom[2]; + + return; + } + + if (t >= d) + { + outClosestPoint[0] = inLineTo[0]; + outClosestPoint[1] = inLineTo[1]; + outClosestPoint[2] = inLineTo[2]; + + return; + } + + + float vVector3[3]; + + VectorScale(vVector2, t, vVector3); + + outClosestPoint[0] = inLineFrom[0] + vVector3[0]; + outClosestPoint[1] = inLineFrom[1] + vVector3[1]; + outClosestPoint[2] = inLineFrom[2] + vVector3[2]; + +} + +float VectorDistanceFromLine(const float* inLineFrom, const float* inLineTo, const float* inTestPosition) +{ + float nearestPointToLine[3]; + VectorGetClosestPointOnLine(inLineFrom, inLineTo, inTestPosition, nearestPointToLine); + + return VectorDistance(inTestPosition, nearestPointToLine); +} + +void VectorGetMidPointOnLine(const float* inLineFrom, const float* inLineTo, float* outPosition) +{ + float vVector1[3]; + VectorSubtract(inLineTo, inLineFrom, vVector1); + VectorScale(vVector1, 0.5f, vVector1); + + VectorAdd(inLineFrom, vVector1, outPosition); +} + + // Added by mmcguire. void VectorsToAngles(const float forward[3], const float right[3], const float up[3], float angles[3]) diff --git a/main/source/util/MathUtil.h b/main/source/util/MathUtil.h index c92d9b97..ca307c71 100644 --- a/main/source/util/MathUtil.h +++ b/main/source/util/MathUtil.h @@ -47,6 +47,9 @@ bool IsVectorBetweenBoundingVectors(const float* inOrigin, const float* inRay, c void VectorRotate (const float* in1, const float in2[3][4], float* out); double VectorDistance(const float* in1, const float* in2); double VectorDistance2D(const float* in1, const float* in2); +void VectorGetClosestPointOnLine(const float* inLineFrom, const float* inLineTo, const float* inTestPosition, float* outClosestPoint); +float VectorDistanceFromLine(const float* inLineFrom, const float* inLineTo, const float* inTestPosition); +void VectorGetMidPointOnLine(const float* inLineFrom, const float* inLineTo, float* outPosition); // Added by mmcguire. /**