From f37df7102959859a553b120fcf29b47032368c57 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 7 Apr 2016 18:13:03 +0200 Subject: [PATCH 01/10] Float fest\! --- Sources/Engine/Base/ProgressHook.cpp | 2 +- Sources/Engine/Math/Functions.h | 4 ++ Sources/Engine/Math/Quaternion.h | 24 +++---- Sources/Engine/Math/Vector.h | 2 +- Sources/Engine/Sound/SoundObject.h | 4 +- Sources/EntitiesMP/AirElemental.es | 2 +- Sources/EntitiesMP/AmmoItem.es | 22 +++---- Sources/EntitiesMP/AmmoPack.es | 2 +- Sources/EntitiesMP/ArmorItem.es | 20 +++--- Sources/EntitiesMP/Beast.es | 2 +- Sources/EntitiesMP/CannonBall.es | 2 +- Sources/EntitiesMP/Common/Common.cpp | 8 +-- Sources/EntitiesMP/Common/Particles.cpp | 66 +++++++++---------- Sources/EntitiesMP/EnemyBase.es | 6 +- .../EntitiesMP/EnvironmentParticlesHolder.es | 8 +-- Sources/EntitiesMP/ExotechLarva.es | 12 ++-- Sources/EntitiesMP/ExotechLarvaBattery.es | 2 +- Sources/EntitiesMP/Fish.es | 2 +- Sources/EntitiesMP/Flame.es | 2 +- Sources/EntitiesMP/Player.es | 8 +-- Sources/EntitiesMP/PlayerView.es | 2 +- Sources/EntitiesMP/PlayerWeapons.es | 4 +- Sources/EntitiesMP/PowerUpItem.es | 10 +-- Sources/EntitiesMP/Projectile.es | 10 +-- Sources/EntitiesMP/Shooter.es | 2 +- Sources/EntitiesMP/Summoner.es | 4 +- Sources/EntitiesMP/WorldSettingsController.es | 24 +++---- Sources/GameMP/CompModels.cpp | 2 +- 28 files changed, 131 insertions(+), 127 deletions(-) mode change 100644 => 100755 Sources/Engine/Base/ProgressHook.cpp mode change 100644 => 100755 Sources/Engine/Math/Functions.h mode change 100644 => 100755 Sources/Engine/Math/Quaternion.h mode change 100644 => 100755 Sources/Engine/Math/Vector.h mode change 100644 => 100755 Sources/Engine/Sound/SoundObject.h mode change 100644 => 100755 Sources/EntitiesMP/AirElemental.es mode change 100644 => 100755 Sources/EntitiesMP/AmmoItem.es mode change 100644 => 100755 Sources/EntitiesMP/AmmoPack.es mode change 100644 => 100755 Sources/EntitiesMP/ArmorItem.es mode change 100644 => 100755 Sources/EntitiesMP/Beast.es mode change 100644 => 100755 Sources/EntitiesMP/CannonBall.es mode change 100644 => 100755 Sources/EntitiesMP/Common/Common.cpp mode change 100644 => 100755 Sources/EntitiesMP/EnemyBase.es mode change 100644 => 100755 Sources/EntitiesMP/EnvironmentParticlesHolder.es mode change 100644 => 100755 Sources/EntitiesMP/ExotechLarva.es mode change 100644 => 100755 Sources/EntitiesMP/ExotechLarvaBattery.es mode change 100644 => 100755 Sources/EntitiesMP/Fish.es mode change 100644 => 100755 Sources/EntitiesMP/Flame.es mode change 100644 => 100755 Sources/EntitiesMP/Player.es mode change 100644 => 100755 Sources/EntitiesMP/PlayerView.es mode change 100644 => 100755 Sources/EntitiesMP/PlayerWeapons.es mode change 100644 => 100755 Sources/EntitiesMP/PowerUpItem.es mode change 100644 => 100755 Sources/EntitiesMP/Projectile.es mode change 100644 => 100755 Sources/EntitiesMP/Shooter.es mode change 100644 => 100755 Sources/EntitiesMP/Summoner.es mode change 100644 => 100755 Sources/EntitiesMP/WorldSettingsController.es mode change 100644 => 100755 Sources/GameMP/CompModels.cpp diff --git a/Sources/Engine/Base/ProgressHook.cpp b/Sources/Engine/Base/ProgressHook.cpp old mode 100644 new mode 100755 index 2514d60..b9b1bc8 --- a/Sources/Engine/Base/ProgressHook.cpp +++ b/Sources/Engine/Base/ProgressHook.cpp @@ -49,7 +49,7 @@ void CallProgressHook_t(FLOAT fCompleted) bTimeInitialized = TRUE; } CTimerValue tvNow = _pTimer->GetHighPrecisionTimer(); - if ((tvNow-tvLastUpdate) > CTimerValue(net_fSendRetryWait*1.1)) { + if ((tvNow-tvLastUpdate) > CTimerValue(net_fSendRetryWait*1.1f)) { if (_pNetwork->ga_IsServer) { // handle server messages _cmiComm.Server_Update(); diff --git a/Sources/Engine/Math/Functions.h b/Sources/Engine/Math/Functions.h old mode 100644 new mode 100755 index 3b388d0..259156a --- a/Sources/Engine/Math/Functions.h +++ b/Sources/Engine/Math/Functions.h @@ -447,7 +447,11 @@ printf("CHECK THIS: %s:%d\n", __FILE__, __LINE__); // square root (works with negative numbers) +#ifdef __arm__ +inline FLOAT Sqrt( FLOAT x) { return sqrtf( ClampDn( x, 0.0f)); } +#else inline FLOAT Sqrt( FLOAT x) { return (FLOAT)sqrt( ClampDn( x, 0.0f)); } +#endif diff --git a/Sources/Engine/Math/Quaternion.h b/Sources/Engine/Math/Quaternion.h old mode 100644 new mode 100755 index 077ff4d..b46c078 --- a/Sources/Engine/Math/Quaternion.h +++ b/Sources/Engine/Math/Quaternion.h @@ -370,8 +370,8 @@ void Quaternion::FromEuler(const Vector &a) template Type Quaternion::EPS(Type orig) const { - if ((orig <= 10e-6) && (orig >= -10e-6)) - return(0.0); + if ((orig <= 10e-6f) && (orig >= -10e-6f)) + return(0.0f); return(orig); } @@ -384,9 +384,9 @@ void Quaternion::ToMatrix(Matrix &m) const Type yy = 2*q_y*q_y; Type yz = 2*q_y*q_z; Type zz = 2*q_z*q_z; Type wx = 2*q_w*q_x; Type wy = 2*q_w*q_y; Type wz = 2*q_w*q_z; - m(1,1) = EPS(1.0-(yy+zz)); m(1,2) = EPS(xy-wz); m(1,3) = EPS(xz+wy); - m(2,1) = EPS(xy+wz); m(2,2) = EPS(1.0-(xx+zz)); m(2,3) = EPS(yz-wx); - m(3,1) = EPS(xz-wy); m(3,2) = EPS(yz+wx); m(3,3) = EPS(1.0-(xx+yy)); + m(1,1) = EPS(1.0f-(yy+zz));m(1,2) = EPS(xy-wz); m(1,3) = EPS(xz+wy); + m(2,1) = EPS(xy+wz); m(2,2) = EPS(1.0f-(xx+zz));m(2,3) = EPS(yz-wx); + m(3,1) = EPS(xz-wy); m(3,2) = EPS(yz+wx); m(3,3) = EPS(1.0f-(xx+yy)); } // conversion from matrix @@ -396,12 +396,12 @@ void Quaternion::FromMatrix(Matrix &m) Type trace = m(1,1)+m(2,2)+m(3,3); Type root; - if ( trace > 0.0 ) + if ( trace > 0.0f ) { // |w| > 1/2, may as well choose w > 1/2 - root = sqrt(trace+1.0); // 2w - q_w = 0.5*root; - root = 0.5/root; // 1/(4w) + root = sqrt(trace+1.0f); // 2w + q_w = 0.5f*root; + root = 0.5f/root; // 1/(4w) q_x = (m(3,2)-m(2,3))*root; q_y = (m(1,3)-m(3,1))*root; q_z = (m(2,1)-m(1,2))*root; @@ -418,10 +418,10 @@ void Quaternion::FromMatrix(Matrix &m) int j = next[i]; int k = next[j]; - root = sqrt(m(i+1,i+1)-m(j+1,j+1)-m(k+1,k+1)+1.0); + root = sqrt(m(i+1,i+1)-m(j+1,j+1)-m(k+1,k+1)+1.0f); Type* quat[3] = { &q_x, &q_y, &q_z }; - *quat[i] = 0.5*root; - root = 0.5/root; + *quat[i] = 0.5f*root; + root = 0.5f/root; q_w = (m(k+1,j+1)-m(j+1,k+1))*root; *quat[j] = (m(j+1,i+1)+m(i+1,j+1))*root; *quat[k] = (m(k+1,i+1)+m(i+1,k+1))*root; diff --git a/Sources/Engine/Math/Vector.h b/Sources/Engine/Math/Vector.h old mode 100644 new mode 100755 index 5aa4a5a..2fda989 --- a/Sources/Engine/Math/Vector.h +++ b/Sources/Engine/Math/Vector.h @@ -234,7 +234,7 @@ template __forceinline Vector &Vector::SafeNormalize(void) { Type tLen = Length(); - if (tLen<1E-6) { + if (tLen<1E-6f) { if (iDimensions==2) { *this = Vector(1,0); } else { diff --git a/Sources/Engine/Sound/SoundObject.h b/Sources/Engine/Sound/SoundObject.h old mode 100644 new mode 100755 index 6fcf60d..a379f99 --- a/Sources/Engine/Sound/SoundObject.h +++ b/Sources/Engine/Sound/SoundObject.h @@ -142,8 +142,8 @@ public: // Set filter inline void SetFilter( FLOAT fLeftFilter, FLOAT fRightFilter) { // 1=no filter (>1=more bass) ASSERT( (fLeftFilter >= 1) && (fRightFilter >= 1)); - so_spNew.sp_slLeftFilter = FloatToInt(32767.0/fLeftFilter); - so_spNew.sp_slRightFilter = FloatToInt(32767.0/fRightFilter); + so_spNew.sp_slLeftFilter = FloatToInt(32767.0f/fLeftFilter); + so_spNew.sp_slRightFilter = FloatToInt(32767.0f/fRightFilter); }; // Set pitch shifting inline void SetPitch( FLOAT fPitch) { // 1.0 for normal (<1 = slower, >1 = faster playing) diff --git a/Sources/EntitiesMP/AirElemental.es b/Sources/EntitiesMP/AirElemental.es old mode 100644 new mode 100755 index b75d15a..d3c66e2 --- a/Sources/EntitiesMP/AirElemental.es +++ b/Sources/EntitiesMP/AirElemental.es @@ -528,7 +528,7 @@ procedures: m_fWindBlastFirePosEnd*m_fAttSizeCurrent, (FLOAT)m_iWind*0.25f); ShootProjectile(PRT_AIRELEMENTAL_WIND, vFirePos, - ANGLE3D(30.0f-m_iWind*10.0, 0.0f, 0.0f)); + ANGLE3D(30.0f-m_iWind*10.0f, 0.0f, 0.0f)); m_iWind++; autowait(0.1f); } diff --git a/Sources/EntitiesMP/AmmoItem.es b/Sources/EntitiesMP/AmmoItem.es old mode 100644 new mode 100755 index 04fcaa6..b91b99c --- a/Sources/EntitiesMP/AmmoItem.es +++ b/Sources/EntitiesMP/AmmoItem.es @@ -146,37 +146,37 @@ functions: } switch (m_EaitType) { case AIT_SHELLS: - Particles_Spiral(this, 1.0f*0.75, 1.0f*0.75, PT_STAR04, 4); + Particles_Spiral(this, 1.0f*0.75f, 1.0f*0.75f, PT_STAR04, 4); break; case AIT_BULLETS: - Particles_Spiral(this, 1.5f*0.75, 1.0f*0.75, PT_STAR04, 6); + Particles_Spiral(this, 1.5f*0.75f, 1.0f*0.75f, PT_STAR04, 6); break; case AIT_ROCKETS: - Particles_Spiral(this, 1.5f*0.75, 1.25f*0.75, PT_STAR04, 6); + Particles_Spiral(this, 1.5f*0.75f, 1.25f*0.75f, PT_STAR04, 6); break; case AIT_GRENADES: - Particles_Spiral(this, 2.0f*0.75, 1.25f*0.75, PT_STAR04, 6); + Particles_Spiral(this, 2.0f*0.75f, 1.25f*0.75f, PT_STAR04, 6); break; case AIT_ELECTRICITY: - Particles_Spiral(this, 1.5f*0.75, 1.125f*0.75, PT_STAR04, 6); + Particles_Spiral(this, 1.5f*0.75f, 1.125f*0.75f, PT_STAR04, 6); break; case AIT_NUKEBALL: - Particles_Spiral(this, 1.25f*0.75, 1.0f*0.75, PT_STAR04, 4); + Particles_Spiral(this, 1.25f*0.75f, 1.0f*0.75f, PT_STAR04, 4); break; case AIT_IRONBALLS: - Particles_Spiral(this, 2.0f*0.75, 1.25f*0.75, PT_STAR04, 8); + Particles_Spiral(this, 2.0f*0.75f, 1.25f*0.75f, PT_STAR04, 8); break; case AIT_BACKPACK: - Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + Particles_Spiral(this, 3.0f*0.5f, 2.5f*0.5f, PT_STAR04, 10); break; case AIT_SERIOUSPACK: - Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + Particles_Spiral(this, 3.0f*0.5f, 2.5f*0.5f, PT_STAR04, 10); break; case AIT_NAPALM: - Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + Particles_Spiral(this, 3.0f*0.5f, 2.5f*0.5f, PT_STAR04, 10); break; case AIT_SNIPERBULLETS: - Particles_Spiral(this, 1.5f*0.75, 1.25f*0.75, PT_STAR04, 6); + Particles_Spiral(this, 1.5f*0.75f, 1.25f*0.75f, PT_STAR04, 6); break; } } diff --git a/Sources/EntitiesMP/AmmoPack.es b/Sources/EntitiesMP/AmmoPack.es old mode 100644 new mode 100755 index 9f28c38..a934c88 --- a/Sources/EntitiesMP/AmmoPack.es +++ b/Sources/EntitiesMP/AmmoPack.es @@ -90,7 +90,7 @@ functions: return; } - Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + Particles_Spiral(this, 3.0f*0.5f, 2.5f*0.5f, PT_STAR04, 10); } /* Fill in entity statistics - for AI purposes only */ diff --git a/Sources/EntitiesMP/ArmorItem.es b/Sources/EntitiesMP/ArmorItem.es old mode 100644 new mode 100755 index 3c9a412..f683c5c --- a/Sources/EntitiesMP/ArmorItem.es +++ b/Sources/EntitiesMP/ArmorItem.es @@ -131,22 +131,22 @@ functions: } switch (m_EaitType) { case ARIT_SHARD: - Particles_Emanate(this, 0.75f*0.75, 0.75f*0.75, PT_STAR04, 8, 7.0f); + Particles_Emanate(this, 0.75f*0.75f, 0.75f*0.75f, PT_STAR04, 8, 7.0f); break; case ARIT_SMALL: - Particles_Emanate(this, 1.0f*0.75, 1.0f*0.75, PT_STAR04, 32, 7.0f); + Particles_Emanate(this, 1.0f*0.75f, 1.0f*0.75f, PT_STAR04, 32, 7.0f); break; case ARIT_MEDIUM: - Particles_Emanate(this, 1.5f*0.75, 1.5f*0.75, PT_STAR04, 64, 7.0f); + Particles_Emanate(this, 1.5f*0.75f, 1.5f*0.75f, PT_STAR04, 64, 7.0f); break; case ARIT_STRONG: - Particles_Emanate(this, 2.0f*0.75, 1.25f*0.75, PT_STAR04, 96, 7.0f); + Particles_Emanate(this, 2.0f*0.75f, 1.25f*0.75f, PT_STAR04, 96, 7.0f); break; case ARIT_SUPER: - Particles_Emanate(this, 2.5f*0.75, 1.5f*0.75, PT_STAR04, 128, 7.0f); + Particles_Emanate(this, 2.5f*0.75f, 1.5f*0.75f, PT_STAR04, 128, 7.0f); break; case ARIT_HELM: - Particles_Emanate(this, 0.875f*0.75, 0.875f*0.75, PT_STAR04, 16, 7.0f); + Particles_Emanate(this, 0.875f*0.75f, 0.875f*0.75f, PT_STAR04, 16, 7.0f); break; } } @@ -162,8 +162,8 @@ functions: m_strDescription.PrintF("Shard - H:%g T:%g", m_fValue, m_fRespawnTime); // set appearance AddItem(MODEL_1, TEXTURE_1, 0, TEX_SPEC_MEDIUM, 0); - AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.4f,0), FLOAT3D(1.0,1.0,0.3f) ); - StretchItem(FLOAT3D(0.75f*0.75, 0.75f*0.75, 0.75f*0.75)); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.4f,0), FLOAT3D(1.0f,1.0f,0.3f) ); + StretchItem(FLOAT3D(0.75f*0.75f, 0.75f*0.75f, 0.75f*0.75f)); m_iSoundComponent = SOUND_SHARD; break; case ARIT_SMALL: @@ -223,8 +223,8 @@ functions: m_strDescription.PrintF("Helm - H:%g T:%g", m_fValue, m_fRespawnTime); // set appearance AddItem(MODEL_5, TEXTURE_5, 0, TEX_SPEC_MEDIUM, 0); - AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.5f,0), FLOAT3D(1.5,1.5,0.4f) ); - StretchItem(FLOAT3D(0.875f*0.75, 0.875f*0.75, 0.875f*0.75)); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.5f,0), FLOAT3D(1.5f,1.5f,0.4f) ); + StretchItem(FLOAT3D(0.875f*0.75f, 0.875f*0.75f, 0.875f*0.75f)); m_iSoundComponent = SOUND_HELM; break; } diff --git a/Sources/EntitiesMP/Beast.es b/Sources/EntitiesMP/Beast.es old mode 100644 new mode 100755 index 660189a..312e8cd --- a/Sources/EntitiesMP/Beast.es +++ b/Sources/EntitiesMP/Beast.es @@ -357,7 +357,7 @@ procedures: autowait(0.51f); ShootProjectile(PRT_BEAST_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BEAST_STRETCH, 0.0f), - ANGLE3D(AngleDeg((FRnd()-0.5)*30.0f), AngleDeg(FRnd()*10.0f), 0)); + ANGLE3D(AngleDeg((FRnd()-0.5f)*30.0f), AngleDeg(FRnd()*10.0f), 0)); autowait(0.3f); } diff --git a/Sources/EntitiesMP/CannonBall.es b/Sources/EntitiesMP/CannonBall.es old mode 100644 new mode 100755 index 0166e7d..adae29c --- a/Sources/EntitiesMP/CannonBall.es +++ b/Sources/EntitiesMP/CannonBall.es @@ -225,7 +225,7 @@ functions: FLOAT fSpeedRatio = Min( en_vCurrentTranslationAbsolute.Length()/140.0f, 1.0f); INDEX ctFireParticles = INDEX( (Max( fSpeedRatio-0.5f, 0.0f)*2.0f)*128); //CPrintF("fSpeedRatio=%g, ctFireParticles=%d\n", fSpeedRatio, ctFireParticles); - if( _pTimer->GetLerpedCurrentTick()-m_fStartTime>0.075) + if( _pTimer->GetLerpedCurrentTick()-m_fStartTime>0.075f) { Particles_BeastBigProjectileTrail( this, 2.0f, 1.0f, 0.75f, ctFireParticles); } diff --git a/Sources/EntitiesMP/Common/Common.cpp b/Sources/EntitiesMP/Common/Common.cpp old mode 100644 new mode 100755 index 1645857..af04321 --- a/Sources/EntitiesMP/Common/Common.cpp +++ b/Sources/EntitiesMP/Common/Common.cpp @@ -1405,13 +1405,13 @@ FLOAT GetGameDamageMultiplier(void) { FLOAT fGameDamageMultiplier = 1.0f; FLOAT fExtraStrength = GetSP()->sp_fExtraEnemyStrength; - if (fExtraStrength>0) { - fGameDamageMultiplier*=1.0f/(1+fExtraStrength); + if (fExtraStrength>0.0f) { + fGameDamageMultiplier*=1.0f/(1.0f+fExtraStrength); } FLOAT fExtraStrengthPerPlayer = GetSP()->sp_fExtraEnemyStrengthPerPlayer; - if (fExtraStrengthPerPlayer>0) { + if (fExtraStrengthPerPlayer>0.0f) { INDEX ctPlayers = _pNetwork->ga_sesSessionState.GetPlayersCount(); - fGameDamageMultiplier*=1.0f/(1+fExtraStrengthPerPlayer*ClampDn(((FLOAT) ctPlayers)-1.0f, 0.0f)); + fGameDamageMultiplier*=1.0f/(1.0f+fExtraStrengthPerPlayer*ClampDn(((FLOAT) ctPlayers)-1.0f, 0.0f)); } if (GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_TOURIST) { fGameDamageMultiplier *= 2.0f; diff --git a/Sources/EntitiesMP/Common/Particles.cpp b/Sources/EntitiesMP/Common/Particles.cpp index 1510fd7..d488fb2 100755 --- a/Sources/EntitiesMP/Common/Particles.cpp +++ b/Sources/EntitiesMP/Common/Particles.cpp @@ -824,14 +824,14 @@ void Particles_GrenadeTrail(CEntity *pen) pvPos2 = &plp->GetPosition(iPos); for (INDEX iInter=0; iInterGetPosition(iPos); for (INDEX iInter=0; iInterGetTexel(PIX(FLOAT(iParticle)/iParticlesLiving*8*1024), 0); Particle_RenderSquare( vPos, fSize, fAngle, col); iParticle++; @@ -939,15 +939,15 @@ void Particles_LavaBombTrail(CEntity *pen, FLOAT fSizeMultiplier) if( *pvPos1 == *pvPos2) continue; for (INDEX iInter=0; iInterGetTexel(PIX(FLOAT(iParticle)/iParticlesLiving*8*1024), 0); Particle_RenderSquare( vPos, fSize, fAngle, col); iParticle++; @@ -983,14 +983,14 @@ void Particles_BeastProjectileDebrisTrail(CEntity *pen, FLOAT fSizeMultiplier) pvPos2 = &plp->GetPosition(iPos); for (INDEX iInter=0; iInterGetTexel(PIX(FLOAT(iParticle)/iParticlesLiving*8*1024), 0); Particle_RenderSquare( vPos, fSize, fAngle, col); iParticle++; @@ -1645,15 +1645,15 @@ void Particles_FlameThrower(const CPlacement3D &plLeader, const CPlacement3D &pl // calculate parameters of hermit spline FLOAT ft3x=dx1+dx2+2.0f*x1-2.0f*x2; - FLOAT ft2x=-2.0f*dx1-dx2-3.0*(x1-x2); + FLOAT ft2x=-2.0f*dx1-dx2-3.0f*(x1-x2); FLOAT ft1x=dx1; FLOAT ft0x=x1; FLOAT ft3y=dy1+dy2+2.0f*y1-2.0f*y2; - FLOAT ft2y=-2.0f*dy1-dy2-3.0*(y1-y2); + FLOAT ft2y=-2.0f*dy1-dy2-3.0f*(y1-y2); FLOAT ft1y=dy1; FLOAT ft0y=y1; FLOAT ft3z=dz1+dz2+2.0f*z1-2.0f*z2; - FLOAT ft2z=-2.0f*dz1-dz2-3.0*(z1-z2); + FLOAT ft2z=-2.0f*dz1-dz2-3.0f*(z1-z2); FLOAT ft1z=dz1; FLOAT ft0z=z1; @@ -1799,20 +1799,20 @@ void Particles_ShooterFlame(const CPlacement3D &plEnd, const CPlacement3D &plSta INDEX iRndFact = 2*i*FloatToInt(fTime*8.0f)+2; // size - FLOAT fSize = 0.05 + 1.0*fTime; + FLOAT fSize = 0.05f + 1.0f*fTime; // angle FLOAT fAngle = fTime*180.0f*afStarsPositions[iRndFact][0]; // transparency UBYTE ub = 255; if (fTime>1.0f) ub = 0; - else if(fTime>0.6f) ub = (UBYTE) ((1.0-fTime)*(1.0/0.4)*255); + else if(fTime>0.6f) ub = (UBYTE) ((1.0-fTime)*(1.0f/0.4f)*255); // color with a bit of red tint before the burnout COLOR col = RGBToColor(192, 192, 192); if (fTime>0.95f) col = RGBToColor(192, 0, 0); - else if (fTime>0.4) col = RGBToColor(192, (UBYTE) ((1.0-fTime)*(1.0/0.6)*100+92), (UBYTE) ((1.0-fTime)*(1.0/0.6)*112+80)); + else if (fTime>0.4f) col = RGBToColor(192, (UBYTE) ((1.0-fTime)*(1.0f/0.6f)*100+92), (UBYTE) ((1.0f-fTime)*(1.0f/0.6f)*112+80)); vPos(1) += afStarsPositions[iRndFact][0]*fTime; - vPos(2) += afStarsPositions[iRndFact][1]*fTime + 0.25*fTime*fTime; + vPos(2) += afStarsPositions[iRndFact][1]*fTime + 0.25f*fTime*fTime; vPos(3) += afStarsPositions[iRndFact][2]*fTime; Particle_RenderSquare( vPos, fSize, fAngle, col|ub); @@ -2147,10 +2147,10 @@ void Particles_DamageSmoke( CEntity *pen, FLOAT tmStarted, FLOATaabbox3D boxOwne vPos(2) += ((afStarsPositions[iRnd2+4][1]+0.5f)*2.0f+1.5f)*fT+boxOwner.Size()(2)*0.0025f; COLOR col = C_dGRAY|UBYTE(64.0f*fRatio); - FLOAT fRotation = afStarsPositions[iRnd2+5][0]*360+fT*200.0f*afStarsPositions[iRnd2+3][0]; + FLOAT fRotation = afStarsPositions[iRnd2+5][0]*360.0f+fT*200.0f*afStarsPositions[iRnd2+3][0]; FLOAT fSize = 0.025f*fDamage+ - (afStarsPositions[iRnd2+6][2]+0.5f)*0.075 + + (afStarsPositions[iRnd2+6][2]+0.5f)*0.075f + (0.15f+(afStarsPositions[iRnd2+2][1]+0.5f)*0.075f*fBoxSize)*fT; Particle_RenderSquare( vPos, fSize, fRotation, col); } @@ -2253,7 +2253,7 @@ void Particles_DustFall(CEntity *pen, FLOAT tmStarted, FLOAT3D vStretch) COLOR col = HSVToColor(ubRndH,ubRndS,ubRndV)|UBYTE(fRndBlend*fPower); FLOAT fRotation = afStarsPositions[iRnd][0]*360+fT*360.0f*afStarsPositions[iRnd][0]*fSpeed; FLOAT fSize = - 0.75f+(afStarsPositions[iRnd][2]+0.5f)*0.25 + // static size + 0.75f+(afStarsPositions[iRnd][2]+0.5f)*0.25f + // static size (0.4f+(afStarsPositions[iRnd][1]+0.5f)*0.4f)*fT; // dinamic size fSize*=fSizeRatio; Particle_RenderSquare( vPos, fSize*fStretch*0.2f, fRotation, col); @@ -3380,13 +3380,13 @@ void Particles_SandFlow( CEntity *pen, FLOAT fStretchAll, FLOAT fSize, FLOAT fHe FLOAT fBirthTime = fNow-(fT*SANDFLOW_TOTAL_TIME); if( (fBirthTimefStopTime+2.0f) ) continue; FLOAT fFade; - if (fT>(1.0f-SANDFLOW_FADE_OUT)) fFade=(1-fT)*(1/SANDFLOW_FADE_OUT); + if (fT>(1.0f-SANDFLOW_FADE_OUT)) fFade=(1.0f-fT)*(1.0f/SANDFLOW_FADE_OUT); else fFade=1.0f; fFade *= (CT_SANDFLOW_TRAIL-iTrail)*(1.0f/CT_SANDFLOW_TRAIL); FLOAT3D vPos = vCenter + vX*(afStarsPositions[iStar][0]*fStretchAll*fPowerFactor+fHeight*fT) + - vY*(fT*fT*-5.0f+(afStarsPositions[iStar][1]*fPowerFactor*0.1)) + + vY*(fT*fT*-5.0f+(afStarsPositions[iStar][1]*fPowerFactor*0.1f)) + vZ*(afStarsPositions[iStar][2]*fPowerFactor*fT*fStretchAll); COLOR colSand = pTD->GetTexel( FloatToInt(fT*2048), 0); @@ -3684,7 +3684,7 @@ void Particles_BulletSpray(INDEX iRndBase, FLOAT3D vSource, FLOAT3D vGDir, enum void MakeBaseFromVector(const FLOAT3D &vY, FLOAT3D &vX, FLOAT3D &vZ) { // if the plane is mostly horizontal - if (Abs(vY(2))>0.5) { + if (Abs(vY(2))>0.5f) { // use cross product of +x axis and plane normal as +s axis vX = FLOAT3D(1.0f, 0.0f, 0.0f)*vY; // if the plane is mostly vertical @@ -5653,10 +5653,10 @@ void Particles_Leaves(CEntity *penTree, FLOATaabbox3D boxSize, FLOAT3D vSource, Particle_SetTexturePart( 256, 256, iFrame, 0); FLOAT fFade=CalculateRatio( fRatio, 0, 1, 0, 0.2f); - INDEX iRnd1=(INDEX(iSpray+tmStarted*12356.789))%CT_MAX_PARTICLES_TABLE; - INDEX iRnd2=(INDEX(iSpray+tmStarted*21341.789))%CT_MAX_PARTICLES_TABLE; - INDEX iRnd3=(INDEX(iSpray+tmStarted*52672.789))%CT_MAX_PARTICLES_TABLE; - INDEX iRnd4=(INDEX(iSpray+tmStarted*83652.458))%CT_MAX_PARTICLES_TABLE; + INDEX iRnd1=(INDEX(iSpray+tmStarted*12356.789f))%CT_MAX_PARTICLES_TABLE; + INDEX iRnd2=(INDEX(iSpray+tmStarted*21341.789f))%CT_MAX_PARTICLES_TABLE; + INDEX iRnd3=(INDEX(iSpray+tmStarted*52672.789f))%CT_MAX_PARTICLES_TABLE; + INDEX iRnd4=(INDEX(iSpray+tmStarted*83652.458f))%CT_MAX_PARTICLES_TABLE; FLOAT3D vLaunchSpeed= FLOAT3D( afStarsPositions[iRnd1][0]*2.0f, (afStarsPositions[iRnd1][1]+1.0f)*3.0f, diff --git a/Sources/EntitiesMP/EnemyBase.es b/Sources/EntitiesMP/EnemyBase.es old mode 100644 new mode 100755 index 2a1ca6d..bef2bba --- a/Sources/EntitiesMP/EnemyBase.es +++ b/Sources/EntitiesMP/EnemyBase.es @@ -650,14 +650,14 @@ functions: FLOAT fKickDamage = fNewDamage; if( (dmtType == DMT_EXPLOSION) || (dmtType == DMT_IMPACT) || (dmtType == DMT_CANNONBALL_EXPLOSION) ) { - fKickDamage*=1.5; + fKickDamage*=1.5f; } if (dmtType==DMT_DROWNING || dmtType==DMT_CLOSERANGE || dmtType==DMT_CHAINSAW) { - fKickDamage /= 10; + fKickDamage /= 10.0f; } if (dmtType==DMT_BURNING) { - fKickDamage /= 100000; + fKickDamage /= 100000.0f; UBYTE ubR, ubG, ubB, ubA; FLOAT fColorFactor=fNewDamage/m_fMaxHealth*255.0f; ColorToRGBA(m_colBurning, ubR, ubG, ubB, ubA); diff --git a/Sources/EntitiesMP/EnvironmentParticlesHolder.es b/Sources/EntitiesMP/EnvironmentParticlesHolder.es old mode 100644 new mode 100755 index 39ba9ee..398ccad --- a/Sources/EntitiesMP/EnvironmentParticlesHolder.es +++ b/Sources/EntitiesMP/EnvironmentParticlesHolder.es @@ -209,10 +209,10 @@ procedures: SetModel(MODEL_ENVIRONMENT_PARTICLES_HOLDER); SetModelMainTexture(TEXTURE_ENVIRONMENT_PARTICLES_HOLDER); - m_tmRainStart = 1e5-1.0f; - m_tmRainEnd = 1e5; - m_tmSnowStart = 1e5-1.0f; - m_tmSnowEnd = 1e5; + m_tmRainStart = 1e5f-1.0f; + m_tmRainEnd = 1e5f; + m_tmSnowStart = 1e5f-1.0f; + m_tmSnowEnd = 1e5f; switch(m_eptType) { case EPTH_GROWTH: diff --git a/Sources/EntitiesMP/ExotechLarva.es b/Sources/EntitiesMP/ExotechLarva.es old mode 100644 new mode 100755 index 8fa5117..9f1f455 --- a/Sources/EntitiesMP/ExotechLarva.es +++ b/Sources/EntitiesMP/ExotechLarva.es @@ -883,7 +883,7 @@ functions: ESpawnEffect eSpawnEffect; eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; eSpawnEffect.betType = BET_CANNON; - eSpawnEffect.vStretch = FLOAT3D(m_fStretch*0.5, m_fStretch*0.5, m_fStretch*0.5); + eSpawnEffect.vStretch = FLOAT3D(m_fStretch*0.5f, m_fStretch*0.5f, m_fStretch*0.5f); CEntityPointer penExplosion = CreateEntity(CPlacement3D(m_vLeftLaserTarget, ANGLE3D(0.0f, 0.0f, 0.0f)), CLASS_BASIC_EFFECT); penExplosion->Initialize(eSpawnEffect); @@ -908,7 +908,7 @@ functions: ESpawnEffect eSpawnEffect; eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; eSpawnEffect.betType = BET_CANNON; - eSpawnEffect.vStretch = FLOAT3D(m_fStretch*0.5, m_fStretch*0.5, m_fStretch*0.5); + eSpawnEffect.vStretch = FLOAT3D(m_fStretch*0.5f, m_fStretch*0.5f, m_fStretch*0.5f); CEntityPointer penExplosion = CreateEntity(CPlacement3D(m_vLeftLaserTarget, ANGLE3D(0.0f, 0.0f, 0.0f)), CLASS_BASIC_EFFECT); penExplosion->Initialize(eSpawnEffect); @@ -1000,7 +1000,7 @@ procedures: ESpawnEffect eSpawnEffect; eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; eSpawnEffect.betType = BET_CANNON; - eSpawnEffect.vStretch = FLOAT3D(m_fStretch*0.5, m_fStretch*0.5, m_fStretch*0.5); + eSpawnEffect.vStretch = FLOAT3D(m_fStretch*0.5f, m_fStretch*0.5f, m_fStretch*0.5f); CEntityPointer penExplosion = CreateEntity(pl, CLASS_BASIC_EFFECT); penExplosion->Initialize(eSpawnEffect); autowait(FRnd()*0.25f+0.15f); @@ -1023,7 +1023,7 @@ procedures: ESpawnEffect eSpawnEffect; eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; eSpawnEffect.betType = BET_CANNON; - eSpawnEffect.vStretch = FLOAT3D(m_fStretch*1.5,m_fStretch*1.5,m_fStretch*1.5); + eSpawnEffect.vStretch = FLOAT3D(m_fStretch*1.5f,m_fStretch*1.5f,m_fStretch*1.5f); CEntityPointer penExplosion = CreateEntity(pl, CLASS_BASIC_EFFECT); penExplosion->Initialize(eSpawnEffect); eSpawnEffect.betType = BET_ROCKET; @@ -1063,7 +1063,7 @@ procedures: // randomize explosion position and size CPlacement3D plExplosion; plExplosion.pl_OrientationAngle = ANGLE3D(0.0f, 0.0f, 0.0f); - plExplosion.pl_PositionVector = FLOAT3D(FRnd()*2.0-1.0f, FRnd()*3.0-1.5f+LARVA_HANDLE_TRANSLATE, FRnd()*2.0-1.0f)*m_fStretch + GetPlacement().pl_PositionVector; + plExplosion.pl_PositionVector = FLOAT3D(FRnd()*2.0f-1.0f, FRnd()*3.0f-1.5f+LARVA_HANDLE_TRANSLATE, FRnd()*2.0f-1.0f)*m_fStretch + GetPlacement().pl_PositionVector; FLOAT vExpSize = (FRnd()*0.7f+0.7f)*m_fStretch; ESpawnEffect eSpawnEffect; @@ -1289,7 +1289,7 @@ procedures: m_bRechargedAtLeastOnce = TRUE; } SetHealth(ClampUp(GetHealth()+m_fRechargePerSecond, m_fMaxHealth*m_fMaxRechargedHealth)); - if (GetHealth()>m_fMaxHealth*0.95) { + if (GetHealth()>m_fMaxHealth*0.95f) { m_ltTarget = LT_ENEMY; m_bRecharging = FALSE; // deactivate beam diff --git a/Sources/EntitiesMP/ExotechLarvaBattery.es b/Sources/EntitiesMP/ExotechLarvaBattery.es old mode 100644 new mode 100755 index ec70e4b..47233a7 --- a/Sources/EntitiesMP/ExotechLarvaBattery.es +++ b/Sources/EntitiesMP/ExotechLarvaBattery.es @@ -125,7 +125,7 @@ functions: RemoveAttachment(WALLCHARGER_ATTACHMENT_LIGHT); GetModelObject()->PlayAnim(WALLCHARGER_ANIM_DAMAGE01, AOF_SMOOTHCHANGE|AOF_NORESTART); SpawnExplosions(); - } else if (fNewHealth<=0.33*m_fMaxHealth && fLastHealth>0.33*m_fMaxHealth) { + } else if (fNewHealth<=0.33f*m_fMaxHealth && fLastHealth>0.33f*m_fMaxHealth) { RemoveAttachment(WALLCHARGER_ATTACHMENT_PLASMA); GetModelObject()->PlayAnim(WALLCHARGER_ANIM_DAMAGE02, AOF_SMOOTHCHANGE|AOF_NORESTART); SpawnExplosions(); diff --git a/Sources/EntitiesMP/Fish.es b/Sources/EntitiesMP/Fish.es old mode 100644 new mode 100755 index 5f16eac..4806a2e --- a/Sources/EntitiesMP/Fish.es +++ b/Sources/EntitiesMP/Fish.es @@ -212,7 +212,7 @@ functions: if( fTimePassed > 0.25f) { // calculate light dying factor - fDieFactor = 1.0-(ClampUp(fTimePassed-0.25f,0.5f)/0.5f); + fDieFactor = 1.0f-(ClampUp(fTimePassed-0.25f,0.5f)/0.5f); } // adjust light fx FLOAT fR = 0.7f+0.1f*(FLOAT(rand())/RAND_MAX); diff --git a/Sources/EntitiesMP/Flame.es b/Sources/EntitiesMP/Flame.es old mode 100644 new mode 100755 index fb1ea1d..1d54598 --- a/Sources/EntitiesMP/Flame.es +++ b/Sources/EntitiesMP/Flame.es @@ -277,7 +277,7 @@ procedures: } // if the plane is mostly horizontal - if (Abs(plPlane(2))>0.5) { + if (Abs(plPlane(2))>0.5f) { // use cross product of +x axis and plane normal as +s axis vU = FLOAT3D(1.0f, 0.0f, 0.0f)*m_vPlaneNormal; // if the plane is mostly vertical diff --git a/Sources/EntitiesMP/Player.es b/Sources/EntitiesMP/Player.es old mode 100644 new mode 100755 index ef90ebf..a249fe5 --- a/Sources/EntitiesMP/Player.es +++ b/Sources/EntitiesMP/Player.es @@ -2936,14 +2936,14 @@ functions: FLOAT fKickDamage = fDamageAmmount; if( (dmtType == DMT_EXPLOSION) || (dmtType == DMT_IMPACT) || (dmtType == DMT_CANNONBALL_EXPLOSION) ) { - fKickDamage*=1.5; + fKickDamage*=1.5f; } if (dmtType==DMT_DROWNING || dmtType==DMT_CLOSERANGE) { - fKickDamage /= 10; + fKickDamage /= 10.0f; } if (dmtType==DMT_CHAINSAW) { - fKickDamage /= 10; + fKickDamage /= 10.0f; } // get passed time since last damage @@ -4744,7 +4744,7 @@ functions: mDesired = en_mRotation*(mDesired*!en_mRotation); FLOATmatrix3D mForced = !mDesired*mCurr*!mLast; // = aCurr-aLast-aDesired; ANGLE3D aForced; DecomposeRotationMatrixNoSnap(aForced, mForced); - if (aForced.MaxNorm()<1E-2) { + if (aForced.MaxNorm()<1E-2f) { aForced = ANGLE3D(0,0,0); } FLOATquat3D qForced; qForced.FromEuler(aForced); diff --git a/Sources/EntitiesMP/PlayerView.es b/Sources/EntitiesMP/PlayerView.es old mode 100644 new mode 100755 index 39f370d..cf9efa6 --- a/Sources/EntitiesMP/PlayerView.es +++ b/Sources/EntitiesMP/PlayerView.es @@ -171,7 +171,7 @@ functions: if (bFollowCrossHair) { FLOAT3D vTarget = vBase-ppw->m_vRayHit; FLOAT fLen = vTarget.Length(); - if (fLen>0.01) { + if (fLen>0.01f) { vTarget/=fLen; } else { vTarget = FLOAT3D(0,1,0); diff --git a/Sources/EntitiesMP/PlayerWeapons.es b/Sources/EntitiesMP/PlayerWeapons.es old mode 100644 new mode 100755 index 0b02517..4ab5858 --- a/Sources/EntitiesMP/PlayerWeapons.es +++ b/Sources/EntitiesMP/PlayerWeapons.es @@ -1962,7 +1962,7 @@ functions: FLOAT3D vToTarget = penClosest->GetPlacement().pl_PositionVector - m_penPlayer->GetPlacement().pl_PositionVector; FLOAT3D vTargetHeading = FLOAT3D(0.0, 0.0, -1.0f)*penClosest->GetRotationMatrix(); vToTarget.Normalize(); vTargetHeading.Normalize(); - if (vToTarget%vTargetHeading>0.64279) //CosFast(50.0f) + if (vToTarget%vTargetHeading>0.64279f) //CosFast(50.0f) { PrintCenterMessage(this, m_penPlayer, TRANS("Backstab!"), 4.0f, MSS_NONE); fDamage *= 4.0f; @@ -4336,7 +4336,7 @@ procedures: } } - autowait(GetSP()->sp_bCooperative ? 0.5f : 0.375); + autowait(GetSP()->sp_bCooperative ? 0.5f : 0.375f); /* drop shell */ /* add one empty bullet shell */ diff --git a/Sources/EntitiesMP/PowerUpItem.es b/Sources/EntitiesMP/PowerUpItem.es old mode 100644 new mode 100755 index 088061b..d561789 --- a/Sources/EntitiesMP/PowerUpItem.es +++ b/Sources/EntitiesMP/PowerUpItem.es @@ -157,7 +157,7 @@ functions: m_strDescription.PrintF("Invisibility"); AddItem( MODEL_INVISIB, TEXTURE_REFLECTION_METAL, 0, TEXTURE_SPECULAR_STRONG, 0); // set appearance AddFlare( MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); // add flare - StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75f)); break; case PUIT_INVULNER: StartModelAnim( ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); @@ -166,7 +166,7 @@ functions: m_strDescription.PrintF("Invulnerability"); AddItem( MODEL_INVULNER, TEXTURE_REFLECTION_GOLD, TEXTURE_REFLECTION_METAL, TEXTURE_SPECULAR_MEDIUM, 0); // set appearance AddFlare( MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); // add flare - StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75f)); break; case PUIT_DAMAGE: StartModelAnim( ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); @@ -175,7 +175,7 @@ functions: m_strDescription.PrintF("SeriousDamage"); AddItem( MODEL_DAMAGE, TEXTURE_DAMAGE, 0, TEXTURE_SPECULAR_STRONG, 0); // set appearance AddFlare( MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); // add flare - StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75f)); break; case PUIT_SPEED: StartModelAnim( ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); @@ -184,7 +184,7 @@ functions: m_strDescription.PrintF("SeriousSpeed"); AddItem( MODEL_SPEED, TEXTURE_SPEED, 0, 0, 0); // set appearance AddFlare( MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); // add flare - StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + StretchItem( FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75f)); break; case PUIT_BOMB: StartModelAnim( ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); @@ -193,7 +193,7 @@ functions: m_strDescription.PrintF("Serious Bomb!"); AddItem( MODEL_BOMB, TEXTURE_BOMB, 0, 0, 0); // set appearance AddFlare( MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); // add flare - StretchItem( FLOAT3D(1.0f*3.0f, 1.0f*3.0f, 1.0f*3.0)); + StretchItem( FLOAT3D(1.0f*3.0f, 1.0f*3.0f, 1.0f*3.0f)); break; } }; diff --git a/Sources/EntitiesMP/Projectile.es b/Sources/EntitiesMP/Projectile.es old mode 100644 new mode 100755 index 6d71e36..f68ca19 --- a/Sources/EntitiesMP/Projectile.es +++ b/Sources/EntitiesMP/Projectile.es @@ -1658,7 +1658,7 @@ void LavamanBombExplosion(void) { FLOAT fHeading = (FRnd()-0.5f)*180.0f; FLOAT fPitch = 10.0f+FRnd()*40.0f; - FLOAT fSpeed = 10.0+FRnd()*50.0f; + FLOAT fSpeed = 10.0f+FRnd()*50.0f; // launch CPlacement3D pl = GetPlacement(); @@ -1961,7 +1961,7 @@ void BeastProjectileExplosion(void) for( INDEX iDebris=0; iDebris<2; iDebris++) { FLOAT fPitch = 10.0f+FRnd()*10.0f; - FLOAT fSpeed = 5.0+FRnd()*20.0f; + FLOAT fSpeed = 5.0f+FRnd()*20.0f; // launch CPlacement3D pl = GetPlacement(); @@ -2019,7 +2019,7 @@ void BeastBigProjectileExplosion(void) { FLOAT fHeading = (FRnd()-0.5f)*180.0f; FLOAT fPitch = 10.0f+FRnd()*40.0f; - FLOAT fSpeed = 10.0+FRnd()*50.0f; + FLOAT fSpeed = 10.0f+FRnd()*50.0f; // launch CPlacement3D pl = GetPlacement(); @@ -2258,7 +2258,7 @@ void DevilGuidedProjectileExplosion(void) { FLOAT fHeading = (FRnd()-0.5f)*180.0f; FLOAT fPitch = 10.0f+FRnd()*40.0f; - FLOAT fSpeed = 10.0+FRnd()*50.0f; + FLOAT fSpeed = 10.0f+FRnd()*50.0f; // launch CPlacement3D pl = GetPlacement(); @@ -3371,7 +3371,7 @@ procedures: ((CProjectile*)&*etouch.penOther)->m_prtType==m_prtType)); bHit &= !IsOfClass(etouch.penOther, "Demon"); FLOAT3D vTrans = en_vCurrentTranslationAbsolute; - bHit &= Abs(vTrans.Normalize() % FLOAT3D(etouch.plCollision)) > 0.35; + bHit &= Abs(vTrans.Normalize() % FLOAT3D(etouch.plCollision)) > 0.35f; if (bHit) { ProjectileTouch(etouch.penOther); diff --git a/Sources/EntitiesMP/Shooter.es b/Sources/EntitiesMP/Shooter.es old mode 100644 new mode 100755 index 171b817..bbdc999 --- a/Sources/EntitiesMP/Shooter.es +++ b/Sources/EntitiesMP/Shooter.es @@ -278,7 +278,7 @@ procedures: // possible random wait if (m_fRndBeginWait>0.0f) { - FLOAT fRndWait = FRnd()*m_fRndBeginWait+0.05; + FLOAT fRndWait = FRnd()*m_fRndBeginWait+0.05f; autowait(fRndWait); } diff --git a/Sources/EntitiesMP/Summoner.es b/Sources/EntitiesMP/Summoner.es old mode 100644 new mode 100755 index ec0dc82..c424631 --- a/Sources/EntitiesMP/Summoner.es +++ b/Sources/EntitiesMP/Summoner.es @@ -564,7 +564,7 @@ functions: //CPrintF("FIRE DISABLED -> too much fuss\n"); m_bFireOK = FALSE; // enable firing only when very little fuss - } else if (m_fFuss<0.4*m_fMaxCurrentFuss) { + } else if (m_fFuss<0.4f*m_fMaxCurrentFuss) { //CPrintF("FIRE ENABLE -> fuss more then %f\n", 0.4*m_fMaxCurrentFuss); m_bFireOK = TRUE; // but if significant damage since last spawn, enable firing anyway @@ -922,7 +922,7 @@ procedures: } if (iEnemyCount<6) { - fToSpawn = (6.0 - (FLOAT)iEnemyCount)/2.0f; + fToSpawn = (6.0f - (FLOAT)iEnemyCount)/2.0f; } else { fToSpawn = 1.0f; } diff --git a/Sources/EntitiesMP/WorldSettingsController.es b/Sources/EntitiesMP/WorldSettingsController.es old mode 100644 new mode 100755 index 0349e26..382310e --- a/Sources/EntitiesMP/WorldSettingsController.es +++ b/Sources/EntitiesMP/WorldSettingsController.es @@ -29,16 +29,16 @@ properties: 3 FLOAT m_tmLightningStart = -1.0f, // lightning start time 4 FLOAT m_fLightningPower = 1.0f, // lightning power 5 FLOAT m_tmStormEnd = -1.0f, // storm end time - 6 FLOAT m_tmPyramidPlatesStart = 1e6, // time when pyramid plates blend started - 7 FLOAT m_tmActivatedPlate1 = 1e6, // time when plate 1 has been activated - 8 FLOAT m_tmDeactivatedPlate1 = 1e6, // time when plate 1 has been deactivated - 9 FLOAT m_tmActivatedPlate2 = 1e6, // time when plate 2 has been activated - 10 FLOAT m_tmDeactivatedPlate2 = 1e6, // time when plate 2 has been deactivated - 11 FLOAT m_tmActivatedPlate3 = 1e6, // time when plate 3 has been activated - 12 FLOAT m_tmDeactivatedPlate3 = 1e6, // time when plate 3 has been deactivated - 13 FLOAT m_tmActivatedPlate4 = 1e6, // time when plate 4 has been activated - 14 FLOAT m_tmDeactivatedPlate4 = 1e6, // time when plate 4 has been deactivated - 15 FLOAT m_tmPyramidMorphRoomActivated = 1e6, // time when pyramid morph room has been activated + 6 FLOAT m_tmPyramidPlatesStart = 1e6f, // time when pyramid plates blend started + 7 FLOAT m_tmActivatedPlate1 = 1e6f, // time when plate 1 has been activated + 8 FLOAT m_tmDeactivatedPlate1 = 1e6f, // time when plate 1 has been deactivated + 9 FLOAT m_tmActivatedPlate2 = 1e6f, // time when plate 2 has been activated + 10 FLOAT m_tmDeactivatedPlate2 = 1e6f, // time when plate 2 has been deactivated + 11 FLOAT m_tmActivatedPlate3 = 1e6f, // time when plate 3 has been activated + 12 FLOAT m_tmDeactivatedPlate3 = 1e6f, // time when plate 3 has been deactivated + 13 FLOAT m_tmActivatedPlate4 = 1e6f, // time when plate 4 has been activated + 14 FLOAT m_tmDeactivatedPlate4 = 1e6f, // time when plate 4 has been deactivated + 15 FLOAT m_tmPyramidMorphRoomActivated = 1e6f, // time when pyramid morph room has been activated 20 FLOAT m_tmShakeStarted = -1.0f, // time when shaking started 21 FLOAT3D m_vShakePos = FLOAT3D(0,0,0), // shake position @@ -207,8 +207,8 @@ procedures: SetModel(MODEL_WORLD_SETTINGS_CONTROLLER); SetModelMainTexture(TEXTURE_WORLD_SETTINGS_CONTROLLER); - m_tmStormStart = 1e5-1.0f; - m_tmStormEnd = 1e5; + m_tmStormStart = 1e5f-1.0f; + m_tmStormEnd = 1e5f; // do nothing return; diff --git a/Sources/GameMP/CompModels.cpp b/Sources/GameMP/CompModels.cpp old mode 100644 new mode 100755 index 00fe4ce..b828575 --- a/Sources/GameMP/CompModels.cpp +++ b/Sources/GameMP/CompModels.cpp @@ -969,7 +969,7 @@ void RenderMessageModel(CDrawPort *pdp, const CTString &strModel) apr = pr; BeginModelRenderingView(apr, pdp); rm.rm_vLightDirection = _vLightDir; - const FLOAT fDistance = 1+ 10*(1/(_fMsgAppearFade+0.01) - 1/(1+0.01)); + const FLOAT fDistance = 1.0f+ 10.f*(1.0f/(_fMsgAppearFade+0.01f) - 1.0f/(1.0f+0.01f)); // if model needs floor if( _bHasFloor) { From 422db3c58c5b1ba36c14ece4d9fb9f583386c056 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 8 Apr 2016 00:11:36 +0200 Subject: [PATCH 02/10] Preliminary First Encounter support --- Sources/CMakeLists.txt | 454 +- Sources/Entities/Acid.es | 70 + Sources/Entities/AirWave.es | 151 + Sources/Entities/AmmoItem.es | 391 ++ Sources/Entities/AmmoPack.es | 203 + Sources/Entities/AnimationChanger.es | 146 + Sources/Entities/AnimationHub.es | 147 + Sources/Entities/ArmorItem.es | 254 + Sources/Entities/BackgroundViewer.es | 68 + Sources/Entities/BasicEffects.es | 1238 ++++ Sources/Entities/Beast.es | 450 ++ Sources/Entities/BigHead.es | 209 + Sources/Entities/BlendController.es | 126 + Sources/Entities/BloodSpray.es | 130 + Sources/Entities/Boneman.es | 385 ++ Sources/Entities/Bouncer.es | 65 + Sources/Entities/Bullet.es | 420 ++ Sources/Entities/Camera.es | 443 ++ Sources/Entities/CameraMarker.es | 69 + Sources/Entities/CannonBall.es | 604 ++ Sources/Entities/Catman.es | 182 + Sources/Entities/Common/Common.cpp | 1117 ++++ Sources/Entities/Common/Common.h | 215 + Sources/Entities/Common/Debris.cpp | 0 Sources/Entities/Common/Flags.h | 157 + Sources/Entities/Common/GameInterface.h | 65 + Sources/Entities/Common/HUD.cpp | 1106 ++++ Sources/Entities/Common/HUD.h | 0 Sources/Entities/Common/Particles.cpp | 2988 ++++++++++ Sources/Entities/Common/Particles.h | 88 + Sources/Entities/Common/PathFinding.cpp | 280 + Sources/Entities/Common/PathFinding.h | 40 + Sources/Entities/Common/Stats.cpp | 0 Sources/Entities/Common/WeaponPositions.h | 373 ++ Sources/Entities/Copier.es | 94 + Sources/Entities/Counter.es | 124 + Sources/Entities/CrateRider.es | 214 + Sources/Entities/Cyborg.es | 743 +++ Sources/Entities/CyborgBike.es | 132 + Sources/Entities/Damager.es | 73 + Sources/Entities/Debris.es | 276 + Sources/Entities/DestroyableArchitecture.es | 415 ++ Sources/Entities/Devil.es | 2415 ++++++++ Sources/Entities/DevilMarker.es | 155 + Sources/Entities/DevilProjectile.es | 270 + Sources/Entities/DoorController.es | 334 ++ Sources/Entities/Dragonman.es | 616 ++ Sources/Entities/EffectMarker.es | 291 + Sources/Entities/Effector.es | 468 ++ Sources/Entities/Elemental.es | 1503 +++++ Sources/Entities/EnemyBase.es | 2785 +++++++++ Sources/Entities/EnemyCounter.es | 105 + Sources/Entities/EnemyDive.es | 250 + Sources/Entities/EnemyFly.es | 479 ++ Sources/Entities/EnemyMarker.es | 53 + Sources/Entities/EnemyRunInto.es | 283 + Sources/Entities/EnemySpawner.es | 389 ++ Sources/Entities/Entities.dsp | 5430 +++++++++++++++++ Sources/Entities/EnvironmentBase.es | 416 ++ Sources/Entities/EnvironmentMarker.es | 92 + Sources/Entities/Eruptor.es | 264 + Sources/Entities/Eyeman.es | 517 ++ Sources/Entities/Fish.es | 335 ++ Sources/Entities/Fishman.es | 350 ++ Sources/Entities/Flame.es | 182 + Sources/Entities/FogMarker.es | 142 + Sources/Entities/GhostBusterRay.cpp | 272 + Sources/Entities/GhostBusterRay.es | 229 + Sources/Entities/GhostBusterRay.h | 73 + Sources/Entities/GhostBusterRay_tables.h | 49 + Sources/Entities/Gizmo.es | 341 ++ Sources/Entities/Global.es | 155 + Sources/Entities/GradientMarker.es | 93 + Sources/Entities/GravityMarker.es | 162 + Sources/Entities/GravityRouter.es | 83 + Sources/Entities/HazeMarker.es | 126 + Sources/Entities/Headman.es | 691 +++ Sources/Entities/HealthItem.es | 263 + Sources/Entities/Huanman.es | 180 + Sources/Entities/Item.es | 279 + Sources/Entities/KeyItem.es | 350 ++ Sources/Entities/LastFileID.txt | 5 + Sources/Entities/Light.es | 454 ++ Sources/Entities/LightStyle.es | 33 + Sources/Entities/Lightning.es | 258 + Sources/Entities/Mamut.es | 452 ++ Sources/Entities/Mamutman.es | 289 + Sources/Entities/Mantaman.es | 197 + Sources/Entities/Marker.es | 59 + Sources/Entities/MessageHolder.es | 63 + Sources/Entities/MessageItem.es | 102 + Sources/Entities/MirrorMarker.es | 82 + Sources/Entities/ModelDestruction.es | 195 + Sources/Entities/ModelHolder.es | 176 + Sources/Entities/ModelHolder2.es | 640 ++ Sources/Entities/MovingBrush.es | 848 +++ Sources/Entities/MovingBrushMarker.es | 58 + Sources/Entities/MusicChanger.es | 76 + Sources/Entities/MusicHolder.es | 400 ++ Sources/Entities/NavigationMarker.es | 178 + Sources/Entities/ParticlesHolder.es | 225 + Sources/Entities/Pendulum.es | 112 + Sources/Entities/Pipebomb.es | 258 + Sources/Entities/Player.es | 5887 +++++++++++++++++++ Sources/Entities/PlayerActionMarker.es | 107 + Sources/Entities/PlayerAnimator.es | 1550 +++++ Sources/Entities/PlayerMarker.es | 90 + Sources/Entities/PlayerView.es | 241 + Sources/Entities/PlayerWeapons.es | 4838 +++++++++++++++ Sources/Entities/PlayerWeaponsEffects.es | 108 + Sources/Entities/Projectile.es | 2543 ++++++++ Sources/Entities/PyramidSpaceShip.es | 921 +++ Sources/Entities/PyramidSpaceShipMarker.es | 100 + Sources/Entities/Reminder.es | 52 + Sources/Entities/RobotDriving.es | 263 + Sources/Entities/RobotFixed.es | 0 Sources/Entities/RobotFlying.es | 209 + Sources/Entities/RollingStone.es | 341 ++ Sources/Entities/Scorpman.es | 638 ++ Sources/Entities/Ship.es | 337 ++ Sources/Entities/ShipMarker.es | 46 + Sources/Entities/SoundHolder.es | 136 + Sources/Entities/StdH/StdH.cpp | 17 + Sources/Entities/StdH/StdH.h | 36 + Sources/Entities/StormController.es | 239 + Sources/Entities/Switch.es | 193 + Sources/Entities/Teleport.es | 94 + Sources/Entities/TouchField.es | 140 + Sources/Entities/Trigger.es | 234 + Sources/Entities/Twister.es | 290 + Sources/Entities/VoiceHolder.es | 80 + Sources/Entities/Walker.es | 499 ++ Sources/Entities/WatchPlayers.es | 161 + Sources/Entities/Watcher.es | 363 ++ Sources/Entities/Water.es | 209 + Sources/Entities/WeaponItem.es | 465 ++ Sources/Entities/Werebull.es | 318 + Sources/Entities/Woman.es | 341 ++ Sources/Entities/WorldBase.es | 1247 ++++ Sources/Entities/WorldLink.es | 64 + Sources/Entities/WorldSettingsController.es | 124 + Sources/SeriousSam/SeriousSam.cpp | 2 +- 142 files changed, 64705 insertions(+), 153 deletions(-) create mode 100644 Sources/Entities/Acid.es create mode 100644 Sources/Entities/AirWave.es create mode 100644 Sources/Entities/AmmoItem.es create mode 100644 Sources/Entities/AmmoPack.es create mode 100644 Sources/Entities/AnimationChanger.es create mode 100644 Sources/Entities/AnimationHub.es create mode 100644 Sources/Entities/ArmorItem.es create mode 100644 Sources/Entities/BackgroundViewer.es create mode 100644 Sources/Entities/BasicEffects.es create mode 100644 Sources/Entities/Beast.es create mode 100644 Sources/Entities/BigHead.es create mode 100644 Sources/Entities/BlendController.es create mode 100644 Sources/Entities/BloodSpray.es create mode 100644 Sources/Entities/Boneman.es create mode 100644 Sources/Entities/Bouncer.es create mode 100644 Sources/Entities/Bullet.es create mode 100644 Sources/Entities/Camera.es create mode 100644 Sources/Entities/CameraMarker.es create mode 100644 Sources/Entities/CannonBall.es create mode 100644 Sources/Entities/Catman.es create mode 100644 Sources/Entities/Common/Common.cpp create mode 100644 Sources/Entities/Common/Common.h create mode 100644 Sources/Entities/Common/Debris.cpp create mode 100644 Sources/Entities/Common/Flags.h create mode 100644 Sources/Entities/Common/GameInterface.h create mode 100644 Sources/Entities/Common/HUD.cpp create mode 100644 Sources/Entities/Common/HUD.h create mode 100644 Sources/Entities/Common/Particles.cpp create mode 100644 Sources/Entities/Common/Particles.h create mode 100644 Sources/Entities/Common/PathFinding.cpp create mode 100644 Sources/Entities/Common/PathFinding.h create mode 100644 Sources/Entities/Common/Stats.cpp create mode 100644 Sources/Entities/Common/WeaponPositions.h create mode 100644 Sources/Entities/Copier.es create mode 100644 Sources/Entities/Counter.es create mode 100644 Sources/Entities/CrateRider.es create mode 100644 Sources/Entities/Cyborg.es create mode 100644 Sources/Entities/CyborgBike.es create mode 100644 Sources/Entities/Damager.es create mode 100644 Sources/Entities/Debris.es create mode 100644 Sources/Entities/DestroyableArchitecture.es create mode 100644 Sources/Entities/Devil.es create mode 100644 Sources/Entities/DevilMarker.es create mode 100644 Sources/Entities/DevilProjectile.es create mode 100644 Sources/Entities/DoorController.es create mode 100644 Sources/Entities/Dragonman.es create mode 100644 Sources/Entities/EffectMarker.es create mode 100644 Sources/Entities/Effector.es create mode 100644 Sources/Entities/Elemental.es create mode 100644 Sources/Entities/EnemyBase.es create mode 100644 Sources/Entities/EnemyCounter.es create mode 100644 Sources/Entities/EnemyDive.es create mode 100644 Sources/Entities/EnemyFly.es create mode 100644 Sources/Entities/EnemyMarker.es create mode 100644 Sources/Entities/EnemyRunInto.es create mode 100644 Sources/Entities/EnemySpawner.es create mode 100644 Sources/Entities/Entities.dsp create mode 100644 Sources/Entities/EnvironmentBase.es create mode 100644 Sources/Entities/EnvironmentMarker.es create mode 100644 Sources/Entities/Eruptor.es create mode 100644 Sources/Entities/Eyeman.es create mode 100644 Sources/Entities/Fish.es create mode 100644 Sources/Entities/Fishman.es create mode 100644 Sources/Entities/Flame.es create mode 100644 Sources/Entities/FogMarker.es create mode 100644 Sources/Entities/GhostBusterRay.cpp create mode 100644 Sources/Entities/GhostBusterRay.es create mode 100644 Sources/Entities/GhostBusterRay.h create mode 100644 Sources/Entities/GhostBusterRay_tables.h create mode 100644 Sources/Entities/Gizmo.es create mode 100644 Sources/Entities/Global.es create mode 100644 Sources/Entities/GradientMarker.es create mode 100644 Sources/Entities/GravityMarker.es create mode 100644 Sources/Entities/GravityRouter.es create mode 100644 Sources/Entities/HazeMarker.es create mode 100644 Sources/Entities/Headman.es create mode 100644 Sources/Entities/HealthItem.es create mode 100644 Sources/Entities/Huanman.es create mode 100644 Sources/Entities/Item.es create mode 100644 Sources/Entities/KeyItem.es create mode 100644 Sources/Entities/LastFileID.txt create mode 100644 Sources/Entities/Light.es create mode 100644 Sources/Entities/LightStyle.es create mode 100644 Sources/Entities/Lightning.es create mode 100644 Sources/Entities/Mamut.es create mode 100644 Sources/Entities/Mamutman.es create mode 100644 Sources/Entities/Mantaman.es create mode 100644 Sources/Entities/Marker.es create mode 100644 Sources/Entities/MessageHolder.es create mode 100644 Sources/Entities/MessageItem.es create mode 100644 Sources/Entities/MirrorMarker.es create mode 100644 Sources/Entities/ModelDestruction.es create mode 100644 Sources/Entities/ModelHolder.es create mode 100644 Sources/Entities/ModelHolder2.es create mode 100644 Sources/Entities/MovingBrush.es create mode 100644 Sources/Entities/MovingBrushMarker.es create mode 100644 Sources/Entities/MusicChanger.es create mode 100644 Sources/Entities/MusicHolder.es create mode 100644 Sources/Entities/NavigationMarker.es create mode 100644 Sources/Entities/ParticlesHolder.es create mode 100644 Sources/Entities/Pendulum.es create mode 100644 Sources/Entities/Pipebomb.es create mode 100644 Sources/Entities/Player.es create mode 100644 Sources/Entities/PlayerActionMarker.es create mode 100644 Sources/Entities/PlayerAnimator.es create mode 100644 Sources/Entities/PlayerMarker.es create mode 100644 Sources/Entities/PlayerView.es create mode 100644 Sources/Entities/PlayerWeapons.es create mode 100644 Sources/Entities/PlayerWeaponsEffects.es create mode 100644 Sources/Entities/Projectile.es create mode 100644 Sources/Entities/PyramidSpaceShip.es create mode 100644 Sources/Entities/PyramidSpaceShipMarker.es create mode 100644 Sources/Entities/Reminder.es create mode 100644 Sources/Entities/RobotDriving.es create mode 100644 Sources/Entities/RobotFixed.es create mode 100644 Sources/Entities/RobotFlying.es create mode 100644 Sources/Entities/RollingStone.es create mode 100644 Sources/Entities/Scorpman.es create mode 100644 Sources/Entities/Ship.es create mode 100644 Sources/Entities/ShipMarker.es create mode 100644 Sources/Entities/SoundHolder.es create mode 100644 Sources/Entities/StdH/StdH.cpp create mode 100644 Sources/Entities/StdH/StdH.h create mode 100644 Sources/Entities/StormController.es create mode 100644 Sources/Entities/Switch.es create mode 100644 Sources/Entities/Teleport.es create mode 100644 Sources/Entities/TouchField.es create mode 100644 Sources/Entities/Trigger.es create mode 100644 Sources/Entities/Twister.es create mode 100644 Sources/Entities/VoiceHolder.es create mode 100644 Sources/Entities/Walker.es create mode 100644 Sources/Entities/WatchPlayers.es create mode 100644 Sources/Entities/Watcher.es create mode 100644 Sources/Entities/Water.es create mode 100644 Sources/Entities/WeaponItem.es create mode 100644 Sources/Entities/Werebull.es create mode 100644 Sources/Entities/Woman.es create mode 100644 Sources/Entities/WorldBase.es create mode 100644 Sources/Entities/WorldLink.es create mode 100644 Sources/Entities/WorldSettingsController.es diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 3c04132..e545098 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -111,6 +111,16 @@ option(USE_TREMOR "Use Tremor instead of Vorbis" FALSE) if (USE_TREMOR) add_definitions(-DUSE_TREMOR=1) endif() + +option(TFE "Compile a The First Encounter version" FALSE) +if (TFE) + add_definitions(-DFIRST_ENCOUNTER=1) + set(MP "") +else() + set(MP "MP") +endif() + + # !!! FIXME: I currently force this, but you shouldn't _have_ to. add_definitions(-DSINGLE_THREADED=1) @@ -190,166 +200,302 @@ entity(Engine/Classes/PlayerEntity) set(ENGINE_ENTITIES_CPP ${ENTITIES_CPP}) set(ENTITIES_CPP "") -entity(EntitiesMP/AirElemental) -entity(EntitiesMP/AirShockwave) -entity(EntitiesMP/AmmoItem) -entity(EntitiesMP/AmmoPack) -entity(EntitiesMP/AnimationChanger) -entity(EntitiesMP/AnimationHub) -entity(EntitiesMP/AreaMarker) -entity(EntitiesMP/ArmorItem) -entity(EntitiesMP/BackgroundViewer) -entity(EntitiesMP/BasicEffects) -entity(EntitiesMP/Beast) -entity(EntitiesMP/BigHead) -entity(EntitiesMP/BlendController) -entity(EntitiesMP/BloodSpray) -entity(EntitiesMP/Boneman) -entity(EntitiesMP/Bouncer) -entity(EntitiesMP/Bullet) -entity(EntitiesMP/Camera) -entity(EntitiesMP/CameraMarker) -entity(EntitiesMP/CannonBall) -entity(EntitiesMP/CannonRotating) -entity(EntitiesMP/CannonStatic) -entity(EntitiesMP/ChainsawFreak) -entity(EntitiesMP/Copier) -entity(EntitiesMP/Counter) -entity(EntitiesMP/CrateBus) -entity(EntitiesMP/CrateRider) -entity(EntitiesMP/CreditsHolder) -entity(EntitiesMP/Damager) -entity(EntitiesMP/Debris) -entity(EntitiesMP/DebugEntityStatesDisplay) -entity(EntitiesMP/Demon) -entity(EntitiesMP/DestroyableArchitecture) -entity(EntitiesMP/Devil) -entity(EntitiesMP/DevilMarker) -entity(EntitiesMP/DevilProjectile) -entity(EntitiesMP/DoorController) -entity(EntitiesMP/Dragonman) -entity(EntitiesMP/EffectMarker) -entity(EntitiesMP/Effector) -entity(EntitiesMP/Elemental) -entity(EntitiesMP/EnemyBase) -entity(EntitiesMP/EnemyCounter) -entity(EntitiesMP/EnemyDive) -entity(EntitiesMP/EnemyFly) -entity(EntitiesMP/EnemyMarker) -entity(EntitiesMP/EnemyRunInto) -entity(EntitiesMP/EnemySpawner) -entity(EntitiesMP/EnvironmentBase) -entity(EntitiesMP/EnvironmentMarker) -entity(EntitiesMP/EnvironmentParticlesHolder) -entity(EntitiesMP/Eruptor) -entity(EntitiesMP/ExotechLarva) -entity(EntitiesMP/ExotechLarvaBattery) -entity(EntitiesMP/ExotechLarvaCharger) -entity(EntitiesMP/Eyeman) -entity(EntitiesMP/Fireworks) -entity(EntitiesMP/Fish) -entity(EntitiesMP/Flame) -entity(EntitiesMP/FogMarker) -entity(EntitiesMP/Gizmo) -entity(EntitiesMP/Global) -entity(EntitiesMP/GradientMarker) -entity(EntitiesMP/GravityMarker) -entity(EntitiesMP/GravityRouter) -entity(EntitiesMP/Grunt) -entity(EntitiesMP/GruntSka) -entity(EntitiesMP/Guffy) -entity(EntitiesMP/HazeMarker) -entity(EntitiesMP/Headman) -entity(EntitiesMP/HealthItem) -entity(EntitiesMP/HudPicHolder) -entity(EntitiesMP/Item) -entity(EntitiesMP/KeyItem) -entity(EntitiesMP/LarvaOffspring) -entity(EntitiesMP/Light) -entity(EntitiesMP/Lightning) -entity(EntitiesMP/Marker) -entity(EntitiesMP/MessageHolder) -entity(EntitiesMP/MessageItem) -entity(EntitiesMP/MeteorShower) -entity(EntitiesMP/MirrorMarker) -entity(EntitiesMP/ModelDestruction) -entity(EntitiesMP/ModelHolder) -entity(EntitiesMP/ModelHolder2) -entity(EntitiesMP/ModelHolder3) -entity(EntitiesMP/MovingBrush) -entity(EntitiesMP/MovingBrushMarker) -entity(EntitiesMP/MusicChanger) -entity(EntitiesMP/MusicHolder) -entity(EntitiesMP/NavigationMarker) -entity(EntitiesMP/ParticlesHolder) -entity(EntitiesMP/Pendulum) -entity(EntitiesMP/PhotoAlbum) -entity(EntitiesMP/Pipebomb) -entity(EntitiesMP/Player) -entity(EntitiesMP/PlayerActionMarker) -entity(EntitiesMP/PlayerAnimator) -entity(EntitiesMP/PlayerMarker) -entity(EntitiesMP/PlayerView) -entity(EntitiesMP/PlayerWeapons) -entity(EntitiesMP/PlayerWeaponsEffects) -entity(EntitiesMP/PowerUpItem) -entity(EntitiesMP/Projectile) -entity(EntitiesMP/PyramidSpaceShip) -entity(EntitiesMP/PyramidSpaceShipMarker) -entity(EntitiesMP/Reminder) -entity(EntitiesMP/RollingStone) -entity(EntitiesMP/Santa) -entity(EntitiesMP/Scorpman) -entity(EntitiesMP/ScrollHolder) -entity(EntitiesMP/SeriousBomb) -entity(EntitiesMP/Ship) -entity(EntitiesMP/ShipMarker) -entity(EntitiesMP/Shooter) -entity(EntitiesMP/SoundHolder) -entity(EntitiesMP/SpawnerProjectile) -entity(EntitiesMP/Spinner) -entity(EntitiesMP/StormController) -entity(EntitiesMP/Summoner) -entity(EntitiesMP/SummonerMarker) -entity(EntitiesMP/Switch) -entity(EntitiesMP/TacticsChanger) -entity(EntitiesMP/TacticsHolder) -entity(EntitiesMP/Teleport) -entity(EntitiesMP/Terrain) -entity(EntitiesMP/TextFXHolder) -entity(EntitiesMP/TimeController) -entity(EntitiesMP/TouchField) -entity(EntitiesMP/Trigger) -entity(EntitiesMP/Twister) -entity(EntitiesMP/VoiceHolder) -entity(EntitiesMP/Walker) -entity(EntitiesMP/WatchPlayers) -entity(EntitiesMP/Watcher) -entity(EntitiesMP/Water) -entity(EntitiesMP/WeaponItem) -entity(EntitiesMP/Werebull) -entity(EntitiesMP/Woman) -entity(EntitiesMP/WorldBase) -entity(EntitiesMP/WorldLink) -entity(EntitiesMP/WorldSettingsController) +if(TFE) + entity(Entities/Acid) + entity(Entities/AirWave) + entity(Entities/AmmoItem) + entity(Entities/AmmoPack) + entity(Entities/AnimationChanger) + entity(Entities/AnimationHub) + entity(Entities/ArmorItem) + entity(Entities/BackgroundViewer) + entity(Entities/BasicEffects) + entity(Entities/Beast) + entity(Entities/BigHead) + entity(Entities/BlendController) + entity(Entities/BloodSpray) + entity(Entities/Boneman) + entity(Entities/Bouncer) + entity(Entities/Bullet) + entity(Entities/Camera) + entity(Entities/CameraMarker) + entity(Entities/CannonBall) + entity(Entities/Catman) + entity(Entities/Copier) + entity(Entities/Counter) + entity(Entities/CrateRider) + entity(Entities/CyborgBike) + entity(Entities/Cyborg) + entity(Entities/Damager) + entity(Entities/Debris) + entity(Entities/DestroyableArchitecture) + entity(Entities/Devil) + entity(Entities/DevilMarker) + entity(Entities/DevilProjectile) + entity(Entities/DoorController) + entity(Entities/Dragonman) + entity(Entities/EffectMarker) + entity(Entities/Effector) + entity(Entities/Elemental) + entity(Entities/EnemyBase) + entity(Entities/EnemyCounter) + entity(Entities/EnemyDive) + entity(Entities/EnemyFly) + entity(Entities/EnemyMarker) + entity(Entities/EnemyRunInto) + entity(Entities/EnemySpawner) + entity(Entities/EnvironmentBase) + entity(Entities/EnvironmentMarker) + entity(Entities/Eruptor) + entity(Entities/Eyeman) + entity(Entities/Fish) + entity(Entities/Fishman) + entity(Entities/Flame) + entity(Entities/FogMarker) + #entity(Entities/GhostBusterRay) + entity(Entities/Gizmo) + entity(Entities/Global) + entity(Entities/GradientMarker) + entity(Entities/GravityMarker) + entity(Entities/GravityRouter) + entity(Entities/HazeMarker) + entity(Entities/Headman) + entity(Entities/HealthItem) + entity(Entities/Huanman) + entity(Entities/Item) + entity(Entities/KeyItem) + entity(Entities/Light) + entity(Entities/Lightning) + entity(Entities/LightStyle) + entity(Entities/Mamut) + entity(Entities/Mamutman) + entity(Entities/Mantaman) + entity(Entities/Marker) + entity(Entities/MessageHolder) + entity(Entities/MessageItem) + entity(Entities/MirrorMarker) + entity(Entities/ModelDestruction) + entity(Entities/ModelHolder2) + entity(Entities/ModelHolder) + entity(Entities/MovingBrush) + entity(Entities/MovingBrushMarker) + entity(Entities/MusicChanger) + entity(Entities/MusicHolder) + entity(Entities/NavigationMarker) + entity(Entities/ParticlesHolder) + entity(Entities/Pendulum) + entity(Entities/Pipebomb) + entity(Entities/PlayerActionMarker) + entity(Entities/PlayerAnimator) + entity(Entities/Player) + entity(Entities/PlayerMarker) + entity(Entities/PlayerView) + entity(Entities/PlayerWeaponsEffects) + entity(Entities/PlayerWeapons) + entity(Entities/Projectile) + entity(Entities/PyramidSpaceShip) + entity(Entities/PyramidSpaceShipMarker) + entity(Entities/Reminder) + entity(Entities/RobotDriving) + entity(Entities/RobotFixed) + entity(Entities/RobotFlying) + entity(Entities/RollingStone) + entity(Entities/Scorpman) + entity(Entities/Ship) + entity(Entities/ShipMarker) + entity(Entities/SoundHolder) + entity(Entities/StormController) + entity(Entities/Switch) + entity(Entities/Teleport) + entity(Entities/TouchField) + entity(Entities/Trigger) + entity(Entities/Twister) + entity(Entities/VoiceHolder) + entity(Entities/Walker) + entity(Entities/Watcher) + entity(Entities/WatchPlayers) + entity(Entities/Water) + entity(Entities/WeaponItem) + entity(Entities/Werebull) + entity(Entities/Woman) + entity(Entities/WorldBase) + entity(Entities/WorldLink) + entity(Entities/WorldSettingsController) +else() + entity(EntitiesMP/AirElemental) + entity(EntitiesMP/AirShockwave) + entity(EntitiesMP/AmmoItem) + entity(EntitiesMP/AmmoPack) + entity(EntitiesMP/AnimationChanger) + entity(EntitiesMP/AnimationHub) + entity(EntitiesMP/AreaMarker) + entity(EntitiesMP/ArmorItem) + entity(EntitiesMP/BackgroundViewer) + entity(EntitiesMP/BasicEffects) + entity(EntitiesMP/Beast) + entity(EntitiesMP/BigHead) + entity(EntitiesMP/BlendController) + entity(EntitiesMP/BloodSpray) + entity(EntitiesMP/Boneman) + entity(EntitiesMP/Bouncer) + entity(EntitiesMP/Bullet) + entity(EntitiesMP/Camera) + entity(EntitiesMP/CameraMarker) + entity(EntitiesMP/CannonBall) + entity(EntitiesMP/CannonRotating) + entity(EntitiesMP/CannonStatic) + entity(EntitiesMP/ChainsawFreak) + entity(EntitiesMP/Copier) + entity(EntitiesMP/Counter) + entity(EntitiesMP/CrateBus) + entity(EntitiesMP/CrateRider) + entity(EntitiesMP/CreditsHolder) + entity(EntitiesMP/Damager) + entity(EntitiesMP/Debris) + entity(EntitiesMP/DebugEntityStatesDisplay) + entity(EntitiesMP/Demon) + entity(EntitiesMP/DestroyableArchitecture) + entity(EntitiesMP/Devil) + entity(EntitiesMP/DevilMarker) + entity(EntitiesMP/DevilProjectile) + entity(EntitiesMP/DoorController) + entity(EntitiesMP/Dragonman) + entity(EntitiesMP/EffectMarker) + entity(EntitiesMP/Effector) + entity(EntitiesMP/Elemental) + entity(EntitiesMP/EnemyBase) + entity(EntitiesMP/EnemyCounter) + entity(EntitiesMP/EnemyDive) + entity(EntitiesMP/EnemyFly) + entity(EntitiesMP/EnemyMarker) + entity(EntitiesMP/EnemyRunInto) + entity(EntitiesMP/EnemySpawner) + entity(EntitiesMP/EnvironmentBase) + entity(EntitiesMP/EnvironmentMarker) + entity(EntitiesMP/EnvironmentParticlesHolder) + entity(EntitiesMP/Eruptor) + entity(EntitiesMP/ExotechLarva) + entity(EntitiesMP/ExotechLarvaBattery) + entity(EntitiesMP/ExotechLarvaCharger) + entity(EntitiesMP/Eyeman) + entity(EntitiesMP/Fireworks) + entity(EntitiesMP/Fish) + entity(EntitiesMP/Flame) + entity(EntitiesMP/FogMarker) + entity(EntitiesMP/Gizmo) + entity(EntitiesMP/Global) + entity(EntitiesMP/GradientMarker) + entity(EntitiesMP/GravityMarker) + entity(EntitiesMP/GravityRouter) + entity(EntitiesMP/Grunt) + entity(EntitiesMP/GruntSka) + entity(EntitiesMP/Guffy) + entity(EntitiesMP/HazeMarker) + entity(EntitiesMP/Headman) + entity(EntitiesMP/HealthItem) + entity(EntitiesMP/HudPicHolder) + entity(EntitiesMP/Item) + entity(EntitiesMP/KeyItem) + entity(EntitiesMP/LarvaOffspring) + entity(EntitiesMP/Light) + entity(EntitiesMP/Lightning) + entity(EntitiesMP/Marker) + entity(EntitiesMP/MessageHolder) + entity(EntitiesMP/MessageItem) + entity(EntitiesMP/MeteorShower) + entity(EntitiesMP/MirrorMarker) + entity(EntitiesMP/ModelDestruction) + entity(EntitiesMP/ModelHolder) + entity(EntitiesMP/ModelHolder2) + entity(EntitiesMP/ModelHolder3) + entity(EntitiesMP/MovingBrush) + entity(EntitiesMP/MovingBrushMarker) + entity(EntitiesMP/MusicChanger) + entity(EntitiesMP/MusicHolder) + entity(EntitiesMP/NavigationMarker) + entity(EntitiesMP/ParticlesHolder) + entity(EntitiesMP/Pendulum) + entity(EntitiesMP/PhotoAlbum) + entity(EntitiesMP/Pipebomb) + entity(EntitiesMP/Player) + entity(EntitiesMP/PlayerActionMarker) + entity(EntitiesMP/PlayerAnimator) + entity(EntitiesMP/PlayerMarker) + entity(EntitiesMP/PlayerView) + entity(EntitiesMP/PlayerWeapons) + entity(EntitiesMP/PlayerWeaponsEffects) + entity(EntitiesMP/PowerUpItem) + entity(EntitiesMP/Projectile) + entity(EntitiesMP/PyramidSpaceShip) + entity(EntitiesMP/PyramidSpaceShipMarker) + entity(EntitiesMP/Reminder) + entity(EntitiesMP/RollingStone) + entity(EntitiesMP/Santa) + entity(EntitiesMP/Scorpman) + entity(EntitiesMP/ScrollHolder) + entity(EntitiesMP/SeriousBomb) + entity(EntitiesMP/Ship) + entity(EntitiesMP/ShipMarker) + entity(EntitiesMP/Shooter) + entity(EntitiesMP/SoundHolder) + entity(EntitiesMP/SpawnerProjectile) + entity(EntitiesMP/Spinner) + entity(EntitiesMP/StormController) + entity(EntitiesMP/Summoner) + entity(EntitiesMP/SummonerMarker) + entity(EntitiesMP/Switch) + entity(EntitiesMP/TacticsChanger) + entity(EntitiesMP/TacticsHolder) + entity(EntitiesMP/Teleport) + entity(EntitiesMP/Terrain) + entity(EntitiesMP/TextFXHolder) + entity(EntitiesMP/TimeController) + entity(EntitiesMP/TouchField) + entity(EntitiesMP/Trigger) + entity(EntitiesMP/Twister) + entity(EntitiesMP/VoiceHolder) + entity(EntitiesMP/Walker) + entity(EntitiesMP/WatchPlayers) + entity(EntitiesMP/Watcher) + entity(EntitiesMP/Water) + entity(EntitiesMP/WeaponItem) + entity(EntitiesMP/Werebull) + entity(EntitiesMP/Woman) + entity(EntitiesMP/WorldBase) + entity(EntitiesMP/WorldLink) + entity(EntitiesMP/WorldSettingsController) +endif() add_custom_target(ParseEntities DEPENDS ${ENTITIES_H}) -set(ENTITIESMPLIB "EntitiesMP${DEBUGSUFFIX}") -add_library(${ENTITIESMPLIB} SHARED - ${ENTITIES_CPP} - EntitiesMP/Common/Common.cpp - EntitiesMP/Common/Particles.cpp - EntitiesMP/Common/EmanatingParticles.cpp - EntitiesMP/Common/PathFinding.cpp - EntitiesMP/Common/HUD.cpp -) +set(ENTITIESMPLIB "Entities${MP}${DEBUGSUFFIX}") +if(TFE) + add_library(${ENTITIESMPLIB} SHARED + ${ENTITIES_CPP} + Entities/Common/Common.cpp + Entities/Common/Debris.cpp + Entities/Common/Particles.cpp + Entities/Common/Stats.cpp + Entities/Common/PathFinding.cpp + Entities/Common/HUD.cpp + ) +else() + add_library(${ENTITIESMPLIB} SHARED + ${ENTITIES_CPP} + EntitiesMP/Common/Common.cpp + EntitiesMP/Common/Particles.cpp + EntitiesMP/Common/EmanatingParticles.cpp + EntitiesMP/Common/PathFinding.cpp + EntitiesMP/Common/HUD.cpp + ) +endif() + if(MACOSX) target_link_libraries(${ENTITIESMPLIB} "-undefined dynamic_lookup") endif() add_dependencies(${ENTITIESMPLIB} ParseEntities) -set(GAMEMPLIB "GameMP${DEBUGSUFFIX}") +set(GAMEMPLIB "Game${MP}${DEBUGSUFFIX}") add_library(${GAMEMPLIB} SHARED GameMP/Camera.cpp GameMP/CompMessage.cpp @@ -666,5 +812,9 @@ if(LINUX) endif() endif() +if(TFE) + set_target_properties(ssam PROPERTIES OUTPUT_NAME "ssam-tfe") +endif() + # end of CMakeLists.txt ... diff --git a/Sources/Entities/Acid.es b/Sources/Entities/Acid.es new file mode 100644 index 0000000..c9b0f31 --- /dev/null +++ b/Sources/Entities/Acid.es @@ -0,0 +1,70 @@ +509 +%{ +#include "Entities/StdH/StdH.h" +%} + +// input parameter for acid +event EAcid { + CEntityPointer penOwner, // entity which owns it + CEntityPointer penTarget, // target entity which receive damage +}; + + +class CAcid : CMovableModelEntity { +name "Acid"; +thumbnail ""; + +properties: + 1 CEntityPointer m_penOwner, // entity which owns it + 2 CEntityPointer m_penTarget, // target entity which receive damage + 5 BOOL m_bLoop = FALSE, // internal for loops + +components: +functions: +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> MAIN + Main(EAcid ea) { + // attach to parent (another entity) + ASSERT(ea.penOwner!=NULL); + ASSERT(ea.penTarget!=NULL); + m_penOwner = ea.penOwner; + m_penTarget = ea.penTarget; + + // initialization + InitAsVoid(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // acid damage + SpawnReminder(this, 10.0f, 0); + m_bLoop = TRUE; + while(m_bLoop) { + wait(0.25f) { + // damage to parent + on (EBegin) : { + // inflict damage to parent + if (m_penTarget!=NULL && !(m_penTarget->GetFlags()&ENF_DELETED)) { + m_penTarget->InflictDirectDamage(m_penTarget, m_penOwner, DMT_ACID, 0.25f, FLOAT3D(0, 0, 0), FLOAT3D(0, 0, 0)); + // stop existing + } else { + m_bLoop = FALSE; + stop; + } + resume; + } + on (ETimer) : { stop; } + on (EReminder) : { + m_bLoop = FALSE; + stop; + } + } + } + + // cease to exist + Destroy(); + return; + } +}; diff --git a/Sources/Entities/AirWave.es b/Sources/Entities/AirWave.es new file mode 100644 index 0000000..dbfbd46 --- /dev/null +++ b/Sources/Entities/AirWave.es @@ -0,0 +1,151 @@ +510 +%{ +#include "Entities/StdH/StdH.h" + +#define ECF_AIRWAVE ( \ + ((ECBI_BRUSH|ECBI_MODEL|ECBI_CORPSE|ECBI_ITEM|ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID)< do not use + 10 FLOAT m_fDamageAmount = 0.0f, // water hit damage + 11 FLOAT m_fIgnoreTime = 0.0f, // time when laucher will be ignored + 12 FLOAT m_fStartTime = 0.0f, // projectile start time + +components: +// ********* WATER ********* + 10 model MODEL_AIRWAVE "Models\\Enemies\\Mamut\\Projectile\\MamutProjectile.mdl", + 11 texture TEXTURE_AIRWAVE "Models\\Enemies\\Mamut\\Projectile\\MamutProjectile.tex", + +functions: + void PreMoving(void) { + // stretch model (1-9) + FLOAT3D vRatio = FLOAT3D(1, 1, 1); + vRatio *= 8*((_pTimer->CurrentTick()-m_fStartTime)/SLIDE_TIME)+1; + GetModelObject()->StretchModel(vRatio); + ModelChangeNotify(); + + CMovableModelEntity::PreMoving(); + }; + + + +/************************************************************ + * FADE OUT * + ************************************************************/ + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) { + FLOAT fTimeRemain = m_fStartTime + SLIDE_TIME - _pTimer->CurrentTick(); + if (fTimeRemain < 0.0f) { fTimeRemain = 0.0f; } + COLOR colAlpha = GetModelObject()->mo_colBlendColor; + colAlpha = (colAlpha&0xffffff00) + (COLOR(fTimeRemain/SLIDE_TIME*0xff)&0xff); + GetModelObject()->mo_colBlendColor = colAlpha; + + return CMovableModelEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + }; + + + +/************************************************************ + * ATTACK SPECIFIC * + ************************************************************/ + // air wave touch his valid target + void AirWaveTouch(CEntityPointer penHit) { + // time passed + FLOAT fTimeDiff = _pTimer->CurrentTick() - m_fStartTime; + FLOAT fRatio = (SLIDE_TIME - fTimeDiff) / 5.0f; + + // direct damage + FLOAT3D vDirection; + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, vDirection); + InflictDirectDamage(penHit, m_penLauncher, DMT_PROJECTILE, 2.0f * fRatio, + GetPlacement().pl_PositionVector, vDirection); + // push target away + FLOAT3D vSpeed; + GetPitchDirection(90.0f, vSpeed); + vSpeed = vSpeed * 10.0f * fRatio; + KickEntity(penHit, vSpeed); + }; + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> PROJECTILE SLIDE ON BRUSH + AirWaveSlide(EVoid) { + m_fStartTime = _pTimer->CurrentTick(); + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + // fly loop + wait(SLIDE_TIME) { + on (EBegin) : { resume; } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + if (bHit) { + AirWaveTouch(epass.penOther); + } + resume; + } + on (ETouch etouch) : { + // clear time limit for launcher + m_fIgnoreTime = 0.0f; + // air wave is moving to slow (stuck somewhere) -> kill it + if (en_vCurrentTranslationAbsolute.Length() < 0.25f*en_vDesiredTranslationRelative.Length()) { + stop; + } + resume; + } + on (EDeath) : { stop; } + on (ETimer) : { stop; } + } + return EEnd(); + }; + + + // --->>> MAIN + Main(EAirWave eaw) { + // remember the initial parameters + ASSERT(eaw.penLauncher!=NULL); + m_penLauncher = eaw.penLauncher; + + // initialization + InitAsModel(); + SetPhysicsFlags(EPF_AIRWAVE); + SetCollisionFlags(ECF_AIRWAVE); + SetModel(MODEL_AIRWAVE); + SetModelMainTexture(TEXTURE_AIRWAVE); + + // remember lauching time + m_fIgnoreTime = _pTimer->CurrentTick() + 1.0f; + + // slide + autocall AirWaveSlide() EEnd; + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/AmmoItem.es b/Sources/Entities/AmmoItem.es new file mode 100644 index 0000000..b05369e --- /dev/null +++ b/Sources/Entities/AmmoItem.es @@ -0,0 +1,391 @@ +803 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +#include "Models/Items/Ammo/Shells/Shells.h" +#include "Models/Items/Ammo/Bullets/Bullets.h" +#include "Models/Items/Ammo/Rockets/Rockets.h" +#include "Models/Weapons/RocketLauncher/Projectile/Rocket.h" +#include "Models/Items/Ammo/Grenades/Grenades.h" +#include "Models/Items/Ammo/Electricity/Electricity.h" +#include "Models/Items/Ammo/Cannonball/CannonBall.h" +#include "Models/Items/Ammo/Cannonball/CannonBallQuad.h" +%} + +uses "Entities/Item"; + +// ammo type +enum AmmoItemType { + 1 AIT_SHELLS "Shells", + 2 AIT_BULLETS "Bullets", + 3 AIT_ROCKETS "Rockets", + 4 AIT_GRENADES "Grenades", + 5 AIT_ELECTRICITY "Electricity", + 6 AIT_NUKEBALL "obsolete", + 7 AIT_IRONBALLS "IronBalls", + 8 AIT_SERIOUSPACK "SeriousPack - don't use", + 9 AIT_BACKPACK "BackPack - don't use", + 10 AIT_NAPALM "obsolete", +}; + +// event for sending through receive item +event EAmmoItem { + enum AmmoItemType EaitType, // ammo type + INDEX iQuantity, // ammo quantity +}; + +class CAmmoItem : CItem { +name "Ammo Item"; +thumbnail "Thumbnails\\AmmoItem.tbn"; + +properties: + 1 enum AmmoItemType m_EaitType "Type" 'Y' = AIT_SHELLS, // health type + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + +// ********* SHELLS ********* + 1 model MODEL_SHELLS "Models\\Items\\Ammo\\Shells\\Shells.mdl", + 2 texture TEXTURE_SHELLS "Models\\Items\\Ammo\\Shells\\Shells.tex", + +// ********* BULLETS ********* + 10 model MODEL_BULLETS "Models\\Items\\Ammo\\Bullets\\Bullets.mdl", + 11 texture TEXTURE_BULLETS "Models\\Items\\Ammo\\Bullets\\Bullets.tex", + +// ********* ROCKETS ********* + 20 model MODEL_ROCKETS "Models\\Items\\Ammo\\Rockets\\Rockets.mdl", + 21 model MODEL_RC_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.mdl", + 22 texture TEXTURE_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.tex", + +// ********* GRENADES ********* + 30 model MODEL_GRENADES "Models\\Items\\Ammo\\Grenades\\Grenades.mdl", + 31 model MODEL_GR_GRENADE "Models\\Items\\Ammo\\Grenades\\Grenade.mdl", + 32 texture TEXTURE_GRENADES "Models\\Items\\Ammo\\Grenades\\Grenades.tex", + 33 texture TEXTURE_GR_GRENADE "Models\\Weapons\\GrenadeLauncher\\Grenade\\Grenade.tex", + +// ********* ELECTRICITY ********* + 40 model MODEL_ELECTRICITY "Models\\Items\\Ammo\\Electricity\\Electricity.mdl", + 41 model MODEL_EL_EFFECT "Models\\Items\\Ammo\\Electricity\\Effect.mdl", + 42 model MODEL_EL_EFFECT2 "Models\\Items\\Ammo\\Electricity\\Effect2.mdl", + 43 texture TEXTURE_ELECTRICITY "Models\\Items\\Ammo\\Electricity\\Electricity.tex", + 44 texture TEXTURE_EL_EFFECT "Models\\Items\\Ammo\\Electricity\\Effect.tex", + +// ********* CANNON BALLS ********* + 50 model MODEL_CANNONBALL "Models\\Items\\Ammo\\Cannonball\\Cannonball.mdl", + 51 model MODEL_CANNONBALLS "Models\\Items\\Ammo\\Cannonball\\CannonballQuad.mdl", + 52 texture TEXTURE_IRONBALL "Models\\Weapons\\Cannon\\Projectile\\IronBall.tex", +// 53 texture TEXTURE_NUKEBALL "Models\\Weapons\\Cannon\\Projectile\\NukeBall.tex", + +// ********* BACK PACK ********* + 60 model MODEL_BACKPACK "Models\\Items\\PowerUps\\BackPack\\BackPack.mdl", + 61 texture TEXTURE_BACKPACK "Models\\Items\\PowerUps\\BackPack\\BackPack.tex", + +// ********* SERIOUS PACK ********* + 70 model MODEL_SERIOUSPACK "Models\\Items\\PowerUps\\SeriousPack\\SeriousPack.mdl", + 71 texture TEXTURE_SERIOUSPACK "Models\\Items\\PowerUps\\SeriousPack\\SeriousPack.tex", + +/* +// ********* FUEL RESERVOIR ********* + 80 model MODEL_FL_RESERVOIR "Models\\Items\\Ammo\\Napalm\\Napalm.mdl", + 81 texture TEXTURE_FL_FUELRESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.tex", + */ + +// ************** FLARE FOR EFFECT ************** +100 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", +101 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", + +// ************** REFLECTIONS ************** +200 texture TEX_REFL_BWRIPLES01 "Models\\ReflectionTextures\\BWRiples01.tex", +201 texture TEX_REFL_BWRIPLES02 "Models\\ReflectionTextures\\BWRiples02.tex", +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", +203 texture TEX_REFL_LIGHTBLUEMETAL01 "Models\\ReflectionTextures\\LightBlueMetal01.tex", +204 texture TEX_REFL_DARKMETAL "Models\\ReflectionTextures\\DarkMetal.tex", +205 texture TEX_REFL_PURPLE01 "Models\\ReflectionTextures\\Purple01.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + +// ************** SOUNDS ************** +213 sound SOUND_PICK "Sounds\\Items\\Ammo.wav", +214 sound SOUND_DEFAULT "Sounds\\Default.wav", + +functions: + void Precache(void) { + PrecacheSound(SOUND_PICK); + } + + // render particles + void RenderParticles(void) { + // no particles when not existing or in DM modes + if (GetRenderType()!=CEntity::RT_MODEL || GetSP()->sp_gmGameMode>CSessionProperties::GM_COOPERATIVE + || !ShowItemParticles()) + { + return; + } + switch (m_EaitType) { + case AIT_SHELLS: + Particles_Spiral(this, 1.0f*0.75, 1.0f*0.75, PT_STAR04, 4); + break; + case AIT_BULLETS: + Particles_Spiral(this, 1.5f*0.75, 1.0f*0.75, PT_STAR04, 6); + break; + case AIT_ROCKETS: + Particles_Spiral(this, 1.5f*0.75, 1.25f*0.75, PT_STAR04, 6); + break; + case AIT_GRENADES: + Particles_Spiral(this, 2.0f*0.75, 1.25f*0.75, PT_STAR04, 6); + break; + case AIT_ELECTRICITY: + Particles_Spiral(this, 1.5f*0.75, 1.125f*0.75, PT_STAR04, 6); + break; + case AIT_NUKEBALL: + Particles_Spiral(this, 1.25f*0.75, 1.0f*0.75, PT_STAR04, 4); + break; + case AIT_IRONBALLS: + Particles_Spiral(this, 2.0f*0.75, 1.25f*0.75, PT_STAR04, 8); + break; + case AIT_BACKPACK: + Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + break; + case AIT_SERIOUSPACK: + Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + break; + case AIT_NAPALM: + Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + break; + } + } + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_ctCount = 1; + pes->es_ctAmmount = m_fValue; + switch (m_EaitType) { + case AIT_SHELLS: + pes->es_strName = "Shells"; + pes->es_fValue = m_fValue*AV_SHELLS; + break; + case AIT_BULLETS: + pes->es_strName = "Bullets"; + pes->es_fValue = m_fValue*AV_BULLETS; + break; + case AIT_ROCKETS: + pes->es_strName = "Rockets"; + pes->es_fValue = m_fValue*AV_ROCKETS; + break; + case AIT_GRENADES: + pes->es_strName = "Grenades"; + pes->es_fValue = m_fValue*AV_GRENADES; + break; + case AIT_ELECTRICITY: + pes->es_strName = "Electricity"; + pes->es_fValue = m_fValue*AV_ELECTRICITY; + break; +/* + case AIT_NUKEBALL: + pes->es_strName = "Nukeballs"; + pes->es_fValue = m_fValue*AV_NUKEBALLS; + break; + */ + case AIT_IRONBALLS: + pes->es_strName = "Ironballs"; + pes->es_fValue = m_fValue*AV_IRONBALLS; + break; + case AIT_SERIOUSPACK: + pes->es_strName = "SeriousPack"; + pes->es_fValue = m_fValue*100000; + break; + case AIT_BACKPACK: + pes->es_strName = "BackPack"; + pes->es_fValue = m_fValue*100000; + break; +/* + case AIT_NAPALM: + pes->es_strName = "Napalm"; + pes->es_fValue = m_fValue*AV_NAPALM; + break; + */ + } + pes->es_iScore = 0;//m_iScore; + return TRUE; + } + + // set ammo properties depending on ammo type + void SetProperties(void) { + switch (m_EaitType) { + case AIT_SHELLS: + m_fValue = 10.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Shells: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_SHELLS, TEXTURE_SHELLS, 0, 0, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.25f,0), FLOAT3D(1.5,1.5,0.75f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; + case AIT_BULLETS: + m_fValue = 50.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Bullets: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_BULLETS, TEXTURE_BULLETS, 0, 0, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(3,3,1.0f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; + case AIT_ROCKETS: + m_fValue = 5.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Rockets: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_ROCKETS, TEXTURE_ROCKET, 0, 0, 0); + AddItemAttachment(ROCKETS_ATTACHMENT_ROCKET1, MODEL_RC_ROCKET, TEXTURE_ROCKET, 0, 0, 0); + AddItemAttachment(ROCKETS_ATTACHMENT_ROCKET2, MODEL_RC_ROCKET, TEXTURE_ROCKET, 0, 0, 0); + AddItemAttachment(ROCKETS_ATTACHMENT_ROCKET3, MODEL_RC_ROCKET, TEXTURE_ROCKET, 0, 0, 0); + AddItemAttachment(ROCKETS_ATTACHMENT_ROCKET4, MODEL_RC_ROCKET, TEXTURE_ROCKET, 0, 0, 0); + AddItemAttachment(ROCKETS_ATTACHMENT_ROCKET5, MODEL_RC_ROCKET, TEXTURE_ROCKET, 0, 0, 0); + SetItemAttachmentAnim(ROCKETS_ATTACHMENT_ROCKET1, ROCKET_ANIM_FORAMMO); + SetItemAttachmentAnim(ROCKETS_ATTACHMENT_ROCKET2, ROCKET_ANIM_FORAMMO); + SetItemAttachmentAnim(ROCKETS_ATTACHMENT_ROCKET3, ROCKET_ANIM_FORAMMO); + SetItemAttachmentAnim(ROCKETS_ATTACHMENT_ROCKET4, ROCKET_ANIM_FORAMMO); + SetItemAttachmentAnim(ROCKETS_ATTACHMENT_ROCKET5, ROCKET_ANIM_FORAMMO); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(2,2,0.75f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; + case AIT_GRENADES: + m_fValue = 5.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Grenades: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_GRENADES, TEXTURE_GRENADES, 0, 0, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(4,4,1.0f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; + case AIT_ELECTRICITY: + m_fValue = 50.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Electricity: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_ELECTRICITY, TEXTURE_ELECTRICITY, TEXTURE_EL_EFFECT, TEXTURE_EL_EFFECT, 0); + AddItemAttachment(ELECTRICITY_ATTACHMENT_EFFECT1, MODEL_EL_EFFECT, TEXTURE_EL_EFFECT, 0, 0, 0); + AddItemAttachment(ELECTRICITY_ATTACHMENT_EFFECT2, MODEL_EL_EFFECT, TEXTURE_EL_EFFECT, 0, 0, 0); + AddItemAttachment(ELECTRICITY_ATTACHMENT_EFFECT3, MODEL_EL_EFFECT2,TEXTURE_EL_EFFECT, 0, 0, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(3,3,0.8f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; +/* + case AIT_NUKEBALL: + m_fValue = 1.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Nuke ball: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_CANNONBALL, TEXTURE_NUKEBALL, TEX_REFL_BWRIPLES01, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.5f,0), FLOAT3D(2,2,0.5f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; + */ + case AIT_IRONBALLS: + m_fValue = 4.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Iron balls: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_CANNONBALLS, TEXTURE_IRONBALL, TEX_REFL_DARKMETAL, TEX_SPEC_WEAK, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(5,5,1.3f) ); + StretchItem(FLOAT3D(0.75f, 0.75f, 0.75f)); + break; +/* + case AIT_NAPALM: + m_fValue = 100.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Napalm: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_FL_RESERVOIR, TEXTURE_FL_FUELRESERVOIR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(3,3,1.0f) ); + StretchItem(FLOAT3D(1.25f, 1.25f, 1.25f)); + break; + */ + case AIT_SERIOUSPACK: + m_fValue = 1.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("SeriousPack: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_SERIOUSPACK, TEXTURE_SERIOUSPACK, 0,0,0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(2,2,1.3f) ); + StretchItem(FLOAT3D(0.5f, 0.5f, 0.5f)); + break; + case AIT_BACKPACK: + m_fValue = 1.0f; + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("BackPack: %d", (int) m_fValue); + // set appearance + AddItem(MODEL_BACKPACK, TEXTURE_BACKPACK, 0,0,0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(2,2,1.3f) ); + StretchItem(FLOAT3D(0.5f, 0.5f, 0.5f)); + break; + default: ASSERTALWAYS("Uknown ammo"); + } + }; + + void AdjustDifficulty(void) + { + m_fValue = ceil(m_fValue*GetSP()->sp_fAmmoQuantity); + + if (GetSP()->sp_bInfiniteAmmo && m_penTarget==NULL) { + Destroy(); + } + } + +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected { + ASSERT(epass.penOther!=NULL); + + // if ammo stays + if (GetSP()->sp_bAmmoStays && !m_bPickupOnce) { + // if already picked by this player + BOOL bWasPicked = MarkPickedBy(epass.penOther); + if (bWasPicked) { + // don't pick again + return; + } + } + + // send ammo to entity + EAmmoItem eAmmo; + eAmmo.EaitType = m_EaitType; + eAmmo.iQuantity = (INDEX) m_fValue; + // if health is received + if (epass.penOther->ReceiveItem(eAmmo)) { + // play the pickup sound + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + if(_pNetwork->IsPlayerLocal(epass.penOther)) {IFeel_PlayEffect("PU_Ammo");} + if( (m_EaitType == AIT_SERIOUSPACK) || (m_EaitType == AIT_BACKPACK) ) + { + PlaySound(m_soPick, SOUND_DEFAULT, SOF_3D); + CPrintF("^cFF0000^f5Warning!!! Replace old serious pack with new, BackPack entity!^r\n"); + } + else + { + PlaySound(m_soPick, SOUND_PICK, SOF_3D); + } + m_fPickSoundLen = GetSoundLength(SOUND_PICK); + if (!GetSP()->sp_bAmmoStays || m_bPickupOnce) { + jump CItem::ItemReceived(); + } + } + return; + }; + + Main() { + if (m_EaitType==AIT_NUKEBALL|| + m_EaitType==AIT_NAPALM) { + m_EaitType=AIT_SHELLS; + } + Initialize(); // initialize base class + StartModelAnim(ITEMHOLDER_ANIM_MEDIUMOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + SetProperties(); // set properties + + jump CItem::ItemLoop(); + }; +}; diff --git a/Sources/Entities/AmmoPack.es b/Sources/Entities/AmmoPack.es new file mode 100644 index 0000000..59170b1 --- /dev/null +++ b/Sources/Entities/AmmoPack.es @@ -0,0 +1,203 @@ +806 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +%} + +uses "Entities/Item"; + +// ammo type +enum AmmoPackType { + 1 APT_CUSTOM "Custom pack", + 2 APT_SERIOUS "Serious pack", +}; + +// event for sending through receive item +event EAmmoPackItem { + INDEX iShells, + INDEX iBullets, + INDEX iRockets, + INDEX iGrenades, +// INDEX iNapalm, + INDEX iElectricity, + INDEX iIronBalls, +// INDEX iNukeBalls, +}; + +class CAmmoPack : CItem { +name "Ammo Pack"; +thumbnail "Thumbnails\\AmmoPack.tbn"; + +properties: + 1 enum AmmoPackType m_aptPackType "Type" 'Y' = APT_CUSTOM, // pack type + + 10 INDEX m_iShells "Shells" 'S' = MAX_SHELLS, + 11 INDEX m_iBullets "Bullets" 'B' = MAX_BULLETS, + 12 INDEX m_iRockets "Rockets" 'C' = MAX_ROCKETS, + 13 INDEX m_iGrenades "Grenades" 'G' = MAX_GRENADES, +// 14 INDEX m_iNapalm "Napalm" 'P' = MAX_NAPALM, + 15 INDEX m_iElectricity "Electricity" 'E' = MAX_ELECTRICITY, + 16 INDEX m_iIronBalls "Iron balls" 'I' = MAX_IRONBALLS, +// 17 INDEX m_iNukeBalls "Nuke balls" 'U' = MAX_NUKEBALLS, + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + +// ********* BACK PACK ********* + 60 model MODEL_BACKPACK "Models\\Items\\PowerUps\\BackPack\\BackPack.mdl", + 61 texture TEXTURE_BACKPACK "Models\\Items\\PowerUps\\BackPack\\BackPack.tex", + +// ********* SERIOUS PACK ********* + 70 model MODEL_SERIOUSPACK "Models\\Items\\PowerUps\\SeriousPack\\SeriousPack.mdl", + 71 texture TEXTURE_SERIOUSPACK "Models\\Items\\PowerUps\\SeriousPack\\SeriousPack.tex", + +// ************** FLARE FOR EFFECT ************** +100 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", +101 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", + +// ************** SOUNDS ************** +213 sound SOUND_PICK "Sounds\\Items\\Ammo.wav", + +functions: + void Precache(void) { + PrecacheSound(SOUND_PICK); + } + + // render particles + void RenderParticles(void) + { + // no particles when not existing or in DM modes + if (GetRenderType()!=CEntity::RT_MODEL || GetSP()->sp_gmGameMode>CSessionProperties::GM_COOPERATIVE + || !ShowItemParticles()) + { + return; + } + + Particles_Spiral(this, 3.0f*0.5, 2.5f*0.5, PT_STAR04, 10); + } + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_ctCount = 1; + pes->es_ctAmmount = 1; + // compile description +// pes->es_strName.PrintF("Back pack: %d Shells, %d Bullets, %d Rockets, %d Grenades, %d Napalm, %d Electricity, %d Iron balls, %d Nuke balls", +// m_iShells, m_iBullets, m_iRockets, m_iGrenades, m_iNapalm, m_iElectricity, m_iIronBalls, m_iNukeBalls); + pes->es_strName.PrintF("Back pack: %d Shells, %d Bullets, %d Rockets, %d Grenades, %d Electricity, %d Iron balls", + m_iShells, m_iBullets, m_iRockets, m_iGrenades, m_iElectricity, m_iIronBalls); + + // calculate value + pes->es_fValue = + m_iShells*AV_SHELLS + + m_iBullets*AV_BULLETS + + m_iRockets*AV_ROCKETS + + m_iGrenades*AV_GRENADES + +// m_iNapalm*AV_NAPALM + + m_iElectricity*AV_ELECTRICITY + + m_iIronBalls*AV_IRONBALLS /*+ + m_iNukeBalls*AV_NUKEBALLS*/; + + pes->es_iScore = 0; + return TRUE; + } + + // set ammo properties depending on ammo type + void SetProperties(void) + { + switch (m_aptPackType) + { + case APT_SERIOUS: + m_strDescription = "Serious:"; + // set appearance + AddItem(MODEL_SERIOUSPACK, TEXTURE_SERIOUSPACK, 0,0,0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(2,2,1.3f) ); + StretchItem(FLOAT3D(0.5f, 0.5f, 0.5f)); + break; + case APT_CUSTOM: + m_strDescription = "Custom:"; + // set appearance + AddItem(MODEL_BACKPACK, TEXTURE_BACKPACK, 0,0,0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(2,2,1.3f) ); + StretchItem(FLOAT3D(0.5f, 0.5f, 0.5f)); + break; + default: ASSERTALWAYS("Uknown ammo"); + } + + m_fValue = 1.0f; + m_fRespawnTime = 30.0f; + if( m_iShells != 0) {m_strDescription.PrintF("%s: Shells (%d)", (const char *) m_strDescription, m_iShells);} + if( m_iBullets != 0) {m_strDescription.PrintF("%s: Bullets (%d)", (const char *) m_strDescription, m_iBullets);} + if( m_iRockets != 0) {m_strDescription.PrintF("%s: Rockets (%d)", (const char *) m_strDescription, m_iRockets);} + if( m_iGrenades != 0) {m_strDescription.PrintF("%s: Grenades (%d)", (const char *) m_strDescription, m_iGrenades);} +// if( m_iNapalm != 0) {m_strDescription.PrintF("%s: Napalm (%d)", (const char *) m_strDescription, m_iNapalm);} + if( m_iElectricity != 0) {m_strDescription.PrintF("%s: Electricity (%d)", (const char *) m_strDescription, m_iElectricity);} + if( m_iIronBalls != 0) {m_strDescription.PrintF("%s: Iron balls (%d)", (const char *) m_strDescription, m_iIronBalls);} +// if( m_iNukeBalls != 0) {m_strDescription.PrintF("%s: Nuke balls (%d)", (const char *) m_strDescription, m_iNukeBalls);} + } + + void AdjustDifficulty(void) + { + //m_fValue = ceil(m_fValue*GetSP()->sp_fAmmoQuantity); + + if (GetSP()->sp_bInfiniteAmmo && m_penTarget==NULL) { + Destroy(); + } + } + +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected + { + ASSERT(epass.penOther!=NULL); + + // if ammo stays + if (GetSP()->sp_bAmmoStays && !m_bPickupOnce) { + // if already picked by this player + BOOL bWasPicked = MarkPickedBy(epass.penOther); + if (bWasPicked) { + // don't pick again + return; + } + } + + // send ammo to entity + EAmmoPackItem eAmmo; + eAmmo.iShells = m_iShells; + eAmmo.iBullets = m_iBullets; + eAmmo.iRockets = m_iRockets; + eAmmo.iGrenades = m_iGrenades; +// eAmmo.iNapalm = m_iNapalm; + eAmmo.iElectricity = m_iElectricity; + eAmmo.iIronBalls = m_iIronBalls; +// eAmmo.iNukeBalls = m_iNukeBalls; + // if health is received + if (epass.penOther->ReceiveItem(eAmmo)) { + // play the pickup sound + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soPick, SOUND_PICK, SOF_3D); + m_fPickSoundLen = GetSoundLength(SOUND_PICK); + if (!GetSP()->sp_bAmmoStays || m_bPickupOnce) { + jump CItem::ItemReceived(); + } + } + return; + }; + + Main() { + m_iShells = Clamp( m_iShells, INDEX(0), MAX_SHELLS); + m_iBullets = Clamp( m_iBullets, INDEX(0), MAX_BULLETS); + m_iRockets = Clamp( m_iRockets, INDEX(0), MAX_ROCKETS); + m_iGrenades = Clamp( m_iGrenades, INDEX(0), MAX_GRENADES); +// m_iNapalm = Clamp( m_iNapalm, INDEX(0), MAX_NAPALM); + m_iElectricity = Clamp( m_iElectricity, INDEX(0), MAX_ELECTRICITY); + m_iIronBalls = Clamp( m_iIronBalls, INDEX(0), MAX_IRONBALLS); +// m_iNukeBalls = Clamp( m_iNukeBalls, INDEX(0), MAX_NUKEBALLS); + + Initialize(); // initialize base class + StartModelAnim(ITEMHOLDER_ANIM_MEDIUMOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + SetProperties(); // set properties + + jump CItem::ItemLoop(); + }; +}; diff --git a/Sources/Entities/AnimationChanger.es b/Sources/Entities/AnimationChanger.es new file mode 100644 index 0000000..bfa99ea --- /dev/null +++ b/Sources/Entities/AnimationChanger.es @@ -0,0 +1,146 @@ +218 +%{ +#include "Entities/StdH/StdH.h" +#include +%} + +uses "Entities/ModelHolder2"; +uses "Entities/Light"; + +// event sent to the entity that should change animation +event EChangeAnim { + INDEX iModelAnim, + BOOL bModelLoop, + INDEX iTextureAnim, + BOOL bTextureLoop, + INDEX iLightAnim, + INDEX iAmbientLightAnim, + BOOL bLightLoop, + BOOL bAmbientLightLoop, + COLOR colAmbient, + COLOR colDiffuse, +}; + +class CAnimationChanger : CRationalEntity { +name "AnimationChanger"; +thumbnail "Thumbnails\\AnimationChanger.tbn"; +features "HasName", "HasTarget", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Animation changer", + 2 CTString m_strDescription = "", + 3 CEntityPointer m_penTarget "Target" 'T' COLOR(C_GREEN|0xFF), + 4 ANIMATION m_iModelAnim "Model Animation" 'M' = 0, + 5 BOOL m_bModelLoop "Model Looping" = FALSE, + 6 ANIMATION m_iTextureAnim "Texture Animation" 'X' = 0, + 7 BOOL m_bTextureLoop "Texture Looping" = FALSE, + 8 ANIMATION m_iLightAnim "Diffuse Light Animation" 'L' = 0, + 9 BOOL m_bLightLoop "Diffuse Light Looping" = FALSE, + 10 ANIMATION m_iAmbientLightAnim "Ambient Light Animation" 'B' = 0, + 11 BOOL m_bAmbientLightLoop "Ambient Light Looping" = FALSE, + 12 COLOR m_colAmbient "Ambient Light Color" 'A' = C_dBLUE, + 13 COLOR m_colDiffuse "Diffuse Light Color" 'C' = C_GRAY, + +components: + 1 model MODEL_CHANGER "Models\\Editor\\AnimationChanger.mdl", + 2 texture TEXTURE_CHANGER "Models\\Editor\\AnimationChanger.tex" + +functions: + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s",(const char *) m_penTarget->GetName()); + } + return m_strDescription; + } + + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + CEntity *penTarget = m_penTarget; + + if (penTarget==NULL) { + return NULL; + } + + if (IsOfClass(penTarget, "AnimationHub")) { + penTarget = ((CAnimationHub*)penTarget)->m_penTarget0; + } + + if (penTarget==NULL) { + return NULL; + } + + // if modelholder + if (IsOfClass(penTarget, "ModelHolder2")) { + CModelHolder2 *penModel = (CModelHolder2*)&*penTarget; + if (slPropertyOffset==offsetof(CAnimationChanger, m_iModelAnim)) { + return penModel->GetModelObject()->GetData(); + } else if (slPropertyOffset==offsetof(CAnimationChanger, m_iTextureAnim)) { + return penModel->GetModelObject()->mo_toTexture.GetData(); + } else if (slPropertyOffset==offsetof(CAnimationChanger, m_iLightAnim)) { + return penModel->m_aoLightAnimation.GetData(); + } + + // if light + } else if (IsOfClass(penTarget, "Light")) { + CLight *penLight = (CLight*)&*penTarget; + + if (slPropertyOffset==offsetof(CAnimationChanger, m_iLightAnim)) + { + return penLight->m_aoLightAnimation.GetData(); + } + else if (slPropertyOffset==offsetof(CAnimationChanger, m_iAmbientLightAnim)) + { + return penLight->m_aoAmbientLightAnimation.GetData(); + } + } + + return CEntity::GetAnimData(slPropertyOffset); + }; + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_CHANGER); + SetModelMainTexture(TEXTURE_CHANGER); + + // check target type + if (m_penTarget!=NULL && + !IsOfClass(m_penTarget, "AnimationHub") && + !IsOfClass(m_penTarget, "ModelHolder2") && + !IsOfClass(m_penTarget, "Light")) { + WarningMessage("Target must be AnimationHub ModelHolder2 or Light!"); + m_penTarget=NULL; + } + if (m_penTarget==NULL) { + return; + } + + //main loop + wait() { + on (EBegin) : { resume; } + on (EStart) : { + EChangeAnim eChange; + eChange.iModelAnim =m_iModelAnim ; + eChange.iTextureAnim =m_iTextureAnim; + eChange.iLightAnim =m_iLightAnim ; + eChange.iAmbientLightAnim =m_iAmbientLightAnim; + eChange.bModelLoop =m_bModelLoop ; + eChange.bTextureLoop =m_bTextureLoop; + eChange.bLightLoop =m_bLightLoop ; + eChange.colAmbient =m_colAmbient ; + eChange.colDiffuse =m_colDiffuse ; + m_penTarget->SendEvent(eChange); + resume; + } + } + return; + } +}; + diff --git a/Sources/Entities/AnimationHub.es b/Sources/Entities/AnimationHub.es new file mode 100644 index 0000000..ad945a0 --- /dev/null +++ b/Sources/Entities/AnimationHub.es @@ -0,0 +1,147 @@ +228 +%{ +#include "Entities/StdH/StdH.h" +#include +%} + + +class CAnimationHub : CRationalEntity { +name "AnimationHub"; +thumbnail "Thumbnails\\AnimationHub.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Animation hub", + 2 CTString m_strDescription = "", + + 3 FLOAT m_tmDelayEach "Delay each" 'D' = 0.0f, + + 10 CEntityPointer m_penTarget0 "Target0" 'T' COLOR(C_GREEN|0xFF), + 11 CEntityPointer m_penTarget1 "Target1" COLOR(C_GREEN|0xFF), + 12 CEntityPointer m_penTarget2 "Target2" COLOR(C_GREEN|0xFF), + 13 CEntityPointer m_penTarget3 "Target3" COLOR(C_GREEN|0xFF), + 14 CEntityPointer m_penTarget4 "Target4" COLOR(C_GREEN|0xFF), + 15 CEntityPointer m_penTarget5 "Target5" COLOR(C_GREEN|0xFF), + 16 CEntityPointer m_penTarget6 "Target6" COLOR(C_GREEN|0xFF), + 17 CEntityPointer m_penTarget7 "Target7" COLOR(C_GREEN|0xFF), + 18 CEntityPointer m_penTarget8 "Target8" COLOR(C_GREEN|0xFF), + 19 CEntityPointer m_penTarget9 "Target9" COLOR(C_GREEN|0xFF), + + 20 FLOAT m_tmDelay0 "Delay0" = 0.0f, + 21 FLOAT m_tmDelay1 "Delay1" = 0.0f, + 22 FLOAT m_tmDelay2 "Delay2" = 0.0f, + 23 FLOAT m_tmDelay3 "Delay3" = 0.0f, + 24 FLOAT m_tmDelay4 "Delay4" = 0.0f, + 25 FLOAT m_tmDelay5 "Delay5" = 0.0f, + 26 FLOAT m_tmDelay6 "Delay6" = 0.0f, + 27 FLOAT m_tmDelay7 "Delay7" = 0.0f, + 28 FLOAT m_tmDelay8 "Delay8" = 0.0f, + 29 FLOAT m_tmDelay9 "Delay9" = 0.0f, + + 100 INDEX m_iModelAnim = 0, + 101 BOOL m_bModelLoop = 0, + 102 INDEX m_iTextureAnim = 0, + 103 BOOL m_bTextureLoop = 0, + 104 INDEX m_iLightAnim = 0, + 105 BOOL m_bLightLoop = 0, + 106 COLOR m_colAmbient = 0, + 107 COLOR m_colDiffuse = 0, + + 110 INDEX m_iCounter = 0, + +components: + 1 model MODEL_HUB "Models\\Editor\\AnimationHub.mdl", + 2 texture TEXTURE_HUB "Models\\Editor\\AnimationHub.tex" + +functions: + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget0!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s...",(const char *) m_penTarget0->GetName()); + } + return m_strDescription; + } + +procedures: + RelayEvents() + { + // for each target + m_iCounter=0; + while(m_iCounter<10) { + // get delay + FLOAT fDelay = m_tmDelayEach + (&m_tmDelay0)[m_iCounter]; + // if has delay + if (fDelay>0) { + // wait + autowait(fDelay); + } + + // get the target + CEntity *penTarget = (&m_penTarget0)[m_iCounter]; + // if no more targets + if (penTarget==NULL) { + // stop + jump WaitChange(); + } + // sent event to it + EChangeAnim eca; + eca.iModelAnim = m_iModelAnim ; + eca.bModelLoop = m_bModelLoop ; + eca.iTextureAnim = m_iTextureAnim; + eca.bTextureLoop = m_bTextureLoop; + eca.iLightAnim = m_iLightAnim ; + eca.bLightLoop = m_bLightLoop ; + eca.colAmbient = m_colAmbient ; + eca.colDiffuse = m_colDiffuse ; + penTarget->SendEvent(eca); + + m_iCounter++; + } + + jump WaitChange(); + } + + WaitChange() + { + // wait forever + while(TRUE) { + wait() { + on (EChangeAnim eca) : { + m_iModelAnim = eca.iModelAnim ; + m_bModelLoop = eca.bModelLoop ; + m_iTextureAnim = eca.iTextureAnim; + m_bTextureLoop = eca.bTextureLoop; + m_iLightAnim = eca.iLightAnim ; + m_bLightLoop = eca.bLightLoop ; + m_colAmbient = eca.colAmbient ; + m_colDiffuse = eca.colDiffuse ; + jump RelayEvents(); + } + } + } + } + + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_HUB); + SetModelMainTexture(TEXTURE_HUB); + + // check target types + for (INDEX i=0; i<10; i++) { + CEntityPointer &penTarget = (&m_penTarget0)[i]; + if (penTarget!=NULL && + !IsOfClass(penTarget, "ModelHolder2") && + !IsOfClass(penTarget, "Light")) { + WarningMessage("All targets must be ModelHolder2 or Light!"); + penTarget=NULL; + } + } + jump WaitChange(); + } +}; + diff --git a/Sources/Entities/ArmorItem.es b/Sources/Entities/ArmorItem.es new file mode 100644 index 0000000..bbe05b9 --- /dev/null +++ b/Sources/Entities/ArmorItem.es @@ -0,0 +1,254 @@ +804 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +%} + +uses "Entities/Item"; + +// health type +enum ArmorItemType { + 0 ARIT_SHARD "Shard", // shard + 1 ARIT_SMALL "Small", // small armor + 2 ARIT_MEDIUM "Medium", // medium armor + 3 ARIT_STRONG "Strong", // strong armor + 4 ARIT_SUPER "Super", // super armor +}; + +// event for sending through receive item +event EArmor { + FLOAT fArmor, // armor to receive + BOOL bOverTopArmor, // can be received over top armor +}; + +class CArmorItem : CItem { +name "Armor Item"; +thumbnail "Thumbnails\\ArmorItem.tbn"; + +properties: + 1 enum ArmorItemType m_EaitType "Type" 'Y' = ARIT_SHARD, // armor type + 2 BOOL m_bOverTopArmor = FALSE, // can be received over top armor + 3 INDEX m_iSoundComponent = 0, + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + +// ********* SHARD ********* + 1 model MODEL_1 "Models\\Items\\Armor\\Armor_1.mdl", + 2 texture TEXTURE_1 "Models\\Items\\Armor\\Armor_1.tex", + +// ********* SMALL ARMOR ********* + 10 model MODEL_25 "Models\\Items\\Armor\\Armor_25.mdl", + 11 texture TEXTURE_25 "Models\\Items\\Armor\\Armor_25.tex", + +// ********* MEDIUM ARMOR ********* + 20 model MODEL_50 "Models\\Items\\Armor\\Armor_50.mdl", + 21 texture TEXTURE_50 "Models\\Items\\Armor\\Armor_50.tex", + +// ********* STRONG ARMOR ********* + 22 model MODEL_100 "Models\\Items\\Armor\\Armor_100.mdl", + 23 texture TEXTURE_100 "Models\\Items\\Armor\\Armor_100.tex", + +// ********* SUPER ARMOR ********* + 40 model MODEL_200 "Models\\Items\\Armor\\Armor_200.mdl", + 41 texture TEXTURE_200 "Models\\Items\\Armor\\Armor_200.tex", + +// ************** FLARE FOR EFFECT ************** +100 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", +101 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", + +// ************** REFLECTIONS ************** +200 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", + +// ************** SOUNDS ************** +301 sound SOUND_SHARD "Sounds\\Items\\ArmourShard.wav", +302 sound SOUND_SMALL "Sounds\\Items\\ArmourSmall.wav", +303 sound SOUND_MEDIUM "Sounds\\Items\\ArmourMedium.wav", +304 sound SOUND_STRONG "Sounds\\Items\\ArmourStrong.wav", +305 sound SOUND_SUPER "Sounds\\Items\\ArmourSuper.wav", + +functions: + void Precache(void) { + switch (m_EaitType) { + case ARIT_SHARD: PrecacheSound(SOUND_SHARD ); break; + case ARIT_SMALL: PrecacheSound(SOUND_SMALL ); break; + case ARIT_MEDIUM: PrecacheSound(SOUND_MEDIUM); break; + case ARIT_STRONG: PrecacheSound(SOUND_STRONG); break; + case ARIT_SUPER: PrecacheSound(SOUND_SUPER ); break; + } + } + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = "Armor"; + pes->es_ctCount = 1; + pes->es_ctAmmount = m_fValue; + pes->es_fValue = m_fValue*2; + pes->es_iScore = 0;//m_iScore; + switch (m_EaitType) { + case ARIT_SHARD: pes->es_strName+=" shard"; break; + case ARIT_SMALL: pes->es_strName+=" small";break; + case ARIT_MEDIUM: pes->es_strName+=" medium";break; + case ARIT_STRONG: pes->es_strName+=" strong";break; + case ARIT_SUPER: pes->es_strName+=" super";break; + } + return TRUE; + } + + // render particles + void RenderParticles(void) { + // no particles when not existing or in DM modes + if (GetRenderType()!=CEntity::RT_MODEL || GetSP()->sp_gmGameMode>CSessionProperties::GM_COOPERATIVE + || !ShowItemParticles()) + { + return; + } + switch (m_EaitType) { + case ARIT_SHARD: + Particles_Emanate(this, 0.75f*0.75, 0.75f*0.75, PT_STAR04, 8); + break; + case ARIT_SMALL: + Particles_Emanate(this, 1.0f*0.75, 1.0f*0.75, PT_STAR04, 32); + break; + case ARIT_MEDIUM: + Particles_Emanate(this, 1.5f*0.75, 1.5f*0.75, PT_STAR04, 64); + break; + case ARIT_STRONG: + Particles_Emanate(this, 2.0f*0.75, 1.25f*0.75, PT_STAR04, 96); + break; + case ARIT_SUPER: + Particles_Emanate(this, 2.5f*0.75, 1.5f*0.75, PT_STAR04, 128); + break; + } + } + + // set health properties depending on health type + void SetProperties(void) { + switch (m_EaitType) { + case ARIT_SHARD: + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_SMALL); + m_fValue = 1.0f; + m_bOverTopArmor = TRUE; + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Shard - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_1, TEXTURE_1, 0, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.4f,0), FLOAT3D(1.0,1.0,0.3f) ); + StretchItem(FLOAT3D(0.75f*0.75, 0.75f*0.75, 0.75f*0.75)); + m_iSoundComponent = SOUND_SHARD; + break; + case ARIT_SMALL: + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 25.0f; + m_bOverTopArmor = FALSE; + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Small - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_25, TEXTURE_25, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(2,2,0.5f) ); + StretchItem(FLOAT3D(2.0f, 2.0f, 2.0f)); + m_iSoundComponent = SOUND_SMALL; + break; + case ARIT_MEDIUM: { + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 50.0f; + m_bOverTopArmor = FALSE; + m_fRespawnTime = 25.0f; + m_strDescription.PrintF("Medium - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_50, TEXTURE_50, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,1.0f,0), FLOAT3D(3,3,0.5f) ); + StretchItem(FLOAT3D(2.0f, 2.0f, 2.0f)); + m_iSoundComponent = SOUND_MEDIUM; + } break; + case ARIT_STRONG: + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 100.0f; + m_bOverTopArmor = FALSE; + m_fRespawnTime = 60.0f; + m_strDescription.PrintF("Strong - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_100, TEXTURE_100, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(3.5,3.5,1.0f) ); + StretchItem(FLOAT3D(2.5f, 2.5f, 2.5f)); + m_iSoundComponent = SOUND_STRONG; + break; + case ARIT_SUPER: + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 200.0f; + m_bOverTopArmor = TRUE; + m_fRespawnTime = 120.0f; + m_strDescription.PrintF("Super - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + + AddItem(MODEL_200, TEXTURE_200, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.75f,0), FLOAT3D(3,3,1.0f) ); + StretchItem(FLOAT3D(2.5f, 2.5f, 2.5f)); + m_iSoundComponent = SOUND_SUPER; + break; + } + }; + + void AdjustDifficulty(void) + { + if (!GetSP()->sp_bAllowArmor && m_penTarget==NULL) { + Destroy(); + } + } + +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected { + ASSERT(epass.penOther!=NULL); + + // if armor stays + if (GetSP()->sp_bHealthArmorStays && !m_bPickupOnce) { + // if already picked by this player + BOOL bWasPicked = MarkPickedBy(epass.penOther); + if (bWasPicked) { + // don't pick again + return; + } + } + + // send health to entity + EArmor eArmor; + eArmor.fArmor = m_fValue; + eArmor.bOverTopArmor = m_bOverTopArmor; + // if health is received + if (epass.penOther->ReceiveItem(eArmor)) { + + if(_pNetwork->IsPlayerLocal(epass.penOther)) + { + switch (m_EaitType) + { + case ARIT_SHARD: IFeel_PlayEffect("PU_ArmourShard"); break; + case ARIT_SMALL: IFeel_PlayEffect("PU_ArmourSmall"); break; + case ARIT_MEDIUM: IFeel_PlayEffect("PU_ArmourMedium"); break; + case ARIT_STRONG: IFeel_PlayEffect("PU_ArmourStrong"); break; + case ARIT_SUPER: IFeel_PlayEffect("PU_ArmourSuper"); break; + } + } + + // play the pickup sound + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soPick, m_iSoundComponent, SOF_3D); + m_fPickSoundLen = GetSoundLength(m_iSoundComponent); + + if (!GetSP()->sp_bHealthArmorStays || m_bPickupOnce) { + jump CItem::ItemReceived(); + } + } + return; + }; + + Main() { + Initialize(); // initialize base class + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + SetProperties(); // set properties + + jump CItem::ItemLoop(); + }; +}; diff --git a/Sources/Entities/BackgroundViewer.es b/Sources/Entities/BackgroundViewer.es new file mode 100644 index 0000000..5ad5890 --- /dev/null +++ b/Sources/Entities/BackgroundViewer.es @@ -0,0 +1,68 @@ +211 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +class CBackgroundViewer: CMarker { +name "Background Viewer"; +thumbnail "Thumbnails\\BackgroundViewer.tbn"; +features "IsImportant"; + +properties: + 1 BOOL m_bActive "Active" 'A' =TRUE, // set if active at beginning of game + 2 CEntityPointer m_penWorldSettingsController "World settings controller" 'W', + +components: + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + +functions: + // Validate offered target for one property + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if(penTarget==NULL) + { + return FALSE; + } + // if gradient marker + if( slPropertyOffset==offsetof(CBackgroundViewer, m_penWorldSettingsController)) + { + return IsOfClass(penTarget, "WorldSettingsController"); + } + return TRUE; + } + + BOOL HandleEvent(const CEntityEvent &ee) { + if (ee.ee_slEvent == EVENTCODE_EStart) { + GetWorld()->SetBackgroundViewer(this); + return TRUE; + } + + return FALSE; + }; + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set name + if (m_strName=="Marker") { + m_strName = "Background Viewer"; + } + + if (m_bActive) { + GetWorld()->SetBackgroundViewer(this); + } + return; + } +}; + diff --git a/Sources/Entities/BasicEffects.es b/Sources/Entities/BasicEffects.es new file mode 100644 index 0000000..ebae31a --- /dev/null +++ b/Sources/Entities/BasicEffects.es @@ -0,0 +1,1238 @@ +601 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Effects/Teleport01/Teleport.h" +#include "Models/Effects/ExplosionGrenade/ExplosionGrenade.h" +#include "Models/Effects/ShockWave01/ShockWave.h" +#include "Models/Effects/BloodOnTheWall01/Blood.h" +#include "Entities/MovingBrush.h" + +#define EXPLOSION_GRENADE_TEXTURE_ANIM_FAST 0 +#define EXPLOSION_GRENADE_TEXTURE_ANIM_MEDIUM 1 +#define EXPLOSION_GRENADE_TEXTURE_ANIM_SLOW 2 + +#define SHOCKWAVE_TEXTURE_ANIM_FAST 0 +#define SHOCKWAVE_TEXTURE_ANIM_MEDIUM 1 +#define SHOCKWAVE_TEXTURE_ANIM_SLOW 2 +%} + +uses "Entities/Light"; + +enum BasicEffectType { + 0 BET_NONE "", // no effect (never spawned) + 1 BET_ROCKET "", // rocket explosion + 2 BET_ROCKET_PLANE "", // rocket explosion on plane + 3 BET_GRENADE "", // grenade explosion + 4 BET_GRENADE_PLANE "", // grenade explosion on plane + 5 BET_EXPLOSIONSTAIN "", // explosion stain on brush + 6 BET_SHOCKWAVE "", // shock wave + 7 BET_LASERWAVE "", // laser wave + 10 BET_BLOODSPILL "", // blood spill from bullet exit wound + 11 BET_BLOODSTAIN "", // blood stain + 19 BET_BLOODSTAINGROW "", // blood stain which grows bigger + 12 BET_BLOODEXPLODE "", // blood explosion at bullet entry wound + 13 BET_CANNON "", // cannon explosion + 14 BET_CANNON_PLANE "", // cannon explosion on plane + 15 BET_CANNONEXPLOSIONSTAIN "", // cannon explosion stain on brush + 16 BET_CANNONSHOCKWAVE "", // cannon shock wave + 17 BET_TELEPORT "", // teleportation + 18 BET_BOMB "", // small bomb explosion + 20 BET_BULLETTRAIL "", // white trail where bullet has passed + 21 BET_GIZMO_SPLASH_FX "", // gizmo splash fx + 22 BET_GIZMOSTAIN "", // gizmo stain + 30 BET_BULLETSTAINSTONE "", // bullet stain with ricochet on stone + 31 BET_BULLETSTAINSAND "", // bullet stain with ricochet on sand + 32 BET_BULLETSTAINWATER "", // bullet stain with ricochet on water surface + 33 BET_BULLETSTAINUNDERWATER "", // bullet stain with ricochet on underwater surface + 34 BET_BULLETSTAINSTONENOSOUND "", // bullet stain on stone with no sound + 35 BET_BULLETSTAINSANDNOSOUND "", // bullet stain on sand with no sound + 36 BET_BULLETSTAINWATERNOSOUND "", // bullet stain on water surface with no sound + 37 BET_BULLETSTAINUNDERWATERNOSOUND "", // bullet stain on under water surface with no sound + 38 BET_BULLETSTAINREDSAND "", // bullet stain with ricochet on red sand + 39 BET_BULLETSTAINREDSANDNOSOUND "", // bullet stain with ricochet on red sand without sound + 40 BET_LIGHT_CANNON "", // cannon explosion with lo sound volume + 41 BET_CANNON_NOLIGHT "", // cannon explosion without light witn lo sound volume +}; + +enum EffectParticlesType { + 0 EPT_NONE "", // no partcicles + 1 EPT_BULLET_STONE "", // bullet partcicles on stone + 2 EPT_BULLET_SAND "", // bullet partcicles on sand + 3 EPT_BULLET_WATER "", // bullet partcicles on water + 4 EPT_BULLET_UNDER_WATER "", // bullet partcicles underwater + 5 EPT_BULLET_RED_SAND "", // bullet partcicles on red sand +}; + + +// input parameter for spwaning a basic effect +event ESpawnEffect { + enum BasicEffectType betType, // type of effect + FLOAT3D vNormal, // normal for orientative effects + FLOAT3D vDirection, // direction oriented effects + FLOAT3D vStretch, // stretch effect model + COLOR colMuliplier, // color multiplier +}; + +%{ +void CBasicEffect_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + switch ((BasicEffectType)iUser) { + case BET_ROCKET: + case BET_ROCKET_PLANE: + pdec->PrecacheSound(SOUND_EXPLOSION); + pdec->PrecacheModel(MDL_ROCKET_EXPLOSION); + pdec->PrecacheTexture(TXT_ROCKET_EXPLOSION); + pdec->PrecacheModel(MDL_PARTICLES_EXPLOSION); + pdec->PrecacheTexture(TXT_PARTICLES_EXPLOSION); + pdec->PrecacheModel(MDL_ROCKET3D_EXPLOSION); + pdec->PrecacheTexture(TXT_ROCKET_EXPLOSION); + pdec->PrecacheModel(MDL_PARTICLES3D_EXPLOSION); + pdec->PrecacheTexture(TXT_PARTICLES_EXPLOSION); + break; + case BET_BOMB: + case BET_GRENADE: + case BET_GRENADE_PLANE: + pdec->PrecacheSound(SOUND_EXPLOSION); + pdec->PrecacheModel(MDL_GRENADE_EXPLOSION); + pdec->PrecacheTexture(TXT_GRENADE_EXPLOSION); + pdec->PrecacheModel(MDL_PARTICLES_EXPLOSION); + pdec->PrecacheTexture(TXT_PARTICLES_EXPLOSION); + pdec->PrecacheModel(MDL_GRENADE3D_EXPLOSION); + pdec->PrecacheTexture(TXT_GRENADE_EXPLOSION); + pdec->PrecacheModel(MDL_PARTICLES3D_EXPLOSION); + pdec->PrecacheTexture(TXT_PARTICLES_EXPLOSION); + break; + case BET_CANNON: + case BET_CANNON_NOLIGHT: + case BET_LIGHT_CANNON: + case BET_CANNON_PLANE: + case BET_CANNONSHOCKWAVE: + pdec->PrecacheSound(SOUND_EXPLOSION); + pdec->PrecacheModel(MDL_CANNON_EXPLOSION); + pdec->PrecacheTexture(TXT_CANNON_EXPLOSION); + pdec->PrecacheModel(MDL_CANNON3D_EXPLOSION); + pdec->PrecacheTexture(TXT_CANNON_EXPLOSION); + pdec->PrecacheModel(MODEL_CANNONSHOCKWAVE); + pdec->PrecacheTexture(TEXTURE_CANNONSHOCKWAVE); + break; + case BET_EXPLOSIONSTAIN: + pdec->PrecacheModel(MODEL_EXPLOSION_STAIN); + pdec->PrecacheTexture(TEXTURE_EXPLOSION_STAIN); + break; + case BET_CANNONEXPLOSIONSTAIN: + pdec->PrecacheModel(MODEL_CANNON_EXPLOSION_STAIN); + pdec->PrecacheTexture(TEXTURE_CANNON_EXPLOSION_STAIN); + break; + case BET_SHOCKWAVE: + pdec->PrecacheModel(MODEL_SHOCKWAVE); + pdec->PrecacheTexture(TEXTURE_SHOCKWAVE); + break; + case BET_LASERWAVE: + pdec->PrecacheModel(MODEL_LASERWAVE); + pdec->PrecacheTexture(TEXTURE_LASERWAVE); + break; + case BET_BULLETSTAINSTONE: + case BET_BULLETSTAINSAND: + case BET_BULLETSTAINREDSAND: + case BET_BULLETSTAINWATER: + case BET_BULLETSTAINUNDERWATER: + case BET_BULLETSTAINSTONENOSOUND: + case BET_BULLETSTAINSANDNOSOUND: + case BET_BULLETSTAINREDSANDNOSOUND: + case BET_BULLETSTAINWATERNOSOUND: + case BET_BULLETSTAINUNDERWATERNOSOUND: + pdec->PrecacheModel(MODEL_BULLET_HIT); + pdec->PrecacheTexture(TEXTURE_BULLET_HIT); + pdec->PrecacheTexture(TEXTURE_BULLET_SAND); + pdec->PrecacheModel(MODEL_SHOCKWAVE); + pdec->PrecacheTexture(TEXTURE_WATER_WAVE); + pdec->PrecacheSound(SOUND_BULLET_STONE); + pdec->PrecacheSound(SOUND_BULLET_SAND); + pdec->PrecacheSound(SOUND_BULLET_WATER); + pdec->PrecacheModel(MODEL_BULLET_STAIN); + pdec->PrecacheTexture(TEXTURE_BULLET_STAIN); + break; + case BET_BULLETTRAIL: + pdec->PrecacheModel(MODEL_BULLET_TRAIL); + pdec->PrecacheTexture(TEXTURE_BULLET_TRAIL); + break; + case BET_GIZMO_SPLASH_FX: + pdec->PrecacheModel(MODEL_BULLET_HIT); + pdec->PrecacheTexture(TEXTURE_BULLET_HIT); + pdec->PrecacheSound(SOUND_GIZMO_SPLASH); + break; + case BET_BLOODEXPLODE: + pdec->PrecacheModel(MODEL_BLOOD_EXPLODE); + pdec->PrecacheTexture(TEXTURE_BLOOD_EXPLODE); + pdec->PrecacheSound(SOUND_BULLET_FLESH); + break; + case BET_BLOODSTAIN: + case BET_BLOODSTAINGROW: + case BET_BLOODSPILL: + case BET_GIZMOSTAIN: + pdec->PrecacheModel(MODEL_BLOOD_STAIN); + pdec->PrecacheTexture(TEXTURE_BLOOD_STAIN1); + pdec->PrecacheTexture(TEXTURE_BLOOD_STAIN2); + pdec->PrecacheTexture(TEXTURE_BLOOD_STAIN3); + pdec->PrecacheTexture(TEXTURE_BLOOD_STAIN4); + pdec->PrecacheTexture(TEXTURE_BLOOD_SPILL1); + pdec->PrecacheTexture(TEXTURE_BLOOD_SPILL2); + pdec->PrecacheTexture(TEXTURE_BLOOD_SPILL3); + pdec->PrecacheTexture(TEXTURE_BLOOD_FLOWER1); + pdec->PrecacheTexture(TEXTURE_BLOOD_FLOWER2); + pdec->PrecacheTexture(TEXTURE_BLOOD_FLOWER3); + break; + case BET_TELEPORT: + pdec->PrecacheModel(MODEL_TELEPORT_EFFECT); + pdec->PrecacheTexture(TEXTURE_TELEPORT_EFFECT); + pdec->PrecacheSound(SOUND_TELEPORT); + break; + default: + ASSERT(FALSE); + } +} +%} + +class CBasicEffect : CRationalEntity { +name "BasicEffect"; +thumbnail ""; +features "ImplementsOnPrecache", "CanBePredictable"; + +properties: + 1 enum BasicEffectType m_betType = BET_NONE, // type of effect + 2 FLOAT m_fWaitTime = 0.0f, // wait time + 3 FLOAT m_fFadeTime = 0.0f, // fade away time + 4 BOOL m_bFade = FALSE, // fade is enabled + 5 FLOAT m_fFadeStartTime = 0.0f, // fade away start time + 9 FLOAT m_fFadeStartAlpha = 1.0f, // alpha value + 6 FLOAT3D m_vNormal = FLOAT3D(0,0,0), // normal for orientative effects + 7 FLOAT3D m_vStretch = FLOAT3D(0,0,0), // stretch effect + 8 FLOAT3D m_vDirection = FLOAT3D(0,0,0), // direction oriented effects + 10 FLOAT m_fDepthSortOffset = 0.0f, + 11 FLOAT m_fFadeInSpeed = 0.0f, + 12 FLOAT m_tmSpawn = 0.0f, // when it was spawned + 13 FLOAT m_tmWaitAfterDeath = 0.0f, // after death wait time + + 20 BOOL m_bLightSource = FALSE, // effect is also light source + 21 CAnimObject m_aoLightAnimation, // light animation object + 22 INDEX m_iLightAnimation = -1, // lignt animation index + 23 COLOR m_colMultiplyColor = 0xFFFFFFFF, // color multiplier + + 30 CSoundObject m_soEffect, // sound channel + 31 FLOAT m_fSoundTime = 0.0f, // wait for sound to end + + 40 enum EffectParticlesType m_eptType = EPT_NONE, // type of particle effect + 41 FLOAT m_tmWhenShot = 0.0f, // when entity was shot + 42 FLOAT3D m_vGravity = FLOAT3D(0,0,0), // simulated direction of gravity + +{ + CLightSource m_lsLightSource; +} + +components: + +// ********** PROJECTILE EXPLOSIONS ********** + 1 model MDL_ROCKET_EXPLOSION "Models\\Effects\\ExplosionRocket\\ExplosionRocket.mdl", + 2 model MDL_ROCKET3D_EXPLOSION "Models\\Effects\\ExplosionRocket\\ExplosionRocket3D.mdl", + 3 texture TXT_ROCKET_EXPLOSION "Models\\Effects\\Explosionrocket\\Texture.tex", + 4 model MDL_GRENADE_EXPLOSION "Models\\Effects\\ExplosionGrenade\\ExplosionGrenade.mdl", + 5 model MDL_GRENADE3D_EXPLOSION "Models\\Effects\\ExplosionGrenade\\ExplosionGrenade3D.mdl", + 6 texture TXT_GRENADE_EXPLOSION "Models\\Effects\\ExplosionGrenade\\Texture.tex", + 7 model MDL_PARTICLES_EXPLOSION "Models\\Effects\\ExplosionParticles\\Particles.mdl", + 8 model MDL_PARTICLES3D_EXPLOSION "Models\\Effects\\ExplosionParticles\\Particles3D.mdl", + 9 texture TXT_PARTICLES_EXPLOSION "Models\\Effects\\ExplosionParticles\\Texture.tex", + 10 sound SOUND_EXPLOSION "Sounds\\Weapons\\_Explosion02.wav", + 11 model MDL_CANNON_EXPLOSION "Models\\Effects\\ExplosionGrenade\\ExplosionGrenade.mdl", + 12 model MDL_CANNON3D_EXPLOSION "Models\\Effects\\ExplosionGrenade\\ExplosionGrenade3D.mdl", + 13 texture TXT_CANNON_EXPLOSION "Models\\Effects\\ExplosionGrenade\\Texture.tex", + +// ********** BULLET HIT ********** + 15 model MODEL_BULLET_HIT "Models\\Effects\\BulletParticles\\BulletParticles.mdl", + 16 texture TEXTURE_BULLET_HIT "Models\\Effects\\BulletParticles\\BulletParticles.tex", + 18 model MODEL_BULLET_STAIN "Models\\Effects\\BulletOnTheWall\\Bullet.mdl", + 19 texture TEXTURE_BULLET_STAIN "Models\\Effects\\BulletOnTheWall\\Bullet.tex", + 70 texture TEXTURE_BULLET_TRAIL "Models\\Effects\\BulletTrail\\BulletTrail.tex", + 71 model MODEL_BULLET_TRAIL "Models\\Effects\\BulletTrail\\BulletTrail.mdl", + + 90 sound SOUND_BULLET_STONE "Sounds\\Weapons\\_BulletHitWall.wav", + 91 sound SOUND_BULLET_SAND "Sounds\\Weapons\\BulletHitSand.wav", + 92 sound SOUND_BULLET_WATER "Sounds\\Weapons\\BulletHitWater.wav", + 93 sound SOUND_BULLET_FLESH "Sounds\\Weapons\\_BulletHitFlesh.wav", + 94 texture TEXTURE_BULLET_SAND "Models\\Effects\\BulletOnTheWall\\BulletSand.tex", + +// ********** BLOOD ********** + 21 model MODEL_BLOOD_EXPLODE "Models\\Effects\\BloodCloud\\BloodCloud.mdl", + 22 texture TEXTURE_BLOOD_EXPLODE "Models\\Effects\\BloodCloud\\BloodCloud.tex", + 23 model MODEL_BLOOD_STAIN "Models\\Effects\\BloodOnTheWall01\\Blood.mdl", + 24 texture TEXTURE_BLOOD_STAIN1 "Models\\Effects\\BloodOnTheWall01\\BloodStain01.tex", + 25 texture TEXTURE_BLOOD_STAIN2 "Models\\Effects\\BloodOnTheWall01\\BloodStain02.tex", + 26 texture TEXTURE_BLOOD_STAIN3 "Models\\Effects\\BloodOnTheWall01\\BloodStain03.tex", + 27 texture TEXTURE_BLOOD_STAIN4 "Models\\Effects\\BloodOnTheWall01\\BloodStain04.tex", + 28 texture TEXTURE_BLOOD_SPILL1 "Models\\Effects\\BloodOnTheWall01\\BloodSpill02.tex", + 29 texture TEXTURE_BLOOD_SPILL2 "Models\\Effects\\BloodOnTheWall01\\BloodSpill05.tex", + 30 texture TEXTURE_BLOOD_SPILL3 "Models\\Effects\\BloodOnTheWall01\\BloodSpill06.tex", + 31 texture TEXTURE_BLOOD_FLOWER1 "Models\\Effects\\Flowers\\Flowers1s.tex", + 32 texture TEXTURE_BLOOD_FLOWER2 "Models\\Effects\\Flowers\\Flowers2s.tex", + 33 texture TEXTURE_BLOOD_FLOWER3 "Models\\Effects\\Flowers\\Flowers3s.tex", + +// ********** SHOCK WAVE ********** + 40 model MODEL_SHOCKWAVE "Models\\Effects\\ShockWave01\\ShockWave.mdl", + 41 texture TEXTURE_SHOCKWAVE "Models\\Effects\\ShockWave01\\Textures\\ShockWave.tex", + + 42 model MODEL_CANNONSHOCKWAVE "Models\\Effects\\ShockWave01\\ShockWave.mdl", + 43 texture TEXTURE_CANNONSHOCKWAVE "Models\\Effects\\ShockWave01\\Textures\\ShockWave.tex", + +// ********** EXPLOSION STAIN ********** + 45 model MODEL_EXPLOSION_STAIN "Models\\Effects\\BurnedStainOnTheWall\\BurnedStainOnTheWall.mdl", + 46 texture TEXTURE_EXPLOSION_STAIN "Models\\Effects\\BurnedStainOnTheWall\\BurnedStainOnTheWall.tex", + + 47 model MODEL_CANNON_EXPLOSION_STAIN "Models\\Effects\\BurnedStainOnTheWall\\BurnedStainOnTheWall.mdl", + 48 texture TEXTURE_CANNON_EXPLOSION_STAIN "Models\\Effects\\BurnedStainOnTheWall\\BurnedStainOnTheWall.tex", + +// ********** LASER WAVE ********** + 50 model MODEL_LASERWAVE "Models\\Effects\\ShockWaveGreen\\ShockWaveGreen.mdl", + 51 texture TEXTURE_LASERWAVE "Models\\Effects\\ShockWaveGreen\\ShockWaveGreen.tex", + +// ********** TELEPORT ********** + 61 model MODEL_TELEPORT_EFFECT "Models\\Effects\\Teleport01\\Teleport.mdl", + 62 texture TEXTURE_TELEPORT_EFFECT "Textures\\Effects\\Effect01\\Effect.tex", + 63 sound SOUND_TELEPORT "Sounds\\Misc\\Teleport.wav", + +// ********** GIZMO SPLASH FX ********** + 80 sound SOUND_GIZMO_SPLASH "Models\\Enemies\\Gizmo\\Sounds\\Death.wav", + +// ********** Water shockwave texture ********** + 100 texture TEXTURE_WATER_WAVE "Models\\Effects\\ShockWave01\\Textures\\WaterWave.tex", + +functions: + + // dump sync data to text file + export void DumpSync_t(CTStream &strm, INDEX iExtensiveSyncCheck) // throw char * + { + CRationalEntity::DumpSync_t(strm, iExtensiveSyncCheck); + strm.FPrintF_t("Type: %d\n", m_betType); + } + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CRationalEntity::Read_t(istr); + // setup light source + if( m_bLightSource) { + SetupLightSource(); + } + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if( m_bLightSource && !IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + // Setup light source + void SetupLightSource(void) + { + if( m_iLightAnimation>=0) + { // set light animation if available + try { + m_aoLightAnimation.SetData_t(CTFILENAME("Animations\\BasicEffects.ani")); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load Animations\\BasicEffects.ani: %s"), strError); + } + // play light animation + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, 0); + } + } + + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 0.0f; + switch (m_betType) { + case BET_ROCKET: + lsNew.ls_colColor = RGBToColor(100, 100, 100); + lsNew.ls_rHotSpot = 3.0f; + lsNew.ls_rFallOff = 12.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case BET_GRENADE: + lsNew.ls_colColor = RGBToColor(200, 200, 200); + lsNew.ls_rFallOff = 12.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case BET_CANNON: + case BET_LIGHT_CANNON: + lsNew.ls_colColor = RGBToColor(200, 200, 200); + lsNew.ls_rFallOff = 12.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case BET_LASERWAVE: + lsNew.ls_colColor = RGBToColor(0, 64, 0); + lsNew.ls_rFallOff = 1.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case BET_BOMB: + lsNew.ls_colColor = RGBToColor(100, 100, 100); + lsNew.ls_rFallOff = 8.0f; + lsNew.ls_plftLensFlare = NULL; + break; + default: + ASSERTALWAYS("Unknown light source"); + } + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + // setup light animation + lsNew.ls_paoLightAnimation = NULL; + if (m_aoLightAnimation.GetData()!=NULL) { + lsNew.ls_paoLightAnimation = &m_aoLightAnimation; + } + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + + +/* RENDER PARTICLES */ + + + void RenderParticles(void) + { + if( m_eptType != EPT_NONE) + { + Particles_BulletSpray(this, m_vGravity, m_eptType, m_tmSpawn, m_vStretch); + } + } + + + +/************************************************************ + * FADE OUT * + ************************************************************/ + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + if( m_bFade) { + FLOAT m_fTimeRemain = m_fFadeStartTime + m_fFadeTime - _pTimer->CurrentTick(); + if (m_fTimeRemain < 0.0f) { m_fTimeRemain = 0.0f; } + COLOR col = GetModelColor() & ~CT_AMASK; + col |= (ULONG)(m_fFadeStartAlpha* m_fTimeRemain/m_fFadeTime *255.0f); + SetModelColor(col); + } else if (m_fFadeInSpeed>0) { + TIME tmAge = _pTimer->GetLerpedCurrentTick()-m_tmSpawn; + COLOR col = GetModelColor() ; + col = (col &~CT_AMASK) | + (ULONG)((255)*Clamp(tmAge*m_fFadeInSpeed/m_fWaitTime, 0.0f, 1.0f)); + SetModelColor(col); + } + + return FALSE; + }; + + // get offset for depth-sorting of alpha models (in meters, positive is nearer) + FLOAT GetDepthSortOffset(void) + { + return m_fDepthSortOffset; + } + + + +/************************************************************ + * GLOBAL SUPPORT FUNCTIONS * + ************************************************************/ + + void SetNonLoopingTexAnims(void) + { + CModelObject *pmo = GetModelObject(); + pmo->mo_toTexture.PlayAnim(0, 0); + FOREACHINLIST(CAttachmentModelObject, amo_lnInMain, pmo->mo_lhAttachments, itamo) { + CModelObject *pmoAtt = &itamo->amo_moModelObject; + pmoAtt->mo_toTexture.PlayAnim(0, 0); + } + } + + void SetNormalForHalfFaceForward(void) + { + CPlacement3D pl = GetPlacement(); + UpVectorToAngles(m_vNormal, pl.pl_OrientationAngle); + SetPlacement(pl); + }; + + void SetNormal(void) + { + CPlacement3D pl = GetPlacement(); + DirectionVectorToAngles(m_vNormal, pl.pl_OrientationAngle); + SetPlacement(pl); + }; + + void SetNormalWithRandomBanking(void) + { + CPlacement3D pl = GetPlacement(); + DirectionVectorToAngles(m_vNormal, pl.pl_OrientationAngle); + pl.pl_OrientationAngle(3) = FRnd()*360.0f; + SetPlacement(pl); + }; + + void FindGravityVectorFromSector(void) + { + CBrushSector *pbscContent = NULL; + {FOREACHSRCOFDST(en_rdSectors, CBrushSector, bsc_rsEntities, pbsc) + pbscContent = &*pbsc; + break; + ENDFOR;} + + if( pbscContent == NULL) + { + return; + } + INDEX iForceType = pbscContent->GetForceType(); + CEntity *penBrush = pbscContent->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity; + CForceStrength fsGravity; + CForceStrength fsField; + penBrush->GetForce( iForceType, en_plPlacement.pl_PositionVector, fsGravity, fsField); + // remember gravity vector + m_vGravity = fsGravity.fs_vDirection; + }; + + void SetNormalAndDirection(void) + { + // special case for stains without sliding + if( m_vDirection.Length() < 0.01f) { + SetNormalWithRandomBanking(); + return; + } + + FLOAT3D vX; + FLOAT3D vY = -m_vDirection; + FLOAT3D vZ = -m_vNormal; + vZ.Normalize(); + vX = vY*vZ; + vX.Normalize(); + vY = vZ*vX; + vY.Normalize(); + + FLOATmatrix3D m; + m(1,1) = vX(1); m(1,2) = vY(1); m(1,3) = vZ(1); + m(2,1) = vX(2); m(2,2) = vY(2); m(2,3) = vZ(2); + m(3,1) = vX(3); m(3,2) = vY(3); m(3,3) = vZ(3); + + CPlacement3D pl = GetPlacement(); + DecomposeRotationMatrixNoSnap(pl.pl_OrientationAngle, m); + SetPlacement(pl); + }; + + void RandomBanking(void) + { + CPlacement3D pl = GetPlacement(); + pl.pl_OrientationAngle(3) = FRnd()*360.0f; + SetPlacement(pl); + }; + + void Stretch(void) { + ASSERT(m_vStretch(1)>0.01f && m_vStretch(3)>0.01f && m_vStretch(3)>0.01f); + GetModelObject()->mo_Stretch = m_vStretch; + }; + + // parent the effect if needed and adjust size not to get out of the polygon + void ParentToNearestPolygonAndStretch(void) + { + // find nearest polygon + FLOAT3D vPoint; + FLOATplane3D plPlaneNormal; + FLOAT fDistanceToEdge; + CBrushPolygon *pbpoNearBrush = GetNearestPolygon( vPoint, plPlaneNormal, fDistanceToEdge); + + if( m_betType>=BET_BULLETSTAINSTONE && m_betType<=BET_BULLETSTAINREDSANDNOSOUND) + { + if( pbpoNearBrush != NULL) + { + CBrushSector *pbscContent = pbpoNearBrush->bpo_pbscSector; + INDEX iForceType = pbscContent->GetForceType(); + CEntity *penNearBrush = pbscContent->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity; + CForceStrength fsGravity; + CForceStrength fsField; + penNearBrush->GetForce( iForceType, en_plPlacement.pl_PositionVector, fsGravity, fsField); + // remember gravity vector + m_vGravity = fsGravity.fs_vDirection; + } + } + + // if there is none, or if it is portal, or it is not near enough + if (pbpoNearBrush==NULL || (pbpoNearBrush->bpo_ulFlags&BPOF_PORTAL) + || (vPoint-GetPlacement().pl_PositionVector).ManhattanNorm()>0.1f*3) { + // dissapear + SwitchToEditorModel(); + // if polygon is found + } else { + CEntity *penNearBrush = pbpoNearBrush->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity; + FLOATaabbox3D box; + en_pmoModelObject->GetCurrentFrameBBox( box); + box.StretchByVector( en_pmoModelObject->mo_Stretch); + FLOAT fOrgSize = box.Size().MaxNorm(); + FLOAT fMaxSize = fDistanceToEdge*2.0f; + // if minimum distance from polygon edges is too small + if( fMaxSizemo_Stretch*fStretch; + Stretch(); + ModelChangeNotify(); + // set parent to that brush + SetParent( penNearBrush); + } + } + } + + +/************************************************************ + * PROJECTILE/GRENADE EXPLOSION, STAIN * + ************************************************************/ + + void ProjectileExplosion(void) + { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_ROCKET_EXPLOSION); + SetModelMainTexture(TXT_ROCKET_EXPLOSION); + AddAttachment(0, MDL_PARTICLES_EXPLOSION, TXT_PARTICLES_EXPLOSION); + RandomBanking(); + SetNonLoopingTexAnims(); + m_soEffect.Set3DParameters(150.0f, 3.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_EXPLOSION, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_EXPLOSION); + m_fWaitTime = 0.95f; + m_bLightSource = TRUE; + m_iLightAnimation = 0; + }; + + void ProjectilePlaneExplosion(void) { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_ROCKET3D_EXPLOSION); + SetModelMainTexture(TXT_ROCKET_EXPLOSION); + AddAttachment(0, MDL_PARTICLES3D_EXPLOSION, TXT_PARTICLES_EXPLOSION); + SetNormalWithRandomBanking(); + SetNonLoopingTexAnims(); + m_fWaitTime = 0.95f; + m_bLightSource = FALSE; + }; + + void BombExplosion(void) { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_GRENADE_EXPLOSION); + SetModelMainTexture(TXT_GRENADE_EXPLOSION); + SetNonLoopingTexAnims(); + FLOAT fSizeFactor = m_vStretch.MaxNorm(); + m_soEffect.Set3DParameters(50.0f*fSizeFactor, 10.0f*fSizeFactor, 1.0f*fSizeFactor, 1.0f); + PlaySound(m_soEffect, SOUND_EXPLOSION, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_EXPLOSION); + m_fWaitTime = 0.95f; + m_bLightSource = TRUE; + m_iLightAnimation = 1; + }; + + void GizmoSplashFX(void) + { + SetPredictable(TRUE); + SetModel(MODEL_BULLET_HIT); + SetModelMainTexture(TEXTURE_BULLET_HIT); + m_soEffect.Set3DParameters(50.0f, 10.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_GIZMO_SPLASH, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_GIZMO_SPLASH); + m_fWaitTime = 0.95f; + m_bLightSource = FALSE; + }; + + void GrenadeExplosion(void) { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_GRENADE_EXPLOSION); + SetModelMainTexture(TXT_GRENADE_EXPLOSION); + AddAttachment(0, MDL_PARTICLES_EXPLOSION, TXT_PARTICLES_EXPLOSION); + RandomBanking(); + SetNonLoopingTexAnims(); + m_soEffect.Set3DParameters(150.0f, 3.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_EXPLOSION, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_EXPLOSION); + m_fWaitTime = 0.95f; + m_bLightSource = TRUE; + m_iLightAnimation = 1; + }; + + void GrenadePlaneExplosion(void) { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_GRENADE3D_EXPLOSION); + SetModelMainTexture(TXT_GRENADE_EXPLOSION); + AddAttachment(0, MDL_PARTICLES3D_EXPLOSION, TXT_PARTICLES_EXPLOSION); + SetNonLoopingTexAnims(); + SetNormalWithRandomBanking(); + m_fWaitTime = 0.95f; + m_bLightSource = FALSE; + }; + + void CannonExplosion(BOOL bLoVolume, BOOL bNoLight) { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_CANNON_EXPLOSION); + CModelObject &moExplosion = *GetModelObject(); + SetModelMainTexture(TXT_CANNON_EXPLOSION); + moExplosion.mo_colBlendColor = m_colMultiplyColor; + moExplosion.mo_toTexture.PlayAnim(EXPLOSION_GRENADE_TEXTURE_ANIM_FAST, 0); + RandomBanking(); + if( bLoVolume) + { + m_soEffect.Set3DParameters(150.0f, 3.0f, 0.5f, 1.0f); + } + else + { + m_soEffect.Set3DParameters(150.0f, 3.0f, 1.0f, 1.0f); + } + + PlaySound(m_soEffect, SOUND_EXPLOSION, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_EXPLOSION); + m_fWaitTime = 0.8f; + if( bNoLight) + { + m_bLightSource = FALSE; + } + else + { + m_bLightSource = TRUE; + m_iLightAnimation = 1; + } + }; + + void CannonPlaneExplosion(void) { + SetPredictable(TRUE); + Stretch(); + SetModel(MDL_CANNON3D_EXPLOSION); + CModelObject &moExplosion = *GetModelObject(); + SetModelMainTexture(TXT_CANNON_EXPLOSION); + moExplosion.mo_toTexture.PlayAnim(EXPLOSION_GRENADE_TEXTURE_ANIM_FAST, 0); + SetNormalWithRandomBanking(); + m_fWaitTime = 1.2f; + m_bLightSource = FALSE; + }; + + void Stain(void) { + SetModel(MODEL_EXPLOSION_STAIN); + SetModelMainTexture(TEXTURE_EXPLOSION_STAIN); + SetNormalWithRandomBanking(); + m_fWaitTime = 5.0f; + m_fFadeTime = 2.5f; + m_bLightSource = FALSE; + ParentToNearestPolygonAndStretch(); + }; + + void CannonStain(void) { + Stretch(); + SetModel(MODEL_CANNON_EXPLOSION_STAIN); + SetModelMainTexture(TEXTURE_CANNON_EXPLOSION_STAIN); + SetNormalWithRandomBanking(); + m_fWaitTime = 5.0f; + m_fFadeTime = 2.5f; + m_bLightSource = FALSE; + ParentToNearestPolygonAndStretch(); + }; + + + +/************************************************************ + * SHOCK / LASER WAVE * + ************************************************************/ + void ShockWave(void) { + SetPredictable(TRUE); + SetModel(MODEL_SHOCKWAVE); + CModelObject &moShockwave = *GetModelObject(); + moShockwave.PlayAnim(SHOCKWAVE_ANIM_FAST, 0); + SetModelMainTexture(TEXTURE_SHOCKWAVE); + SetNormal(); + SetNonLoopingTexAnims(); + m_fWaitTime = 0.4f; + m_fFadeTime = 0.1f; + m_bLightSource = FALSE; + }; + + void CannonShockWave(void) { + SetPredictable(TRUE); + Stretch(); + SetModel(MODEL_CANNONSHOCKWAVE); + CModelObject &moShockwave = *GetModelObject(); + moShockwave.PlayAnim(SHOCKWAVE_ANIM_SLOW, 0); + SetModelMainTexture(TEXTURE_CANNONSHOCKWAVE); + moShockwave.mo_toTexture.PlayAnim(SHOCKWAVE_TEXTURE_ANIM_SLOW, 0); + SetNormal(); + m_fWaitTime = 1.25f; + m_fFadeTime = 0.25f; + m_bLightSource = FALSE; + }; + + void LaserWave(void) { + SetModel(MODEL_LASERWAVE); + GetModelObject()->StretchModel(FLOAT3D(0.75f, 0.75f, 0.75f)); + ModelChangeNotify(); + SetModelMainTexture(TEXTURE_LASERWAVE); + SetNormalWithRandomBanking(); + SetNonLoopingTexAnims(); + m_fWaitTime = 0.05f; + m_fFadeTime = 0.25f; + m_bLightSource = TRUE; + ParentToNearestPolygonAndStretch(); + }; + + + + /************************************************************ + * TELEPORT * + ************************************************************/ + void TeleportEffect(void) + { + SetPredictable(TRUE); + Stretch(); + SetModel(MODEL_TELEPORT_EFFECT); + CModelObject &mo = *GetModelObject(); + SetModelMainTexture(TEXTURE_TELEPORT_EFFECT); + mo.PlayAnim(TELEPORT_ANIM_ACTIVATE, 0); + RandomBanking(); + FLOAT fSize = m_vStretch.MaxNorm(); + m_soEffect.Set3DParameters(40.0f*fSize, 10.0f*fSize, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_TELEPORT, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_TELEPORT); + m_fWaitTime = 0.8f; + m_bLightSource = FALSE; + }; + +/************************************************************ + * BULLET HIT / STAIN * + ************************************************************/ + void BulletStainSand(BOOL bSound) + { + if( bSound) + { + m_soEffect.Set3DParameters(20.0f, 10.0f, 1.0f, 1.0f+FRnd()*0.2f); + PlaySound(m_soEffect, SOUND_BULLET_SAND, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_BULLET_SAND); + } + + SetModel(MODEL_BULLET_STAIN); + SetModelMainTexture(TEXTURE_BULLET_SAND); + CModelObject &moHole = *GetModelObject(); + moHole.StretchModel(FLOAT3D(1.5f, 1.5f, 1.5f)); + ModelChangeNotify(); + + SetNormalWithRandomBanking(); + m_fWaitTime = 2.0f; + m_fFadeTime = 2.0f; + m_bLightSource = FALSE; + m_eptType = EPT_BULLET_SAND; + FLOAT3D vTemp = m_vStretch; + ParentToNearestPolygonAndStretch(); + m_vStretch = vTemp; + } + + void BulletStainRedSand(BOOL bSound) + { + if( bSound) + { + m_soEffect.Set3DParameters(20.0f, 10.0f, 1.0f, 1.0f+FRnd()*0.2f); + PlaySound(m_soEffect, SOUND_BULLET_SAND, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_BULLET_SAND); + } + + SetModel(MODEL_BULLET_STAIN); + SetModelMainTexture(TEXTURE_BULLET_SAND); + CModelObject &moHole = *GetModelObject(); + moHole.StretchModel(FLOAT3D(1.5f, 1.5f, 1.5f)); + ModelChangeNotify(); + moHole.mo_colBlendColor = 0x805030FF; + + SetNormalWithRandomBanking(); + m_fWaitTime = 2.0f; + m_fFadeTime = 2.0f; + m_bLightSource = FALSE; + m_eptType = EPT_BULLET_RED_SAND; + FLOAT3D vTemp = m_vStretch; + ParentToNearestPolygonAndStretch(); + m_vStretch = vTemp; + } + + void BulletStainStone(BOOL bSound, BOOL bSmoke) + { + if( bSound) + { + m_soEffect.Set3DParameters(20.0f, 10.0f, 1.0f, 1.0f+FRnd()*0.2f); + PlaySound(m_soEffect, SOUND_BULLET_STONE, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_BULLET_STONE); + } + SetModel(MODEL_BULLET_STAIN); + SetModelMainTexture(TEXTURE_BULLET_STAIN); + SetNormalWithRandomBanking(); + m_fWaitTime = 2.0f; + m_fFadeTime = 2.0f; + m_bLightSource = FALSE; + if( bSmoke) + { + m_eptType = EPT_BULLET_STONE; + } + else + { + m_eptType = EPT_BULLET_UNDER_WATER; + } + FLOAT3D vTemp = m_vStretch; + ParentToNearestPolygonAndStretch(); + m_vStretch = vTemp; + } + + void BulletStainWater(BOOL bSound) + { + if( bSound) + { + m_soEffect.Set3DParameters(20.0f, 10.0f, 1.0f, 1.0f+FRnd()*0.2f); + PlaySound(m_soEffect, SOUND_BULLET_WATER, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_BULLET_WATER); + } + + SetModel(MODEL_SHOCKWAVE); + SetModelMainTexture(TEXTURE_WATER_WAVE); + CModelObject &moShockwave = *GetModelObject(); + moShockwave.PlayAnim(SHOCKWAVE_ANIM_MEDIUM, 0); + moShockwave.StretchModel(FLOAT3D(0.25f, 0.25f, 0.25f)); + ModelChangeNotify(); + + SetNormalWithRandomBanking(); + FindGravityVectorFromSector(); + m_fWaitTime = 0.5f; + m_fFadeTime = 0.5f; + m_bLightSource = FALSE; + m_tmWaitAfterDeath = 1.0f; + m_eptType = EPT_BULLET_WATER; + } + + void BulletTrail(void) { + Stretch(); + SetModel(MODEL_BULLET_TRAIL); + SetModelMainTexture(TEXTURE_BULLET_TRAIL); + CModelObject &mo = *GetModelObject(); + mo.mo_colBlendColor = m_colMultiplyColor; + SetNormalForHalfFaceForward(); + m_fWaitTime = 0.1f; + m_bLightSource = FALSE; + }; + + +/************************************************************ + * BLOOD SPILL / STAIN * + ************************************************************/ + + + // bullet hitpoint wound + void BloodExplode(void) + { + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + if( iBloodType<1) { return; } + + SetPredictable(TRUE); + Stretch(); + SetModel(MODEL_BLOOD_EXPLODE); + if( iBloodType==3) { + // flower mode! :) + SetModelColor( RGBAToColor( 255,255,255,255)); + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + } + } else { + SetModelMainTexture(TEXTURE_BLOOD_EXPLODE); + if( iBloodType==2) { SetModelColor( RGBAToColor( 250,20,20,255)); } + else { SetModelColor( RGBAToColor( 0,250,0,255)); } + } + //RandomBanking(); + m_soEffect.Set3DParameters(7.5f, 5.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_BULLET_FLESH, SOF_3D); + m_fSoundTime = GetSoundLength(SOUND_BULLET_FLESH); + m_fWaitTime = 0.25f; + m_fFadeTime = 0.75f; + m_bLightSource = FALSE; + } + + + // blood stain on wall/floor + void BloodStain(void) + { + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + if( iBloodType<1) { return; } + + Stretch(); + SetModel(MODEL_BLOOD_STAIN); + if( iBloodType==3) { + // flower mode! :) + SetModelColor( RGBAToColor( 255,255,255,255)); + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + } + } else { + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_STAIN1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_STAIN2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_STAIN3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_STAIN4); break; } + } + if( iBloodType==2) { SetModelColor( RGBAToColor( 250,20,20,255)); } + else { SetModelColor( RGBAToColor( 0,250,0,255)); } + } + + SetNormalAndDirection(); + m_fWaitTime = 12.0f + FRnd()*3.0f; + m_fFadeTime = 3.0f; + m_bLightSource = FALSE; + m_fDepthSortOffset = -0.1f; + ParentToNearestPolygonAndStretch(); + } + + + // blood stain on wall/floor that grows + void BloodStainGrow(void) + { + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + if( iBloodType<1) { return; } + + SetPredictable(TRUE); + Stretch(); + SetModel(MODEL_BLOOD_STAIN); + if( iBloodType==3) { + // flower mode! :) + SetModelColor( RGBAToColor( 255,255,255,255)); + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + } + } else { + SetModelMainTexture(TEXTURE_BLOOD_STAIN4); + if( iBloodType==2) { SetModelColor( RGBAToColor( 250,20,20,255)); } + else { SetModelColor( RGBAToColor( 0,250,0,255)); } + } + SetNormalAndDirection(); + m_bLightSource = FALSE; + m_fDepthSortOffset = -0.1f; + ParentToNearestPolygonAndStretch(); + + m_fWaitTime = 15.0f + FRnd()*2.0f; + m_fFadeTime = 2.0f; + m_fFadeInSpeed = 4.0f; + CModelObject &mo = *GetModelObject(); + mo.PlayAnim(BLOOD_ANIM_GROW, 0); + } + + + // gizmo stain on wall/floor + void GizmoStain(void) + { + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + if( iBloodType<1) { return; } + + Stretch(); + SetModel(MODEL_BLOOD_STAIN); + if( iBloodType==3) { + // flower mode! :) + SetModelColor( RGBAToColor( 255,255,255,255)); + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + } + } else { + SetModelColor( RGBAToColor( 0,250,0,255)); + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_STAIN1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_STAIN2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_STAIN3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_STAIN4); break; } + } + } + SetNormalAndDirection(); + m_fWaitTime = 15.0f + FRnd()*2.0f; + m_fFadeTime = 2.0f; + m_bLightSource = FALSE; + m_fDepthSortOffset = -0.1f; + ParentToNearestPolygonAndStretch(); + } + + + // bullet exit wound blood on wall/floor + void BloodSpill(COLOR colBloodSpillColor) + { + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + if( iBloodType<1) { return; } + + Stretch(); + SetModel(MODEL_BLOOD_STAIN); + if( iBloodType==3) { + // flower mode! :) + SetModelColor( RGBAToColor( 255,255,255,255)); + switch( IRnd()&3) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER3); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_FLOWER1); break; } + } + } else { + switch( IRnd()%5) { + case 1: { SetModelMainTexture(TEXTURE_BLOOD_SPILL1); break; } + case 2: { SetModelMainTexture(TEXTURE_BLOOD_SPILL2); break; } + case 3: { SetModelMainTexture(TEXTURE_BLOOD_SPILL1); break; } + case 4: { SetModelMainTexture(TEXTURE_BLOOD_SPILL2); break; } + default: { SetModelMainTexture(TEXTURE_BLOOD_SPILL3); break; } + } + if( iBloodType==2) + { + SetModelColor( colBloodSpillColor); + } + else { SetModelColor( RGBAToColor( 0,250,0,255)); } + } + SetNormalAndDirection(); + m_fWaitTime = 15.0f + FRnd()*2.0f; + m_fFadeTime = 2.0f; + m_bLightSource = FALSE; + ParentToNearestPolygonAndStretch(); + } + +procedures: + + +/************************************************************ + * M A I N * + ************************************************************/ + + Main(ESpawnEffect eSpawn) + { + if(eSpawn.betType == BET_GIZMO_SPLASH_FX) + { + InitAsEditorModel(); + } + else + { + InitAsModel(); + } + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + SetFlags(GetFlags() | ENF_SEETHROUGH); + + // set appearance + m_tmSpawn = _pTimer->CurrentTick(); + m_vNormal = eSpawn.vNormal; + m_vDirection = eSpawn.vDirection; + m_vStretch = eSpawn.vStretch; + m_betType = eSpawn.betType; + m_colMultiplyColor = eSpawn.colMuliplier; + + switch (m_betType) { + case BET_ROCKET: ProjectileExplosion(); break; + case BET_ROCKET_PLANE: ProjectilePlaneExplosion(); break; + case BET_GRENADE: GrenadeExplosion(); break; + case BET_GRENADE_PLANE: GrenadePlaneExplosion(); break; + case BET_EXPLOSIONSTAIN: Stain(); break; + case BET_SHOCKWAVE: ShockWave(); break; + case BET_LASERWAVE: LaserWave(); break; + case BET_BULLETTRAIL: BulletTrail(); break; + case BET_BULLETSTAINSAND: BulletStainSand(TRUE); break; + case BET_BULLETSTAINREDSAND: BulletStainRedSand(TRUE); break; + case BET_BULLETSTAINSTONE: BulletStainStone(TRUE, TRUE); break; + case BET_BULLETSTAINWATER: BulletStainWater(TRUE); break; + case BET_BULLETSTAINUNDERWATER: BulletStainStone(TRUE, FALSE); break; + case BET_BULLETSTAINSANDNOSOUND: BulletStainSand(FALSE); break; + case BET_BULLETSTAINREDSANDNOSOUND: BulletStainRedSand(FALSE); break; + case BET_BULLETSTAINSTONENOSOUND: BulletStainStone(FALSE, TRUE); break; + case BET_BULLETSTAINWATERNOSOUND: BulletStainWater(FALSE); break; + case BET_BULLETSTAINUNDERWATERNOSOUND: BulletStainStone(FALSE, FALSE); break; + case BET_BLOODSPILL: BloodSpill(m_colMultiplyColor); break; + case BET_BLOODSTAIN: BloodStain(); break; + case BET_GIZMOSTAIN: GizmoStain(); break; + case BET_BLOODSTAINGROW: BloodStainGrow(); break; + case BET_BLOODEXPLODE: BloodExplode(); break; + case BET_CANNON: CannonExplosion(FALSE, FALSE); break; + case BET_CANNON_NOLIGHT: CannonExplosion(TRUE, TRUE); break; + case BET_LIGHT_CANNON: CannonExplosion(TRUE, FALSE); break; + case BET_CANNON_PLANE: CannonPlaneExplosion(); break; + case BET_CANNONEXPLOSIONSTAIN: CannonStain(); break; + case BET_CANNONSHOCKWAVE: CannonShockWave(); break; + case BET_TELEPORT: TeleportEffect(); break; + case BET_BOMB: BombExplosion(); break; + case BET_GIZMO_SPLASH_FX: GizmoSplashFX(); break; + default: + ASSERTALWAYS("Unknown effect type"); + } + + // setup light source + if (m_bLightSource) { SetupLightSource(); } + + wait() { + on (EBegin) : { call EffectLoop(); } + on (EBrushDestroyed) : { stop; } + on (EReturn) : { stop; } + } + + // cease to exist + Destroy(); + return; + } + + + // standard effect loop + EffectLoop() + { + // wait + if (m_fWaitTime>0.0f) { + autowait(m_fWaitTime); + } + // fading + if (m_fFadeTime>0.0f) { + m_fFadeStartTime = _pTimer->CurrentTick(); + m_fFadeStartAlpha = ((GetModelColor()&CT_AMASK)>>CT_ASHIFT) / 255.0f; + m_bFade = TRUE; + autowait(m_fFadeTime); + m_bFade = FALSE; + } + + // wait for sound to end + if (m_fSoundTime > m_fWaitTime+m_fFadeTime) { + SwitchToEditorModel(); + autowait(m_fSoundTime - (m_fWaitTime+m_fFadeTime)); + } + + if (m_tmWaitAfterDeath>0.0f) { + if( en_RenderType != RT_EDITORMODEL) + { + SwitchToEditorModel(); + } + autowait(m_tmWaitAfterDeath); + } + + return EReturn(); + } + +}; diff --git a/Sources/Entities/Beast.es b/Sources/Entities/Beast.es new file mode 100644 index 0000000..9fea7c5 --- /dev/null +++ b/Sources/Entities/Beast.es @@ -0,0 +1,450 @@ +336 + +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Beast/Beast.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/BackgroundViewer.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/BasicEffects"; + +enum BeastType { + 0 BT_NORMAL "Small", // normal (fighter) + 1 BT_BIG "Big", // big +}; + +%{ +static int _tmLastStandingAnim =0; +#define BEAST_STRETCH 2.0f +#define BIG_BEAST_STRETCH 12.0f +// info structure +static EntityInfo eiBeastNormal = { + EIBT_FLESH, 1500.0f, + 0.0f, 2.0f*BEAST_STRETCH, 0.0f, // source (eyes) + 0.0f, 1.5f*BEAST_STRETCH, 0.0f, // target (body) +}; +static EntityInfo eiBeastBig = { + EIBT_FLESH, 5000.0f, + 0.0f, 2.0f*BIG_BEAST_STRETCH, 0.0f, // source (eyes) + 0.0f, 1.5f*BIG_BEAST_STRETCH, 0.0f, // target (body) +}; +%} + +class CBeast : CEnemyBase { +name "Beast"; +thumbnail "Thumbnails\\Beast.tbn"; + +properties: + 1 enum BeastType m_bcType "Character" 'C' = BT_NORMAL, + 2 INDEX m_iCounter = 0, + 3 BOOL m_bBeBoss "Boss" 'B' = FALSE, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + + 10 model MODEL_BEAST "Models\\Enemies\\Beast\\Beast.mdl", + 11 texture TEXTURE_BEAST_NORMAL "Models\\Enemies\\Beast\\Beast.tex", + 12 texture TEXTURE_BEAST_BIG "Models\\Enemies\\Beast\\BeastBig.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Beast\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Beast\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Beast\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Beast\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Beast\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Beast\\Sounds\\Death.wav", + 56 sound SOUND_DEATHBIG "Models\\Enemies\\Beast\\Sounds\\DeathBig.wav", + 57 sound SOUND_ANGER "Models\\Enemies\\Beast\\Sounds\\Anger.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("A Reptiloid killed %s"),(const char*) strPlayerName); + return str; + } + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnmNormal, "Data\\Messages\\Enemies\\BeastNormal.txt"); + static DECLARE_CTFILENAME(fnmBig, "Data\\Messages\\Enemies\\BeastBig.txt"); + switch(m_bcType) { + default: ASSERT(FALSE); + case BT_NORMAL: return fnmNormal; + case BT_BIG: return fnmBig; + } + }; + void Precache(void) { + CEnemyBase::Precache(); + PrecacheSound(SOUND_IDLE ); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_ANGER); + PrecacheSound(SOUND_FIRE); + PrecacheSound(SOUND_KICK); + PrecacheModel(MODEL_BEAST); + PrecacheTexture(TEXTURE_BEAST_NORMAL); + PrecacheTexture(TEXTURE_BEAST_BIG); + if (m_bcType == BT_NORMAL) { + PrecacheSound(SOUND_DEATH); + PrecacheClass(CLASS_PROJECTILE, PRT_BEAST_PROJECTILE); + } else { + PrecacheSound(SOUND_DEATHBIG); + PrecacheClass(CLASS_PROJECTILE, PRT_BEAST_BIG_PROJECTILE); + } + }; + + /* Entity info */ + void *GetEntityInfo(void) { + if (m_bcType == BT_NORMAL) { + return &eiBeastNormal; + } else { + return &eiBeastBig; + } + }; + + class CWorldSettingsController *GetWSC(void) + { + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + return pwsc; + } + + void ShakeItBaby(FLOAT tmShaketime, FLOAT fPower) + { + CWorldSettingsController *pwsc = GetWSC(); + if (pwsc!=NULL) { + pwsc->m_tmShakeStarted = tmShaketime; + pwsc->m_vShakePos = GetPlacement().pl_PositionVector; + pwsc->m_fShakeFalloff = 400.0f; + pwsc->m_fShakeFade = 3.0f; + + pwsc->m_fShakeIntensityZ = 0.0f; + pwsc->m_tmShakeFrequencyZ = 5.0f; + pwsc->m_fShakeIntensityY = 0.1f*fPower; + pwsc->m_tmShakeFrequencyY = 5.0f; + pwsc->m_fShakeIntensityB = 2.5f*fPower; + pwsc->m_tmShakeFrequencyB = 7.2f; + } + } + + FLOAT GetCrushHealth(void) + { + if (m_bcType == BT_BIG) { + return 100.0f; + } + return 0.0f; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // can't harm own class + if (!IsOfClass(penInflictor, "Beast")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + if(m_bcType==BT_BIG && GetHealth() <= m_fMaxHealth/2) { + iAnim = BEAST_ANIM_ANGER; + } else { + iAnim = BEAST_ANIM_WOUND; + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + if(m_bcType==BT_BIG) { + iAnim = BEAST_ANIM_DEATHBIG; + } else { + iAnim = BEAST_ANIM_DEATH; + } + + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(BEAST_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + _tmLastStandingAnim = _pTimer->CurrentTick(); + StartModelAnim(BEAST_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART); + }; + + void WalkingAnim(void) { + if(_pTimer->CurrentTick()>=_tmLastStandingAnim-_pTimer->TickQuantum && + _pTimer->CurrentTick()<=_tmLastStandingAnim+_pTimer->TickQuantum) + { + BREAKPOINT; + } + + if(m_bcType==BT_BIG) { + StartModelAnim(BEAST_ANIM_WALKBIG, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(BEAST_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + } + }; + + void RunningAnim(void) { + WalkingAnim(); + }; + void RotatingAnim(void) { + WalkingAnim(); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + if(m_bcType==BT_BIG && GetHealth() <= m_fMaxHealth/2) { + PlaySound(m_soSound, SOUND_ANGER, SOF_3D); + } else { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + } + }; + void DeathSound(void) { + if (m_bcType == BT_NORMAL) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + } else { + PlaySound(m_soSound, SOUND_DEATHBIG, SOF_3D); + } + }; + + + // adjust sound and watcher parameters here if needed + void EnemyPostInit(void) + { + m_soSound.Set3DParameters(160.0f, 50.0f, 2.0f, 1.0f); + }; + +procedures: +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + if (m_bcType == BT_NORMAL) { + jump CEnemyBase::Death(); + } + // stop moving + StopMoving(); + DeathSound(); // death sound + LeaveStain(TRUE); + // set physic flags + SetPhysicsFlags(EPF_MODEL_CORPSE); + SetCollisionFlags(ECF_CORPSE); + SetFlags(GetFlags() | ENF_SEETHROUGH); + // stop making fuss + RemoveFromFuss(); + // death notify (usually change collision box and change body density) + DeathNotify(); + // start death anim + AnimForDeath(); + autowait(1.0f); + ShakeItBaby(_pTimer->CurrentTick(), 2.0f); + autowait(2.4f-1.0f); + ShakeItBaby(_pTimer->CurrentTick(), 5.0f); + autowait(GetModelObject()->GetAnimLength(BEAST_ANIM_DEATHBIG)-3.4f); + return EEnd(); + }; + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire + { + // wait to finish walk and smooth change to idle + StartModelAnim(BEAST_ANIM_WALKTOIDLE, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + if( m_bcType == BT_NORMAL) + { + StartModelAnim(BEAST_ANIM_ATTACK, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.51f); + + ShootProjectile(PRT_BEAST_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BEAST_STRETCH, 0.0f), + ANGLE3D(AngleDeg((FRnd()-0.5)*30.0f), AngleDeg(FRnd()*10.0f), 0)); + autowait(0.3f); + } + + if( m_bcType == BT_BIG) + { + if( GetHealth() <= m_fMaxHealth/2) + { + m_iCounter = 0; + while ( m_iCounter<6) + { + StartModelAnim(BEAST_ANIM_ATTACKFAST, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.34f); + ShootProjectile(PRT_BEAST_BIG_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BIG_BEAST_STRETCH, 0.0f), + ANGLE3D( AngleDeg(40.0f*Cos(m_iCounter*360.0/6.0f)), AngleDeg(20.0f*Sin(m_iCounter*180.0/6.0f)), 0)); + //autowait(0.15f); + m_iCounter++; + } + m_fAttackFireTime = 7.0f; + } + + if( GetHealth() > m_fMaxHealth/2) + { + m_iCounter = 0; + while ( m_iCounter<3) + { + StartModelAnim(BEAST_ANIM_ATTACK, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.5f); + ShootProjectile(PRT_BEAST_BIG_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BIG_BEAST_STRETCH, 0.0f), + ANGLE3D( AngleDeg(20.0f*Cos(m_iCounter*360.0/3.0f)), AngleDeg(10.0f*Sin(m_iCounter*180.0/3.0f)), 0)); + //autowait(0.25f); + m_iCounter++; + } + } + } + + MaybeSwitchToAnotherPlayer(); + + autowait(FRnd()/2 + _pTimer->TickQuantum); + + if( m_penEnemy != NULL) + { + FLOAT fEnemyDistance = CalcDist(m_penEnemy); + if( fEnemyDistance>m_fCloseDistance*1.25f) + { + StartModelAnim(BEAST_ANIM_IDLETOWALK, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + autowait(GetModelObject()->GetAnimLength(BEAST_ANIM_IDLETOWALK)/2.0f - _pTimer->TickQuantum); + } + } + + + return EReturn(); + }; + + // hit enemy + Hit(EVoid) : CEnemyBase::Hit { + // close attack + StartModelAnim(BEAST_ANIM_KICK, 0); + autowait(0.45f); + /* + StartModelAnim(BEAST_ANIM_KICK, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + */ + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + if (CalcDist(m_penEnemy) < m_fCloseDistance) { + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + if (m_bcType == BT_BIG) { + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 80.0f, FLOAT3D(0, 0, 0), vDirection); + } else { + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 40.0f, FLOAT3D(0, 0, 0), vDirection); + } + } + + /* + StartModelAnim(BEAST_ANIM_IDLE, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + */ + autowait(0.45f); + MaybeSwitchToAnotherPlayer(); + return EReturn(); + }; + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + + en_fDensity = 1100.0f; + // set your appearance + SetModel(MODEL_BEAST); + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd()*2 + 5.0f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*20.0f + 50.0f); + m_fCloseRunSpeed = FRnd() + 10.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 900.0f); + // setup attack distances + m_fAttackDistance = 500.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 0.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 750.0f; + m_bBoss = m_bBeBoss; + m_fStopDistance = 5.0f; + m_fCloseDistance = 7.0f; + m_tmGiveUp = Max(m_tmGiveUp, 10.0f); + + // damage/explode properties + if( m_bcType == BT_NORMAL) + { + m_fAttackRunSpeed = 6.0f;//6 + m_aAttackRotateSpeed = AngleDeg(3600.0f); + SetHealth(400.0f); + SetModelMainTexture(TEXTURE_BEAST_NORMAL); + m_fBlowUpAmount = 10000.0f; + m_fBodyParts = 4; + m_fDamageWounded = 250.0f; + m_iScore = 5000;//500 + // set stretch factor + GetModelObject()->StretchModel(FLOAT3D(BEAST_STRETCH, BEAST_STRETCH, BEAST_STRETCH)); + ModelChangeNotify(); + m_sptType = SPT_SLIME; + m_fAttackFireTime = 3.0f; + } + else + { + m_fAttackRunSpeed = 8.0f;//8 + m_aAttackRotateSpeed = AngleDeg(600.0f); + SetHealth(2000.0f);//500 + SetModelMainTexture(TEXTURE_BEAST_BIG); + m_fBlowUpAmount = 10000.0f;//500 + m_fBodyParts = 6; + m_fDamageWounded = 650.0f;//500 + m_iScore = 25000; //1000 + m_fStopDistance = 15; + m_fCloseDistance = 20; + // set stretch factor + GetModelObject()->StretchModel(FLOAT3D(BIG_BEAST_STRETCH, BIG_BEAST_STRETCH, BIG_BEAST_STRETCH)); + ModelChangeNotify(); + m_sptType = SPT_BLOOD; + m_fAttackFireTime = 5.0f; + } + m_fMaxHealth = GetHealth(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/BigHead.es b/Sources/Entities/BigHead.es new file mode 100644 index 0000000..ece886a --- /dev/null +++ b/Sources/Entities/BigHead.es @@ -0,0 +1,209 @@ +340 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Mental/Mental.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/BasicEffects"; + +%{ +// info structure +static EntityInfo eiMental = { + EIBT_FLESH, 200.0f, + 0.0f, 1.5f, 0.0f, // source (eyes) + 0.0f, 1.0f, 0.0f, // target (body) +}; + +#define GREET_SENSE_RANGE 10.0f +#define GREET_SENSE_DELAY 30.0f + +%} + +class CBigHead: CEnemyBase { +name "BigHead"; +thumbnail "Thumbnails\\Mental.tbn"; + +properties: + // class internal + 1 CTFileName m_fnmHeadTex "Head texture" 'H' = CTString(""), + 2 CTFileName m_fnmNameSnd "Name sound" 'S' = CTString(""), + 3 FLOAT m_tmLastGreetTime = -100.0f, + + { + CAutoPrecacheSound m_aps; + CAutoPrecacheTexture m_apt; + } + +components: + 1 class CLASS_BASE "Classes\\EnemyBase.ecl", + 2 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + 3 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +// ************** DATA ************** + 10 model MODEL_MENTAL "Models\\Enemies\\Mental\\Mental.mdl", + 11 texture TEXTURE_MENTAL "Models\\Enemies\\Mental\\Mental.tex", + 12 model MODEL_HEAD "Models\\Enemies\\Mental\\Head.mdl", + + 50 sound SOUND_IDLE "Models\\Enemies\\Mental\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Mental\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Mental\\Sounds\\Wound.wav", + 53 sound SOUND_DEATH "Models\\Enemies\\Mental\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) + { + return &eiMental; + }; + + void Precache(void) + { + CEnemyBase::Precache(); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_IDLE); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_DEATH); + m_aps.Precache(m_fnmNameSnd); + m_apt.Precache(m_fnmHeadTex); + }; + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + iAnim = MENTAL_ANIM_PANIC; + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + iAnim = MENTAL_ANIM_DEATH; + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { +// ChangeCollisionBoxIndexWhenPossible(HEADMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(MENTAL_ANIM_GROUNDREST, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { + StartModelAnim(MENTAL_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + if (_pTimer->CurrentTick()>m_tmLastGreetTime+GREET_SENSE_DELAY) { + m_fSenseRange = GREET_SENSE_RANGE; + m_bDeaf = FALSE; + } + }; + void RunningAnim(void) + { + StartModelAnim(MENTAL_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + RunningAnim(); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + +procedures: + Fire(EVoid) : CEnemyBase::Fire { + // hit + if (CalcDist(m_penEnemy) <= m_fStopDistance*1.1f) { + PlaySound(m_soSound, m_fnmNameSnd, SOF_3D); + m_bBlind = TRUE; + m_bDeaf = TRUE; + m_fSenseRange = 0.0f; + m_tmLastGreetTime = _pTimer->CurrentTick(); + SetTargetNone(); + StartModelAnim(MENTAL_ANIM_GREET, 0); + autowait(GetModelObject()->GetCurrentAnimLength()); + StandingAnim(); + return EReconsiderBehavior(); + } + return EReturn(); + } + + /************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(20.0f); + m_fMaxHealth = 20.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 2000.0f; + m_fBlowUpSize = 2.0f; + + // set your appearance + SetModel(MODEL_MENTAL); + SetModelMainTexture(TEXTURE_MENTAL); + AddAttachment(0, MODEL_HEAD, TEXTURE_MENTAL); + if (m_fnmHeadTex!="") { + // try to + try { + CAttachmentModelObject *pamoHead = GetModelObject()->GetAttachmentModel(0); + if (pamoHead!=NULL) { + pamoHead->amo_moModelObject.mo_toTexture.SetData_t(m_fnmHeadTex); + } + // if anything failed + } catch (char *strError) { + // report error + CPrintF("%s\n", strError); + AddAttachment(0, MODEL_HEAD, TEXTURE_MENTAL); + } + } + + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd()*2.0f + 6.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 6.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 5.0f; // greeting distance + m_fAttackFireTime = 0.1f; + m_fCloseFireTime = 0.1f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 65.0f; + m_fBodyParts = 4; + m_fDamageWounded = 1.0f; + m_iScore = 0; + m_bBlind = TRUE; + m_fSenseRange = GREET_SENSE_RANGE; + + // set stretch factors for height and width + const FLOAT fSize = 0.6f; + GetModelObject()->StretchModel(FLOAT3D(fSize, fSize, fSize)); + ModelChangeNotify(); + StandingAnim(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/BlendController.es b/Sources/Entities/BlendController.es new file mode 100644 index 0000000..43a1770 --- /dev/null +++ b/Sources/Entities/BlendController.es @@ -0,0 +1,126 @@ +612 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/BackgroundViewer.h" +%} + +uses "Entities/Marker"; + +enum BlendControllerType { + 0 BCT_NONE "None", // no FX + 1 BCT_PYRAMID_PLATES "Appear pyramid plates", // effect of appearing of pyramid plates + 2 BCT_ACTIVATE_PLATE_1 "Activate plate 1", // plate 1 activating + 3 BCT_ACTIVATE_PLATE_2 "Activate plate 2", // plate 2 activating + 4 BCT_ACTIVATE_PLATE_3 "Activate plate 3", // plate 3 activating + 5 BCT_ACTIVATE_PLATE_4 "Activate plate 4", // plate 4 activating + 6 BCT_ACTIVATE_PYRAMID_MORPH_ROOM "Pyramid morph room", // pyramid morph room activated +}; + +class CBlendController: CMarker +{ +name "Blend controller"; +thumbnail "Thumbnails\\BlendController.tbn"; +features "IsImportant"; + +properties: + + 1 enum BlendControllerType m_bctType "Blend type" 'Y' = BCT_NONE, // type of effect + +components: + + 1 model MODEL_CONTROLLER "Models\\Editor\\BlendController.mdl", + 2 texture TEXTURE_CONTROLLER "Models\\Editor\\BlendController.tex", + + +functions: + // ----------- Obtain world settings controller + CWorldSettingsController *GetWSC(void) + { + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) + { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + return pwsc; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + // obtain world settings controller + CWorldSettingsController *pwsc = GetWSC(); + if( pwsc == NULL) { + return FALSE; + } + FLOAT tmNow = _pTimer->CurrentTick(); + + if (ee.ee_slEvent==EVENTCODE_EActivate) + { + switch(m_bctType) + { + case BCT_PYRAMID_PLATES: + pwsc->m_tmPyramidPlatesStart = tmNow; + break; + case BCT_ACTIVATE_PLATE_1: + pwsc->m_tmActivatedPlate1 = tmNow; + pwsc->m_tmDeactivatedPlate1 = 1e6; + break; + case BCT_ACTIVATE_PLATE_2: + pwsc->m_tmActivatedPlate2 = tmNow; + pwsc->m_tmDeactivatedPlate2 = 1e6; + break; + case BCT_ACTIVATE_PLATE_3: + pwsc->m_tmActivatedPlate3 = tmNow; + pwsc->m_tmDeactivatedPlate3 = 1e6; + break; + case BCT_ACTIVATE_PLATE_4: + pwsc->m_tmActivatedPlate4 = tmNow; + pwsc->m_tmDeactivatedPlate4 = 1e6; + break; + case BCT_ACTIVATE_PYRAMID_MORPH_ROOM: + pwsc->m_tmPyramidMorphRoomActivated = tmNow; + break; + } + } + else if (ee.ee_slEvent==EVENTCODE_EDeactivate) + { + switch(m_bctType) + { + case BCT_ACTIVATE_PLATE_1: + pwsc->m_tmDeactivatedPlate1 = tmNow; + break; + case BCT_ACTIVATE_PLATE_2: + pwsc->m_tmDeactivatedPlate2 = tmNow; + break; + case BCT_ACTIVATE_PLATE_3: + pwsc->m_tmDeactivatedPlate3 = tmNow; + break; + case BCT_ACTIVATE_PLATE_4: + pwsc->m_tmDeactivatedPlate4 = tmNow; + break; + } + } + return FALSE; + } + +procedures: + + Main() + { + // init model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_CONTROLLER); + SetModelMainTexture(TEXTURE_CONTROLLER); + + return; + } +}; + diff --git a/Sources/Entities/BloodSpray.es b/Sources/Entities/BloodSpray.es new file mode 100644 index 0000000..2f27e92 --- /dev/null +++ b/Sources/Entities/BloodSpray.es @@ -0,0 +1,130 @@ +603 +%{ +#include "Entities/StdH/StdH.h" +%} + +enum SprayParticlesType { + 0 SPT_NONE "None", // no particles + 1 SPT_BLOOD "Blood", // blood + 2 SPT_BONES "Bones", // bones + 3 SPT_FEATHER "Feather", // feather + 4 SPT_STONES "Stones", // stones + 5 SPT_WOOD "Wood", // wood + 6 SPT_SLIME "Slime", // gizmo/beast slime + 7 SPT_LAVA_STONES "Lava Stones", // lava stones + 8 SPT_ELECTRICITY_SPARKS "Electricity sparks", // electricity sparks + 9 SPT_BEAST_PROJECTILE_SPRAY "Beast projectile spray", // beast projectile explosion sparks + 10 SPT_SMALL_LAVA_STONES "Small Lava Stones", // small lava stones +}; + +// input parameter for spawning a blood spray +event ESpawnSpray { + enum SprayParticlesType sptType, // type of particles + FLOAT fDamagePower, // factor saying how powerfull damage has been + FLOAT fSizeMultiplier, // stretch factor + FLOAT3D vDirection, // dammage direction + CEntityPointer penOwner, // who spawned the spray +}; + +class CBloodSpray: CRationalEntity { +name "Blood Spray"; +thumbnail ""; +features "CanBePredictable"; + +properties: + + 1 enum SprayParticlesType m_sptType = SPT_NONE, // type of particles + 2 FLOAT m_tmStarted = 0.0f, // time when spawned + 3 FLOAT3D m_vDirection = FLOAT3D(0,0,0), // dammage direction + 5 CEntityPointer m_penOwner, // who spawned the spray + 6 FLOAT m_fDamagePower = 1.0f, // power of inflicted damage + 8 FLOATaabbox3D m_boxOwner = FLOATaabbox3D(FLOAT3D(0,0,0), 0.01f), // bounding box of blood spray's owner + 9 FLOAT3D m_vGDir = FLOAT3D(0,0,0), // gravity direction + 10 FLOAT m_fGA = 0.0f, // gravity strength + + +components: + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + +functions: + + // particles + void RenderParticles(void) + { + switch( m_sptType) + { + case SPT_BLOOD: + case SPT_BONES: + case SPT_FEATHER: + case SPT_STONES: + case SPT_WOOD: + case SPT_SLIME: + case SPT_LAVA_STONES: + case SPT_SMALL_LAVA_STONES: + case SPT_BEAST_PROJECTILE_SPRAY: + Particles_BloodSpray(m_sptType, this, m_vGDir, m_fGA, m_boxOwner, m_vDirection, m_tmStarted, m_fDamagePower); + break; + case SPT_ELECTRICITY_SPARKS: + { + Particles_MetalParts(this, m_tmStarted, m_boxOwner, m_fDamagePower); + Particles_DamageSmoke(this, m_tmStarted, m_boxOwner, m_fDamagePower); + Particles_BloodSpray(SPT_BLOOD, this, m_vGDir, m_fGA, m_boxOwner, m_vDirection, m_tmStarted, m_fDamagePower/2.0f); + Particles_ElectricitySparks( this, m_tmStarted, 5.0f, 0.0f, 32); + break; + } + } + }; + +/************************************************************ + * MAIN * + ************************************************************/ + +procedures: + + Main( ESpawnSpray eSpawn) + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + SetPredictable(TRUE); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // setup variables + m_sptType = eSpawn.sptType; + m_vDirection = eSpawn.vDirection; + m_penOwner = eSpawn.penOwner; + m_fDamagePower = eSpawn.fDamagePower; + m_tmStarted = _pTimer->CurrentTick(); + // if owner doesn't exist (could be destroyed in initialization) + if( eSpawn.penOwner->en_pmoModelObject == NULL) + { + // don't do anything + Destroy(); + return; + } + eSpawn.penOwner->en_pmoModelObject->GetCurrentFrameBBox( m_boxOwner); + m_boxOwner.StretchByVector(eSpawn.penOwner->en_pmoModelObject->mo_Stretch*eSpawn.fSizeMultiplier); + if (m_penOwner->GetPhysicsFlags()&EPF_MOVABLE) { + m_vGDir = ((CMovableEntity *)&*m_penOwner)->en_vGravityDir; + m_fGA = ((CMovableEntity *)&*m_penOwner)->en_fGravityA; + } else { + FLOATmatrix3D &m = m_penOwner->en_mRotation; + m_vGDir = FLOAT3D(-m(1,2), -m(2,2), -m(3,2)); + m_fGA = 30.0f; + } + + FLOAT fWaitTime = 2.0f; + if( m_sptType==SPT_ELECTRICITY_SPARKS) + { + fWaitTime = 4.0f; + } + autowait(fWaitTime); + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/Boneman.es b/Sources/Entities/Boneman.es new file mode 100644 index 0000000..e18b983 --- /dev/null +++ b/Sources/Entities/Boneman.es @@ -0,0 +1,385 @@ +305 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Boneman/Boneman.h" +%} + +uses "Entities/EnemyBase"; + +%{ +// info structure +static EntityInfo eiBoneman = { + EIBT_BONES, 250.0f, + 0.0f, 1.9f, 0.0f, // source (eyes) + 0.0f, 1.9f, 0.0f, // target (body) +}; + +#define BONES_HIT 2.8f +#define FIRE_RIGHT_HAND FLOAT3D( 0.25f, 1.5f, 0.0f) +#define FIRE_LEFT_HAND FLOAT3D(-0.25f, 1.5f, 0.0f) +%} + + +class CBoneman : CEnemyBase { +name "Boneman"; +thumbnail "Thumbnails\\Boneman.tbn"; + +properties: + 2 BOOL m_bFistHit = FALSE, // used for close attack + 3 BOOL m_bTouchAnother = FALSE, // another entity touched on far attack + 4 CSoundObject m_soFeet, // for running sound + 5 BOOL m_bRunSoundPlaying = FALSE, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 model MODEL_BONEMAN "Models\\Enemies\\Boneman\\Boneman.mdl", + 2 texture TEXTURE_BONEMAN "Models\\Enemies\\Boneman\\Boneman.tex", + 3 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + +// ************** BONEMAN PARTS ************** + 10 model MODEL_BONEMAN_BODY "Models\\Enemies\\Boneman\\Debris\\Body.mdl", + 11 model MODEL_BONEMAN_HAND "Models\\Enemies\\Boneman\\Debris\\Hand.mdl", + 12 model MODEL_BONEMAN_LEGS "Models\\Enemies\\Boneman\\Debris\\Legs.mdl", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Boneman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Boneman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Boneman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Boneman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Boneman\\Sounds\\Kick.wav", + 55 sound SOUND_PUNCH "Models\\Enemies\\Boneman\\Sounds\\Punch.wav", + 56 sound SOUND_DEATH "Models\\Enemies\\Boneman\\Sounds\\Death.wav", + 57 sound SOUND_RUN "Models\\Enemies\\Boneman\\Sounds\\Run.wav", + +functions: + void Precache(void) { + CEnemyBase::Precache(); + PrecacheSound(SOUND_IDLE ); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_FIRE ); + PrecacheSound(SOUND_KICK ); + PrecacheSound(SOUND_PUNCH); + PrecacheSound(SOUND_DEATH); + PrecacheSound(SOUND_RUN ); + + PrecacheModel(MODEL_BONEMAN_BODY); + PrecacheModel(MODEL_BONEMAN_HAND); + PrecacheModel(MODEL_BONEMAN_LEGS); + + PrecacheClass(CLASS_PROJECTILE, PRT_BONEMAN_FIRE); + }; + + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + if (eDeath.eLastDamage.dmtType==DMT_CLOSERANGE) { + str.PrintF(TRANS("%s was ripped apart by a Kleer"),(const char*) strPlayerName); + } else { + str.PrintF(TRANS("%s was killed by a Kleer"),(const char*) strPlayerName); + } + return str; + } + + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Boneman.txt"); + return fnm; + }; + + /* Entity info */ + void *GetEntityInfo(void) { + return &eiBoneman; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // boneman can't harm boneman + if (!IsOfClass(penInflictor, "Boneman")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + void LeaveStain(BOOL bGrow) + { + // boneman doesn't leave bloody stain + } + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + switch (IRnd()%5) { + case 0: iAnim = BONEMAN_ANIM_WOUNDCRITICAL01; break; + case 1: iAnim = BONEMAN_ANIM_WOUNDCRITICAL02; break; + case 2: iAnim = BONEMAN_ANIM_WOUNDCRITICAL03; break; + case 3: iAnim = BONEMAN_ANIM_FALL01; break; + case 4: iAnim = BONEMAN_ANIM_FALL02; break; + default: ASSERTALWAYS("Boneman unknown damage"); + } + StartModelAnim(iAnim, 0); + DeactivateRunningSound(); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = BONEMAN_ANIM_DEATHTOBACK; break; + case 1: iAnim = BONEMAN_ANIM_DEATHTOFRONT; break; + default: ASSERTALWAYS("Boneman unknown death"); + } + StartModelAnim(iAnim, 0); + DeactivateRunningSound(); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(BONEMAN_COLLISION_BOX_DEATH); + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(BONEMAN_ANIM_STANDLOOP, AOF_LOOPING|AOF_NORESTART); + DeactivateRunningSound(); + }; + void WalkingAnim(void) { + StartModelAnim(BONEMAN_ANIM_WALKLOOP, AOF_LOOPING|AOF_NORESTART); + DeactivateRunningSound(); + }; + void RunningAnim(void) { + StartModelAnim(BONEMAN_ANIM_RUNLOOP, AOF_LOOPING|AOF_NORESTART); + ActivateRunningSound(); + }; + void RotatingAnim(void) { + StartModelAnim(BONEMAN_ANIM_WALKLOOP, AOF_LOOPING|AOF_NORESTART); + DeactivateRunningSound(); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + + // running sounds + void ActivateRunningSound(void) + { + if (!m_bRunSoundPlaying) { + PlaySound(m_soFeet, SOUND_RUN, SOF_3D|SOF_LOOP); + m_bRunSoundPlaying = TRUE; + } + } + void DeactivateRunningSound(void) + { + m_soFeet.Stop(); + m_bRunSoundPlaying = FALSE; + } + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + // spawn body parts + void BlowUp(void) { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + + vNormalizedDamage *= 0.75f; + + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + + // spawn debris + Debris_Begin(EIBT_BONES, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 5.0f, 2.0f); + + Debris_Spawn(this, this, MODEL_BONEMAN_BODY, TEXTURE_BONEMAN, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_BONEMAN_HAND, TEXTURE_BONEMAN, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_BONEMAN_HAND, TEXTURE_BONEMAN, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_BONEMAN_LEGS, TEXTURE_BONEMAN, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + }; + + + + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire { + // fire projectile + StartModelAnim(BONEMAN_ANIM_ATTACKCLOSELOOP, 0); + DeactivateRunningSound(); + autowait(0.35f); + ShootProjectile(PRT_BONEMAN_FIRE, FIRE_RIGHT_HAND, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.45f); + ShootProjectile(PRT_BONEMAN_FIRE, FIRE_LEFT_HAND, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(FRnd()/3+0.6f); + + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + // hit + if (CalcDist(m_penEnemy) < BONES_HIT) { + jump HitWithBones(); + + // jump + } else if (CalcDist(m_penEnemy) < 10.0f) { + jump JumpOnEnemy(); + } + + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.5f; + return EReturn(); + }; + + // jump on enemy + JumpOnEnemy(EVoid) { + StartModelAnim(BONEMAN_ANIM_ATTACKFAR, 0); + DeactivateRunningSound(); + + // jump + FLOAT3D vDir = (m_penEnemy->GetPlacement().pl_PositionVector - + GetPlacement().pl_PositionVector).Normalize(); + vDir *= !GetRotationMatrix(); + vDir *= m_fCloseRunSpeed*1.5f; + vDir(2) = 2.5f; + SetDesiredTranslation(vDir); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + + // animation - IGNORE DAMAGE WOUND - + SpawnReminder(this, 0.5f, 0); + m_iChargeHitAnimation = BONEMAN_ANIM_ATTACKFAR; + m_fChargeHitDamage = 20.0f; + m_fChargeHitAngle = 0.0f; + m_fChargeHitSpeed = 15.0f; + autocall CEnemyBase::ChargeHitEnemy() EReturn; + autowait(0.3f); + return EReturn(); + }; + + // hit with bones + HitWithBones(EVoid) { + // attack with bones + StartModelAnim(BONEMAN_ANIM_ATTACKCLOSELOOP, 0); + DeactivateRunningSound(); + + // right hand + m_bFistHit = FALSE; + autowait(0.35f); + if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + // damage enemy + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 10.0f, FLOAT3D(0, 0, 0), vDirection); + // push target left + FLOAT3D vSpeed; + GetHeadingDirection(AngleDeg(90.0f), vSpeed); + vSpeed = vSpeed * 5.0f; + KickEntity(m_penEnemy, vSpeed); + } + + // left hand + m_bFistHit = FALSE; + autowait(0.25f); + if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 10.0f, FLOAT3D(0, 0, 0), vDirection); + // push target left + FLOAT3D vSpeed; + GetHeadingDirection(AngleDeg(-90.0f), vSpeed); + vSpeed = vSpeed * 5.0f; + KickEntity(m_penEnemy, vSpeed); + } + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(125.0f); + m_fMaxHealth = 125.0f; + en_fDensity = 2000.0f; + + // set your appearance + SetModel(MODEL_BONEMAN); + SetModelMainTexture(TEXTURE_BONEMAN); + StandingAnim(); + m_sptType = SPT_BONES; + // setup moving speed + m_fWalkSpeed = FRnd() + 2.5f; + m_aWalkRotateSpeed = FRnd()*25.0f + 45.0f; + m_fAttackRunSpeed = FRnd()*3.0f + 10.0f; + m_aAttackRotateSpeed = FRnd()*200 + 600.0f; + m_fCloseRunSpeed = FRnd() + 13.0f; + m_aCloseRotateSpeed = FRnd()*100 + 1000.0f; + // setup attack distances + m_fAttackDistance = 100.0f; + m_fCloseDistance = 30.0f; + m_fStopDistance = 2.0f; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 2.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 70.0f; + m_fBodyParts = 4; + m_fDamageWounded = 80.0f; + m_iScore = 1000; + if (m_fStepHeight==-1) { + m_fStepHeight = 4.0f; + } + + // set stretch factors for height and width + CEnemyBase::StretchModel(); + m_soFeet.Set3DParameters(80.0f, 5.0f, 1.0f, 1.0f); + m_bRunSoundPlaying = FALSE; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Bouncer.es b/Sources/Entities/Bouncer.es new file mode 100644 index 0000000..eda4a2a --- /dev/null +++ b/Sources/Entities/Bouncer.es @@ -0,0 +1,65 @@ +105 +%{ +#include "Entities/StdH/StdH.h" +%} + +%{ + +extern DECL_DLL void JumpFromBouncer(CEntity *penToBounce, CEntity *penBouncer) +{ + CEntity *pen = penToBounce; + CBouncer *pbo = (CBouncer *)penBouncer; + // if it is a movable model and some time has passed from the last jump + if ( (pen->GetRenderType()==CEntity::RT_MODEL) && + (pen->GetPhysicsFlags()&EPF_MOVABLE) ) { + CMovableEntity *pmen = (CMovableEntity *)pen; + if (pmen->en_penReference==NULL) { + return; + } + // give it speed + FLOAT3D vDir; + AnglesToDirectionVector(pbo->m_aDirection, vDir); + pmen->FakeJump(pmen->en_vIntendedTranslation, vDir, pbo->m_fSpeed, + -pbo->m_fParallelComponentMultiplier, pbo->m_fNormalComponentMultiplier, pbo->m_fMaxExitSpeed, pbo->m_tmControl); + } +} + +%} + +class CBouncer : CRationalEntity { +name "Bouncer"; +thumbnail "Thumbnails\\Bouncer.tbn"; +features "HasName"; + +properties: + 1 CTString m_strName "Name" 'N' = "Bouncer", + 2 CTString m_strDescription = "", + + 4 FLOAT m_fSpeed "Speed [m/s]" 'S' = 20.0f, + 5 ANGLE3D m_aDirection "Direction" 'D' = ANGLE3D(0,90,0), + 6 FLOAT m_tmControl "Control time" 'T' = 5.0f, + 7 BOOL m_bEntrySpeed = TRUE, + 10 FLOAT m_fMaxExitSpeed "Max exit speed" 'M' = 200.0f, + 12 FLOAT m_fNormalComponentMultiplier "Normal component multiplier" 'O' = 1.0f, + 13 FLOAT m_fParallelComponentMultiplier "Parallel component multiplier" 'P' = 0.0f, + +components: +functions: +procedures: + Main() { + // declare yourself as a brush + InitAsBrush(); + SetPhysicsFlags(EPF_BRUSH_FIXED|EPF_NOIMPACT); + SetCollisionFlags(ECF_BRUSH); + + // if old flag "entry speed" has been reset + if (!m_bEntrySpeed) + { + // kill normal component by default (same behaviour by default) + m_fNormalComponentMultiplier = 0.0f; + m_bEntrySpeed = TRUE; + } + return; + } +}; + \ No newline at end of file diff --git a/Sources/Entities/Bullet.es b/Sources/Entities/Bullet.es new file mode 100644 index 0000000..a9347ed --- /dev/null +++ b/Sources/Entities/Bullet.es @@ -0,0 +1,420 @@ +502 +%{ +#include "Entities/StdH/StdH.h" +#define BLOOD_SPILL_RED RGBAToColor(250,20,20,255) +#define BLOOD_SPILL_GREEN RGBAToColor(0,250,0,255) +%} + +uses "Entities/BasicEffects"; +uses "Engine/Classes/MovableEntity"; + + +// input parameters for bullet +event EBulletInit { + CEntityPointer penOwner, // who launched it + FLOAT fDamage, // damage +}; + +// hit enum +enum BulletHitType { + 0 BHT_NONE "", // none + 1 BHT_FLESH "", // flesh + 2 BHT_BRUSH_STONE "", // brush stone + 3 BHT_BRUSH_SAND "", // brush sand + 4 BHT_BRUSH_WATER "", // brush water + 5 BHT_BRUSH_UNDER_WATER "", // brush under water + 6 BHT_ACID "", // acid + 7 BHT_BRUSH_RED_SAND "", // brush red sand +}; + +%{ +void CBullet_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINSTONE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINSAND); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINREDSAND); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINWATER); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINSTONENOSOUND); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINSANDNOSOUND); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINREDSANDNOSOUND); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETSTAINWATERNOSOUND); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSPILL); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BULLETTRAIL); +} +%} + +class export CBullet : CEntity { +name "Bullet"; +thumbnail ""; +features "ImplementsOnPrecache"; + +properties: + 1 CEntityPointer m_penOwner, // entity which owns it + 2 FLOAT m_fDamage = 0.0f, // damage + 3 FLOAT3D m_vTarget = FLOAT3D(0,0,0), // bullet target point in space + 4 FLOAT3D m_vTargetCopy = FLOAT3D(0,0,0), // copy of bullet target point in space for jitter + 6 FLOAT3D m_vHitPoint = FLOAT3D(0,0,0), // hit point + 8 INDEX m_iBullet = 0, // bullet for lerped launch + 9 enum DamageType m_EdtDamage = DMT_BULLET, // damage type + 10 FLOAT m_fBulletSize = 0.0f, // bullet can have radius, for hitting models only + +components: + 1 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl" + +functions: + +/************************************************************ + * BULLET LAUNCH * + ************************************************************/ + // set bullet damage + void SetDamage(FLOAT fDamage) { + m_fDamage = fDamage; + }; + + // calc jitter target + void CalcTarget(FLOAT fRange) { + // destination in bullet direction + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, m_vTarget); + m_vTarget *= fRange; + m_vTarget += GetPlacement().pl_PositionVector; + m_vTargetCopy = m_vTarget; + }; + + void CalcTarget(CEntity *pen, FLOAT fRange) { + FLOAT3D vTarget; + + // target body + EntityInfo *peiTarget = (EntityInfo*) (pen->GetEntityInfo()); + GetEntityInfoPosition(pen, peiTarget->vTargetCenter, vTarget); + + // calculate + m_vTarget = (vTarget - GetPlacement().pl_PositionVector).Normalize(); + m_vTarget *= fRange; + m_vTarget += GetPlacement().pl_PositionVector; + m_vTargetCopy = m_vTarget; + }; + + // calc jitter target - !!! must call CalcTarget first !!! + void CalcJitterTarget(FLOAT fR) { + FLOAT3D vJitter; +/* My Sphere + FLOAT fXZ = FRnd()*360.0f; + FLOAT fXY = FRnd()*360.0f; + + // sphere + fR *= FRnd(); + vJitter(1) = CosFast(fXZ)*CosFast(fXY)*fR; + vJitter(2) = CosFast(fXZ)*SinFast(fXY)*fR; + vJitter(3) = SinFast(fXZ)*fR;*/ +// comp graphics algorithms sphere + FLOAT fZ = FRnd()*2.0f - 1.0f; + FLOAT fA = FRnd()*360.0f; + FLOAT fT = Sqrt(1-(fZ*fZ)); + vJitter(1) = fT * CosFast(fA); + vJitter(2) = fT * SinFast(fA); + vJitter(3) = fZ; + vJitter = vJitter*fR*FRnd(); + + // target + m_vTarget = m_vTargetCopy + vJitter; + }; + + // calc jitter target asymetric - !!! must call CalcTarget first !!! + void CalcJitterTargetFixed(FLOAT fX, FLOAT fY, FLOAT fJitter) { + FLOAT fRndX = FRnd()*2.0f - 1.0f; + FLOAT fRndY = FRnd()*2.0f - 1.0f; + FLOAT3D vX, vY; + const FLOATmatrix3D &m=GetRotationMatrix(); + vX(1) = m(1,1); vX(2) = m(2,1); vX(3) = m(3,1); + vY(1) = m(1,2); vY(2) = m(2,2); vY(3) = m(3,2); + // target + m_vTarget = m_vTargetCopy + (vX*(fX+fRndX*fJitter)) + (vY*(fY+fRndY*fJitter)); + }; + + // launch one bullet + void LaunchBullet(BOOL bSound, BOOL bTrail, BOOL bHitFX) + { + // cast a ray to find bullet target + CCastRay crRay( m_penOwner, GetPlacement().pl_PositionVector, m_vTarget); + crRay.cr_bHitPortals = TRUE; + crRay.cr_bHitTranslucentPortals = TRUE; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + crRay.cr_bPhysical = FALSE; + crRay.cr_fTestR = m_fBulletSize; + FLOAT3D vHitDirection; + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, vHitDirection); + + INDEX ctCasts = 0; + while( ctCasts<10) + { + if(ctCasts == 0) + { + // perform first cast + GetWorld()->CastRay(crRay); + } + else + { + // next casts + GetWorld()->ContinueCast(crRay); + } + ctCasts++; + + // stop casting if nothing hit + if (crRay.cr_penHit==NULL) + { + break; + } + // apply damage + InflictDirectDamage(crRay.cr_penHit, m_penOwner, m_EdtDamage, m_fDamage, + crRay.cr_vHit, vHitDirection); + + m_vHitPoint = crRay.cr_vHit; + + // if brush hitted + if (crRay.cr_penHit->GetRenderType()==RT_BRUSH && crRay.cr_pbpoBrushPolygon!=NULL) + { + CBrushPolygon *pbpo = crRay.cr_pbpoBrushPolygon; + FLOAT3D vHitNormal = FLOAT3D(pbpo->bpo_pbplPlane->bpl_plAbsolute); + // obtain surface type + INDEX iSurfaceType = pbpo->bpo_bppProperties.bpp_ubSurfaceType; + BulletHitType bhtType = BHT_BRUSH_STONE; + // get content type + INDEX iContent = pbpo->bpo_pbscSector->GetContentType(); + CContentType &ct = GetWorld()->wo_actContentTypes[iContent]; + // if this is under water polygon + if( ct.ct_ulFlags&CTF_BREATHABLE_GILLS) + { + // if we hit water surface + if( iSurfaceType==SURFACE_WATER) + { + vHitNormal = -vHitNormal; + bhtType=BHT_BRUSH_WATER; + } + // if we hit stone under water + else + { + bhtType=BHT_BRUSH_UNDER_WATER; + } + } + else + { + if( iSurfaceType==SURFACE_SAND) {bhtType=BHT_BRUSH_SAND;} + if( iSurfaceType==SURFACE_RED_SAND) {bhtType=BHT_BRUSH_RED_SAND;} + if( iSurfaceType==SURFACE_WATER) {bhtType=BHT_BRUSH_WATER;} + } + // spawn hit effect + BOOL bPassable = pbpo->bpo_ulFlags & (BPOF_PASSABLE|BPOF_SHOOTTHRU); + if (!bPassable || iSurfaceType==SURFACE_WATER) { + SpawnHitTypeEffect(bhtType, bSound, vHitNormal, crRay.cr_vHit, vHitDirection, FLOAT3D(0.0f, 0.0f, 0.0f)); + } + if(!bPassable) { + break; + } + // if not brush + } else { + + // if flesh entity + if (crRay.cr_penHit->GetEntityInfo()!=NULL) { + if( ((EntityInfo*)crRay.cr_penHit->GetEntityInfo())->Eeibt == EIBT_FLESH) + { + CEntity *penOfFlesh = crRay.cr_penHit; + FLOAT3D vHitNormal = (GetPlacement().pl_PositionVector-m_vTarget).Normalize(); + FLOAT3D vOldHitPos = crRay.cr_vHit; + FLOAT3D vDistance; + + // look behind the entity (for back-stains) + GetWorld()->ContinueCast(crRay); + if( crRay.cr_penHit!=NULL && crRay.cr_pbpoBrushPolygon!=NULL && + crRay.cr_penHit->GetRenderType()==RT_BRUSH) + { + vDistance = crRay.cr_vHit-vOldHitPos; + vHitNormal = FLOAT3D(crRay.cr_pbpoBrushPolygon->bpo_pbplPlane->bpl_plAbsolute); + } + else + { + vDistance = FLOAT3D(0.0f, 0.0f, 0.0f); + vHitNormal = FLOAT3D(0,0,0); + } + + if(IsOfClass(penOfFlesh, "Gizmo") || + IsOfClass(penOfFlesh, "Beast")) + { + // spawn green blood hit spill effect + SpawnHitTypeEffect(BHT_ACID, bSound, vHitNormal, crRay.cr_vHit, vHitDirection, vDistance); + } + else + { + // spawn red blood hit spill effect + SpawnHitTypeEffect(BHT_FLESH, bSound, vHitNormal, crRay.cr_vHit, vHitDirection, vDistance); + } + break; + } + } + + // stop casting ray if not brush + break; + } + } + + if( bTrail) + { + SpawnTrail(); + } + }; + + // destroy yourself + void DestroyBullet(void) { + Destroy(); + }; + + + +/************************************************************ + * EFFECTS * + ************************************************************/ + // spawn effect from hit type + void SpawnHitTypeEffect(enum BulletHitType bhtType, BOOL bSound, FLOAT3D vHitNormal, FLOAT3D vHitPoint, + FLOAT3D vDirection, FLOAT3D vDistance) + { + switch (bhtType) + { + case BHT_BRUSH_STONE: + case BHT_BRUSH_SAND: + case BHT_BRUSH_RED_SAND: + case BHT_BRUSH_WATER: + case BHT_BRUSH_UNDER_WATER: + { + // bullet stain + ESpawnEffect ese; + if( bSound) + { + if( bhtType == BHT_BRUSH_STONE) {ese.betType = BET_BULLETSTAINSTONE;}; + if( bhtType == BHT_BRUSH_SAND) {ese.betType = BET_BULLETSTAINSAND;}; + if( bhtType == BHT_BRUSH_RED_SAND) {ese.betType = BET_BULLETSTAINREDSAND;}; + if( bhtType == BHT_BRUSH_WATER) {ese.betType = BET_BULLETSTAINWATER;}; + if( bhtType == BHT_BRUSH_UNDER_WATER) {ese.betType = BET_BULLETSTAINUNDERWATER;}; + } + else + { + if( bhtType == BHT_BRUSH_STONE) {ese.betType = BET_BULLETSTAINSTONENOSOUND;}; + if( bhtType == BHT_BRUSH_SAND) {ese.betType = BET_BULLETSTAINSANDNOSOUND;}; + if( bhtType == BHT_BRUSH_RED_SAND) {ese.betType = BET_BULLETSTAINREDSANDNOSOUND;}; + if( bhtType == BHT_BRUSH_WATER) {ese.betType = BET_BULLETSTAINWATERNOSOUND;}; + if( bhtType == BHT_BRUSH_UNDER_WATER) {ese.betType = BET_BULLETSTAINUNDERWATERNOSOUND;}; + } + + ese.vNormal = vHitNormal; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + FLOAT3D vDirection = (vHitPoint-GetPlacement().pl_PositionVector).Normalize(); + // reflect direction arround normal + FLOAT fNx = vHitNormal(1); + FLOAT fNy = vHitNormal(2); + FLOAT fNz = vHitNormal(3); + FLOAT fNV = fNx*vDirection(1) + fNy*vDirection(2) + fNz*vDirection(3); + FLOAT fRVx = vDirection(1) - 2*fNx*fNV; + FLOAT fRVy = vDirection(2) - 2*fNy*fNV; + FLOAT fRVz = vDirection(3) - 2*fNz*fNV; + ese.vStretch = FLOAT3D( fRVx, fRVy, fRVz); + SpawnEffect(vHitPoint, ese); + break; + } + case BHT_FLESH: + case BHT_ACID: + { + // spawn bullet entry wound + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + // if there is exit wound blood spill place + FLOAT fDistance = vDistance.Length(); + if( fDistance>0.01f && !(IRnd()%2) ) + { + // spawn bullet exit wound blood patch + ese.betType = BET_BLOODSPILL; + if( bhtType == BHT_ACID) + { + ese.colMuliplier = BLOOD_SPILL_GREEN; + } + else + { + ese.colMuliplier = BLOOD_SPILL_RED; + } + ese.vNormal = vHitNormal; + if (fDistance<25.0f) + { + GetNormalComponent( vDistance/fDistance, vHitNormal, ese.vDirection); + FLOAT fLength = ese.vDirection.Length(); + fLength = Clamp( fLength*3, 1.0f, 3.0f); + fDistance = Clamp( log10(fDistance), 0.5, 2.0); + ese.vStretch = FLOAT3D( fDistance, fLength*fDistance, 1.0f); + SpawnEffect(vHitPoint, ese); + } + } + break; + } + } + }; + // spawn trail of this bullet + void SpawnTrail(void) + { + // get bullet path positions + const FLOAT3D &v0 = GetPlacement().pl_PositionVector; + const FLOAT3D &v1 = m_vHitPoint; + // calculate distance + FLOAT3D vD = v1-v0; + FLOAT fD = vD.Length(); + // if too short + if (fD<1.0f) { + // no trail + return; + } + + // length must be such that it doesn't get out of path + FLOAT fLen = Min(20.0f, fD); + // position is random, but it must not make trail go out of path + FLOAT3D vPos; + if (fLenInitialize(eSpawnEffect); + }; + +procedures: + + Main(EBulletInit eInit) + { + // remember the initial parameters + ASSERT(eInit.penOwner!=NULL); + m_penOwner = eInit.penOwner; + m_fDamage = eInit.fDamage; + + InitAsVoid(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // for lerped launch + m_iBullet = 0; + return; + }; +}; \ No newline at end of file diff --git a/Sources/Entities/Camera.es b/Sources/Entities/Camera.es new file mode 100644 index 0000000..aa547bb --- /dev/null +++ b/Sources/Entities/Camera.es @@ -0,0 +1,443 @@ +220 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/WorldLink"; +uses "Entities/Player"; +uses "Entities/CameraMarker"; + +class CCamera : CMovableModelEntity +{ +name "Camera"; +thumbnail "Thumbnails\\Camera.tbn"; +features "HasName", "IsTargetable", "IsImportant"; + + +properties: + + 1 FLOAT m_tmTime "Time" 'E' = 5.0f, // how long to show the scene + 2 FLOAT m_fFOV "FOV" 'F' = 90.0f, // camera fov + 5 FLOAT m_fLastFOV = 90.0f, + 3 CEntityPointer m_penTarget "Target" 'T' COLOR(C_lBLUE|0xFF), + 4 CTString m_strName "Name" 'N' = "Camera", + 6 CEntityPointer m_penOnBreak "OnBreak" 'B' COLOR(C_lRED|0xFF), + 7 BOOL m_bWideScreen "WideScreen" 'W' = TRUE, + + 10 FLOAT m_tmAtMarker = 0.0f, // time when current marker was reached + 11 FLOAT m_tmDelta = 0.0f, // time to reach next marker + 13 FLOAT3D m_vPNp0 = FLOAT3D(0,0,0), + 14 FLOAT3D m_vPNp1 = FLOAT3D(0,0,0), + 15 FLOAT3D m_vTNp0 = FLOAT3D(0,0,0), + 16 FLOAT3D m_vTNp1 = FLOAT3D(0,0,0), + 17 FLOAT m_fFOVp0 = 0.0f, + 18 FLOAT m_fFOVp1 = 0.0f, + 19 FLOAT m_fTFOVp0 = 0.0f, + 20 FLOAT m_fTFOVp1 = 0.0f, + 31 FLOATquat3D m_qPNp0 = FLOATquat3D(0,0,0,0), + 32 FLOATquat3D m_qPNp1 = FLOATquat3D(0,0,0,0), + 33 FLOATquat3D m_qANp0 = FLOATquat3D(0,0,0,0), + 34 FLOATquat3D m_qANp1 = FLOATquat3D(0,0,0,0), + + 40 CEntityPointer m_penLast, // previous marker + 41 CEntityPointer m_penPlayer, // player viewing this camera + 42 CTString m_strDescription = "", + 43 BOOL m_bStopMoving = FALSE, // stop moving camera on next target + + 50 COLOR m_colFade0 = 0, // camera fading color + 51 COLOR m_colFade1 = 0, + 52 BOOL m_bMoving = FALSE, // set while moving + +components: + + 1 model MODEL_CAMERA "Models\\Editor\\Camera.mdl", + 2 texture TEXTURE_CAMERA "Models\\Editor\\Camera.tex" + + +functions: + + // render particles + void RenderParticles(void) + { + if (Particle_GetViewer()==this) { + Particles_ViewerLocal(this); + } + } + + // Check if entity is moved on a route set up by its targets + BOOL MovesByTargetedRoute( CTString &strTargetProperty) const + { + strTargetProperty = "Target"; + return TRUE; + } + + // Check if entity can drop marker for making linked route + BOOL DropsMarker( CTFileName &fnmMarkerClass, CTString &strTargetProperty) const + { + fnmMarkerClass = CTFILENAME( "Classes\\CameraMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + + // returns camera description + const CTString &GetDescription(void) const + { + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s",(const char*) m_penTarget->GetName()); + } else { + ((CTString&)m_strDescription).PrintF("->"); + } + return m_strDescription; + } + + + CPlacement3D GetLerpedPlacement(void) const + { + FLOAT fLerpFactor; + if (IsPredictor()) { + fLerpFactor = _pTimer->GetLerpFactor(); + } else { + fLerpFactor = _pTimer->GetLerpFactor2(); + } + return LerpPlacementsPrecise(en_plLastPlacement, en_plPlacement, fLerpFactor); + //return CMovableEntity::GetLerpedPlacement(); + } + + void PreMoving() + { + // remember old placement for lerping + en_plLastPlacement = en_plPlacement; + } + + + void DoMoving() + { + if (!m_bMoving) { + return; + } + // read current tick + FLOAT tmCurrent = _pTimer->CurrentTick(); + // lerping is initially enabled + BOOL bLerping = TRUE; + + // if we hit a marker + if( tmCurrent > (m_tmAtMarker+m_tmDelta - _pTimer->TickQuantum*3/2)) + { + // get markers + CCameraMarker *pcmNm1 = &(CCameraMarker&)*m_penLast; + CCameraMarker *pcmNp0 = &(CCameraMarker&)*m_penTarget; + CCameraMarker *pcmNp1 = &(CCameraMarker&)*pcmNp0->m_penTarget; + CCameraMarker *pcmNp2 = &(CCameraMarker&)*pcmNp1->m_penTarget; + + // repeat + FOREVER { + // if there is a trigger at the hit marker + if (pcmNp0->m_penTrigger!=NULL) { + // trigger it + SendToTarget(pcmNp0->m_penTrigger, EET_TRIGGER, m_penPlayer); + } + + // if the marker should not be skipped + if (!pcmNp0->m_bSkipToNext) { + // stop skipping + break; + } + + // go to next marker immediately + pcmNm1 = pcmNp0; + pcmNp0 = pcmNp1; + pcmNp1 = pcmNp2; + pcmNp2 = (CCameraMarker*)&*pcmNp2->m_penTarget; + // disable lerping + bLerping = FALSE; + } + + // update markers for next interval + m_penTarget = pcmNp1; + m_penLast = pcmNp0; + + // get markers + CCameraMarker &cmNm1 = *pcmNm1; + CCameraMarker &cmNp0 = *pcmNp0; + CCameraMarker &cmNp1 = *pcmNp1; + CCameraMarker &cmNp2 = *pcmNp2; + + // get positions from four markers + const FLOAT3D &vPNm1 = cmNm1.GetPlacement().pl_PositionVector; + const FLOAT3D &vPNp0 = cmNp0.GetPlacement().pl_PositionVector; + const FLOAT3D &vPNp1 = cmNp1.GetPlacement().pl_PositionVector; + const FLOAT3D &vPNp2 = cmNp2.GetPlacement().pl_PositionVector; + ANGLE3D aPNm1 = cmNm1.GetPlacement().pl_OrientationAngle; + ANGLE3D aPNp0 = cmNp0.GetPlacement().pl_OrientationAngle; + ANGLE3D aPNp1 = cmNp1.GetPlacement().pl_OrientationAngle; + ANGLE3D aPNp2 = cmNp2.GetPlacement().pl_OrientationAngle; + FLOAT fFOVm1 = cmNm1.m_fFOV; + FLOAT fFOVp0 = cmNp0.m_fFOV; + FLOAT fFOVp1 = cmNp1.m_fFOV; + FLOAT fFOVp2 = cmNp2.m_fFOV; + m_colFade0 = cmNp0.m_colFade; + m_colFade1 = cmNp1.m_colFade; + + // find quaternions for rotations + FLOATquat3D qPNm1; qPNm1.FromEuler(aPNm1); + FLOATquat3D qPNp0; qPNp0.FromEuler(aPNp0); + FLOATquat3D qPNp1; qPNp1.FromEuler(aPNp1); + FLOATquat3D qPNp2; qPNp2.FromEuler(aPNp2); + + // make all angles between quaternion pairs acute + if( qPNm1%qPNp0<0 ) { + qPNp0 = -qPNp0; + } + if( qPNp0%qPNp1<0 ) { + qPNp1 = -qPNp1; + } + if( qPNp1%qPNp2<0 ) { + qPNp2 = -qPNp2; + } + + // update time and position + m_tmAtMarker = m_tmAtMarker+m_tmDelta; + m_tmDelta = cmNp0.m_fDeltaTime; + m_vPNp0 = vPNp0; + m_vPNp1 = vPNp1; + m_fFOVp0 = fFOVp0; + m_fFOVp1 = fFOVp1; + m_qPNp0 = qPNp0; + m_qPNp1 = qPNp1; + + // determine delta time multipliers + FLOAT tmDNm1 = cmNm1.m_fDeltaTime; + FLOAT tmDNp0 = cmNp0.m_fDeltaTime; + FLOAT tmDNp1 = cmNp1.m_fDeltaTime; + FLOAT fD0 = 2*tmDNp0 / (tmDNm1+tmDNp0); + FLOAT fD1 = 2*tmDNp0 / (tmDNp0+tmDNp1); + + // determine biases, tensions and continuities + FLOAT fBNp0 = cmNp0.m_fBias; + FLOAT fTNp0 = cmNp0.m_fTension; + FLOAT fCNp0 = cmNp0.m_fContinuity; + FLOAT fBNp1 = cmNp1.m_fBias; + FLOAT fTNp1 = cmNp1.m_fTension; + FLOAT fCNp1 = cmNp1.m_fContinuity; + + FLOAT fF00 = (1-fTNp0)*(1-fCNp0)*(1-fBNp0) / 2; + FLOAT fF01 = (1-fTNp0)*(1+fCNp0)*(1+fBNp0) / 2; + FLOAT fF10 = (1-fTNp1)*(1+fCNp1)*(1-fBNp1) / 2; + FLOAT fF11 = (1-fTNp1)*(1-fCNp1)*(1+fBNp1) / 2; + + // find tangents for translation + m_vTNp0 = ( (vPNp1-vPNp0) * fF00 + (vPNp0-vPNm1) * fF01) * fD0; + m_vTNp1 = ( (vPNp2-vPNp1) * fF10 + (vPNp1-vPNp0) * fF11) * fD1; + + // find tangents for FOV + m_fTFOVp0 = ( (fFOVp1-fFOVp0) * fF00 + (fFOVp0-fFOVm1) * fF01) * fD0; + m_fTFOVp1 = ( (fFOVp2-fFOVp1) * fF10 + (fFOVp1-fFOVp0) * fF11) * fD1; + + // find tangents for rotation + FLOATquat3D qTNp0, qTNp1; + qTNp0 = ( Log(qPNp0.Inv()*qPNp1) * fF00 + Log(qPNm1.Inv()*qPNp0) * fF01) * fD0; + qTNp1 = ( Log(qPNp1.Inv()*qPNp2) * fF10 + Log(qPNp0.Inv()*qPNp1) * fF11) * fD1; + + // find squad parameters + m_qANp0 = qPNp0*Exp( (qTNp0 - Log(qPNp0.Inv()*qPNp1))/2 ); + m_qANp1 = qPNp1*Exp( (Log(qPNp0.Inv()*qPNp1) - qTNp1)/2 ); + + // check for stop moving + if( cmNp0.m_bStopMoving) { + m_bStopMoving = TRUE; + } + } + + // calculate the parameter value and hermit basis + FLOAT fT = (tmCurrent - m_tmAtMarker) / m_tmDelta; + FLOAT fH0 = 2*fT*fT*fT - 3*fT*fT + 1; + FLOAT fH1 = -2*fT*fT*fT + 3*fT*fT; + FLOAT fH2 = fT*fT*fT - 2*fT*fT + fT; + FLOAT fH3 = fT*fT*fT - fT*fT; + + // interpolate position, rotation and fov + FLOAT3D vPos = m_vPNp0*fH0 + m_vPNp1*fH1 + m_vTNp0*fH2 + m_vTNp1*fH3; + FLOAT fFOV = m_fFOVp0*fH0 + m_fFOVp1*fH1 + m_fTFOVp0*fH2 + m_fTFOVp1*fH3; + FLOATquat3D qRot = Squad(fT, m_qPNp0, m_qPNp1, m_qANp0, m_qANp1); + FLOATmatrix3D mRot; + qRot.ToMatrix(mRot); + + // just cache near polygons for various engine needs + en_vNextPosition = vPos; + en_mNextRotation = mRot; + CacheNearPolygons(); + + // set new placement + CPlacement3D plNew; + plNew.pl_PositionVector = vPos; + DecomposeRotationMatrixNoSnap(plNew.pl_OrientationAngle, mRot); + SetPlacement_internal(plNew, mRot, TRUE); + // if lerping is disabled + if (!bLerping) { + // make last placement same as this one + en_plLastPlacement = en_plPlacement; + } + // set new fov + m_fLastFOV = m_fFOV; + m_fFOV = fFOV; + } + + + void PostMoving() + { + if (!m_bMoving) { + return; + } + // + if( m_bStopMoving) { + m_bMoving = FALSE; + // mark for removing from list of movers + en_ulFlags |= ENF_INRENDERING; + SendEvent( EStop()); + } + } + + +procedures: + + // routine for playing static camera + PlayStaticCamera() + { + m_bMoving = FALSE; + ECameraStart eStart; + eStart.penCamera = this; + m_penPlayer->SendEvent(eStart); + autowait(m_tmTime); + ECameraStop eStop; + eStop.penCamera=this; + m_penPlayer->SendEvent(eStop); + return; + } + + + // routine for playing movable camera + PlayMovingCamera() + { + // init camera + ECameraStart eStart; + eStart.penCamera = this; + m_penPlayer->SendEvent(eStart); + + // check all markers for correct type and numbers + INDEX ctMarkers=1; + INDEX ctNonSkipped=0; + CCameraMarker *pcm0 = (CCameraMarker*)&*m_penTarget; + CCameraMarker *pcm = (CCameraMarker*)&*pcm0->m_penTarget; + // loop thru markers + while( pcm!=NULL && pcm->m_penTarget!=pcm0) + { + pcm = (CCameraMarker*)&*pcm->m_penTarget; + if (pcm==NULL) { + WarningMessage( "Movable camera - broken link!"); + return; + } + if (!pcm->m_bSkipToNext) { + ctNonSkipped++; + } + ctMarkers++; + if (ctMarkers>500) { + WarningMessage( "Movable camera - invalid marker loop!"); + return; + } + } + // check if we have enough markers to do smooth interpolation + if( ctMarkers<2) { + WarningMessage( "Movable camera requires at least 2 markers in order to work!"); + return; + } + // check if we have enough markers to do smooth interpolation + if( ctNonSkipped<1) { + WarningMessage( "Movable camera requires at least 1 non-skipped marker!"); + return; + } + + // prepare internal variables + FLOAT tmCurrent = _pTimer->CurrentTick(); + m_tmAtMarker = tmCurrent; + m_tmDelta = 0.0f; + m_bStopMoving = FALSE; + m_penLast = pcm; // keep last marker + ASSERT( pcm->m_penTarget == m_penTarget); + pcm = (CCameraMarker*)&*m_penTarget; + m_colFade0 = m_colFade1 = pcm->m_colFade; + + // register camera as movable entity + AddToMovers(); + m_bMoving = TRUE; + + // roll, baby, roll ... + wait() { + on( EStop) : { + ECameraStop eStop; + eStop.penCamera=this; + m_penPlayer->SendEvent(eStop); + return; + } + otherwise() : { + resume; + } + } + + // all done for now + return; + } + + + // determine camera type and jump to corresponding routine + PlayCamera() + { + // eventually add to movers list + CCameraMarker &cm = (CCameraMarker&)*m_penTarget; + // if we have at least one marker + if( &cm!=NULL) { + // treat camera as movable + jump PlayMovingCamera(); + // if there isn't any markers + } else { + // treat camera as fixed + jump PlayStaticCamera(); + } + } + + + Main() + { + // init as model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MOVABLE); + SetCollisionFlags(ECF_CAMERA); + // set appearance + FLOAT fSize = 5.0f; + GetModelObject()->mo_Stretch = FLOAT3D(fSize, fSize, fSize); + SetModel(MODEL_CAMERA); + SetModelMainTexture(TEXTURE_CAMERA); + m_fLastFOV = m_fFOV; + + if( m_penTarget!=NULL && !IsOfClass( m_penTarget, "Camera Marker")) { + WarningMessage( "Entity '%s' is not of Camera Marker class!",(const char*) m_penTarget->GetName()); + m_penTarget = NULL; + } + + while(TRUE) + { + wait() { + on (ETrigger eTrigger) : { + if( IsDerivedFromClass(eTrigger.penCaused, "Player")) { + m_penPlayer = eTrigger.penCaused; + call PlayCamera(); + } + } + } + }; + + // cease to exist + Destroy(); + return; + }; +}; + diff --git a/Sources/Entities/CameraMarker.es b/Sources/Entities/CameraMarker.es new file mode 100644 index 0000000..f6b540d --- /dev/null +++ b/Sources/Entities/CameraMarker.es @@ -0,0 +1,69 @@ +224 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +class CCameraMarker: CMarker +{ +name "Camera Marker"; +thumbnail "Thumbnails\\CameraMarker.tbn"; + +properties: + + 1 FLOAT m_fDeltaTime "Delta time" 'D' = 5.0f, + 2 FLOAT m_fBias "Bias" 'B' = 0.0f, + 3 FLOAT m_fTension "Tension" 'E' = 0.0f, + 4 FLOAT m_fContinuity "Continuity" 'C' = 0.0f, + 5 BOOL m_bStopMoving "Stop moving" 'O' = FALSE, + 6 FLOAT m_fFOV "FOV" 'F' = 90.0f, + 7 BOOL m_bSkipToNext "Skip to next" 'S' = FALSE, + 8 COLOR m_colFade "Fade Color" 'C' = 0, // camera fading color + 9 CEntityPointer m_penTrigger "Trigger" 'G', // camera triggers when at this marker + +components: + + 1 model MODEL_MARKER "Models\\Editor\\CameraMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\CameraMarker.tex" + + +functions: + + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker( CTFileName &fnmMarkerClass, CTString &strTargetProperty) const + { + fnmMarkerClass = CTFILENAME("Classes\\CameraMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + +procedures: + + Main() + { + // clamp parameters + m_fDeltaTime = ClampDn( m_fDeltaTime, 0.001f); + m_fBias = Clamp( m_fBias, -1.0f, +1.0f); + m_fTension = Clamp( m_fTension, -1.0f, +1.0f); + m_fContinuity = Clamp( m_fContinuity, -1.0f, +1.0f); + + // init model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + if( m_penTarget!=NULL && !IsOfClass( m_penTarget, "Camera Marker")) { + WarningMessage( "Entity '%s' is not of Camera Marker class!",(const char*) m_penTarget->GetName()); + m_penTarget = NULL; + } + + return; + } + +}; + diff --git a/Sources/Entities/CannonBall.es b/Sources/Entities/CannonBall.es new file mode 100644 index 0000000..510802b --- /dev/null +++ b/Sources/Entities/CannonBall.es @@ -0,0 +1,604 @@ +506 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Weapons/Cannon/Projectile/CannonBall.h" +#include "Entities/MovingBrush.h" +#include "Entities/DestroyableArchitecture.h" +%} + +uses "Entities/BasicEffects"; +uses "Entities/Light"; +uses "Entities/PlayerWeapons"; +uses "Entities/EnemyBase"; + +enum CannonBallType { + 0 CBT_IRON "", + 1 CBT_NUKE "", +}; + +// input parameter for launching the projectile +event ELaunchCannonBall { + CEntityPointer penLauncher, // who launched it + enum CannonBallType cbtType, // type of cannon ball + FLOAT fLaunchPower, // how fast will cannon be lounched +}; +event EForceExplode { +}; + +%{ + +// projectile solid +#define ECF_CANNON_BALL ( \ + ((ECBI_MODEL|ECBI_BRUSH|ECBI_PROJECTILE_SOLID|ECBI_CORPSE|ECBI_MODEL_HOLDER|ECBI_MODEL_HOLDER)<PrecacheClass(CLASS_BASIC_EFFECT, BET_CANNON); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_CANNONEXPLOSIONSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_CANNONSHOCKWAVE); + + pdec->PrecacheModel(MODEL_BALL); + pdec->PrecacheTexture(TEXTURE_IRON_BALL); + pdec->PrecacheTexture(TEXTURE_NUKE_BALL); + pdec->PrecacheTexture(TEX_REFL_BWRIPLES01); + pdec->PrecacheTexture(TEX_SPEC_MEDIUM); + pdec->PrecacheSound(SOUND_BALL_BOUNCE); +} + +%} + + +class export CCannonBall : CMovableModelEntity { +name "Cannon ball"; +thumbnail ""; +features "ImplementsOnPrecache"; + +properties: + 1 CEntityPointer m_penLauncher, // who lanuched it + 2 FLOAT m_fLaunchPower = 0.0f, // how fast will cannon be launched + + 10 FLOAT m_fIgnoreTime = 0.0f, // time when laucher will be ignored + 11 FLOAT m_fStartTime = 0.0f, // start time when launched + + 12 INDEX m_iNextChannel = 0, // next channel to play sound on + + 13 BOOL m_bSelfExploded = FALSE, // if cannonball exploded because of time, not because of impact + + // sound channels for bouncing sound + 20 CSoundObject m_soBounce0, + 21 CSoundObject m_soBounce1, + 22 CSoundObject m_soBounce2, + 23 CSoundObject m_soBounce3, + 24 CSoundObject m_soBounce4, + + 30 enum CannonBallType m_cbtType = CBT_IRON, + 40 FLOAT m_tmInvisibility = 0.0f, // don't render before given time + 41 FLOAT m_tmExpandBox = 0.0f, // expand collision after a few seconds + 42 FLOAT m_tmForceExplode = 0.0f, // force explosion at given moment +/* +{ + CLightSource m_lsLightSource; +}*/ + +components: + 1 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 2 class CLASS_LIGHT "Classes\\Light.ecl", + +// ********* PLAYER ROCKET ********* + 10 model MODEL_BALL "Models\\Weapons\\Cannon\\Projectile\\CannonBall.mdl", + 11 texture TEXTURE_NUKE_BALL "Models\\Weapons\\Cannon\\Projectile\\NukeBall.tex", + 13 texture TEXTURE_IRON_BALL "Models\\Weapons\\Cannon\\Projectile\\IronBall.tex", + 12 sound SOUND_BALL_BOUNCE "Models\\Weapons\\Cannon\\Sounds\\Bounce.wav", +200 texture TEX_REFL_BWRIPLES01 "Models\\ReflectionTextures\\BWRiples01.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", + +functions: + // premoving + void PreMoving(void) { + if (m_tmExpandBox>0) { + if (_pTimer->CurrentTick()>m_fStartTime+m_tmExpandBox) { + ChangeCollisionBoxIndexWhenPossible(1); + m_tmExpandBox = 0; + } + } + CMovableModelEntity::PreMoving(); + } + + void PostMoving(void) + { + CMovableModelEntity::PostMoving(); + if (en_vCurrentTranslationAbsolute.Length()<1.0f || // if very slow, allmost standing + _pTimer->CurrentTick()>=m_tmForceExplode || // if forced explosion + (GetCollisionBoxIndex()==0 && // if unable to change collision box for some time + (_pTimer->CurrentTick()>m_fStartTime+m_tmExpandBox+0.5f))) + { + SendEvent(EForceExplode()); + } + } + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CMovableModelEntity::Read_t(istr); + // setup light source +// SetupLightSource(); + } + + /* Get static light source information. */ +/* + CLightSource *GetLightSource(void) + { +// if (!IsPredictor()) { +// return &m_lsLightSource; +// } else { + return NULL; +// } + } +*/ + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + // if time now is inside invisibility time, don't render model + CModelObject *pmo = GetModelObject(); + if ( (pmo != NULL) && (_pTimer->GetLerpedCurrentTick() < (m_fStartTime+m_tmInvisibility) ) ) + { + // make it invisible + pmo->mo_colBlendColor = 0; + } + else + { + // make it visible + pmo->mo_colBlendColor = C_WHITE|CT_OPAQUE; + } + return CEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + } + +/* // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DARKLIGHT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 0.0f; + lsNew.ls_colColor = RGBToColor(128, 128, 128); + lsNew.ls_rFallOff = 5.0f; + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + */ + + // render particles + void RenderParticles(void) { + // no particles when not existing + if (GetRenderType()!=CEntity::RT_MODEL) { + return; + } + + FLOAT fSpeedRatio = Min( en_vCurrentTranslationAbsolute.Length()/140.0f, 1.0f); + INDEX ctFireParticles = INDEX( (Max( fSpeedRatio-0.5f, 0.0f)*2.0f)*128); + //CPrintF("fSpeedRatio=%g, ctFireParticles=%d\n", fSpeedRatio, ctFireParticles); + if( _pTimer->GetLerpedCurrentTick()-m_fStartTime>0.075) + { + Particles_BeastBigProjectileTrail( this, 2.0f, 1.0f, 0.75f, ctFireParticles); + } + } + +void Initialize(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_CANNON_BALL); + SetModel(MODEL_BALL); + if( m_cbtType == CBT_IRON) + { + SetModelMainTexture(TEXTURE_IRON_BALL); + } + else + { + SetModelMainTexture(TEXTURE_NUKE_BALL); + } + // stretch it + GetModelObject()->StretchModel(FLOAT3D(CANNONBALL_STRETCH, CANNONBALL_STRETCH, CANNONBALL_STRETCH)); + ModelChangeNotify(); + + // reflection texture data + GetModelObject()->mo_toReflection.SetData(GetTextureDataForComponent(TEX_REFL_BWRIPLES01)); + // specular texture data + GetModelObject()->mo_toSpecular.SetData(GetTextureDataForComponent(TEX_SPEC_MEDIUM)); + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -m_fLaunchPower), (CMovableEntity*)(CEntity*)m_penLauncher); + en_fBounceDampNormal = 0.5f; + en_fBounceDampParallel = 0.75f; + en_fAcceleration = 0.0f; + en_fDeceleration = 5.0f; + en_fCollisionSpeedLimit = 40.0f; + en_fCollisionDamageFactor = 10.0f; + SetHealth(50000.0f); + GetModelObject()->PlayAnim(CANNONBALL_ANIM_FIRESLOW, 0); +}; + +FLOAT CalculateDamageToInflict(void) +{ + FLOAT fMaxDamage = IRON_DAMAGE_MAX; + if(m_cbtType == CBT_NUKE) + { + fMaxDamage = IRON_DAMAGE_MAX; + } + + // speed can range from + FLOAT fSpeedRatio = en_vCurrentTranslationAbsolute.Length()/140.0f; + // apply damage to range from 0 to damage max + FLOAT fApplyDamage = Clamp( fSpeedRatio*fMaxDamage, 0.0f, fMaxDamage); + return fApplyDamage; +} + +void Explosion(FLOAT3D vCenter, + const FLOAT3D &vStretchExplosion, + const FLOAT3D &vStretchShockwave, + const FLOAT3D &vStretchStain, + BOOL bHasExplosion, + BOOL bHasShockWave, + BOOL bHasStain, + BOOL bHasLight) +{ + ESpawnEffect ese; + FLOAT3D vOnPlane; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + if( bHasExplosion) + { + ese.colMuliplier = C_WHITE|CT_OPAQUE; + if( bHasLight) + { + ese.betType = BET_CANNON; + } + else + { + ese.betType = BET_CANNON_NOLIGHT; + } + ese.vStretch = vStretchExplosion; + CPlacement3D plHandle = GetPlacement(); + plHandle.pl_PositionVector+=vCenter; + SpawnEffect(plHandle, ese); + // spawn sound event in range + if( IsDerivedFromClass( m_penLauncher, "Player")) { + SpawnRangeSound( m_penLauncher, this, SNDT_PLAYER, 100.0f); + } + } + // on plane + if (GetNearestPolygon(vOnPlane, vPlaneNormal, fDistanceToEdge)) { + if ((vOnPlane-GetPlacement().pl_PositionVector).Length() < 3.5f) { + if( bHasStain) + { + // wall stain + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_CANNONEXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = vStretchShockwave; + SpawnEffect(CPlacement3D(vOnPlane, ANGLE3D(0, 0, 0)), ese); + } + if( bHasShockWave) + { + // shock wave horizontal + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_CANNONSHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = vStretchShockwave; + SpawnEffect(CPlacement3D(vOnPlane, ANGLE3D(0, 0, 0)), ese); + } + // shock wave vertical + /* + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_CANNONSHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = vStretchShockwave; + SpawnEffect(CPlacement3D(vOnPlane, ANGLE3D(0, 0.0f, 0)), ese); + */ + // second explosion on plane + /* + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_CANNON_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = vStretchExplosion; + SpawnEffect(CPlacement3D(vOnPlane+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + */ + } + } + + RangeDamage(); +}; + + + +/************************************************************ + * C O M M O N F U N C T I O N S * + ************************************************************/ +// ball touch his valid target +BOOL BallTouchExplode(CEntityPointer penHit) +{ + FLOAT fApplyDamage = CalculateDamageToInflict(); + + // obtain touched entity health + FLOAT fHealth = 100; + BOOL bForceCannonballToExplode = FALSE; + + if (penHit->GetPhysicsFlags()&EPF_MOVABLE) { + fHealth = ((CMovableEntity&)*penHit).GetHealth(); + if( IsDerivedFromClass(penHit, "Enemy Base")) + { + bForceCannonballToExplode = ((CEnemyBase&)*penHit).ForcesCannonballToExplode(); + } + } else { + if (IsOfClass(penHit, "ModelHolder2")) { + fHealth = ((CLiveEntity&)*penHit).GetHealth(); + } else { + return FALSE; + } + } + if (IsOfClass(penHit, "Player")) { + fHealth += ((CPlayer&)*penHit).m_fArmor * 2.0f; + } + // inflict direct damage to kill hitted entity + FLOAT3D vDirection = en_vCurrentTranslationAbsolute; + vDirection.Normalize(); +// CPrintF( "Applied damage %g\n", fApplyDamage); + InflictDirectDamage(penHit, m_penLauncher, DMT_CANNONBALL, fApplyDamage, + GetPlacement().pl_PositionVector, vDirection); + return(fApplyDamage <= fHealth || bForceCannonballToExplode); +}; + +// infilict range damage by cannonball +void RangeDamage(void) + { + if(m_cbtType == CBT_IRON) + { + InflictRangeDamage(m_penLauncher, DMT_CANNONBALL_EXPLOSION, IRON_RANGE_DAMAGE, + GetPlacement().pl_PositionVector, IRON_RANGE_HOTSPOT, IRON_RANGE_FALLOFF); + } + else + { + // nuclear explosion ... + InflictRangeDamage(m_penLauncher, DMT_CANNONBALL_EXPLOSION, NUKE_RANGE_DAMAGE, + GetPlacement().pl_PositionVector, NUKE_RANGE_HOTSPOT, NUKE_RANGE_FALLOFF); + } +}; + + +// spawn effect +void SpawnEffect(const CPlacement3D &plEffect, const ESpawnEffect &eSpawnEffect) { + CEntityPointer penEffect = CreateEntity(plEffect, CLASS_BASIC_EFFECT); + penEffect->Initialize(eSpawnEffect); +}; + + + +/************************************************************ + * S O U N D S * + ************************************************************/ +void BounceSound(FLOAT fSpeed) { + FLOAT fVolume = Clamp(fSpeed/6.0f, 0.0f, 1.0f); + if (fVolume<0.1f) { + return; + } + CSoundObject &so = (&m_soBounce0)[m_iNextChannel]; + m_iNextChannel = (m_iNextChannel+1)%5; + so.Set3DParameters(70.0f, 10.0f, fVolume, 1.0f); + PlaySound(so, SOUND_BALL_BOUNCE, SOF_3D); +}; + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + Bounce(EVoid) { + // if already inside some entity + CEntity *penObstacle; + if (CheckForCollisionNow(0, &penObstacle)) { + // explode now + return EEnd(); + } + + FLOAT fWaitTime = IRON_LIFE_TIME; + // if this is nuke ball + if(m_cbtType == CBT_NUKE) + { + fWaitTime = NUKE_LIFE_TIME; + } + // bounce loop + wait(fWaitTime) { + on (EBegin) : { resume; } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // ignore twister + bHit &= !IsOfClass(epass.penOther, "Twister"); + + if (bHit) + { + if (BallTouchExplode(epass.penOther)) { stop; } + } + resume; + } + on (ETouch etouch) : { + // explode if touched another cannon ball + if( IsOfClass(etouch.penOther, "Cannon ball")) + { + stop; + } + if( IsOfClass(etouch.penOther, "Moving Brush")) + { + CMovingBrush &br = (CMovingBrush &) *etouch.penOther; + if( br.m_fHealth>0) + { + FLOAT3D vDirection = en_vCurrentTranslationAbsolute; + vDirection.Normalize(); + InflictDirectDamage(etouch.penOther, m_penLauncher, DMT_CANNONBALL, CalculateDamageToInflict(), + GetPlacement().pl_PositionVector, vDirection); + m_bSelfExploded = FALSE; + stop; + } + } + if( IsOfClass(etouch.penOther, "DestroyableArchitecture")) + { + CDestroyableArchitecture &br = (CDestroyableArchitecture &) *etouch.penOther; + if( br.m_fHealth>0) + { + FLOAT3D vDirection = en_vCurrentTranslationAbsolute; + vDirection.Normalize(); + InflictDirectDamage(etouch.penOther, m_penLauncher, DMT_CANNONBALL, CalculateDamageToInflict(), + GetPlacement().pl_PositionVector, vDirection); + m_bSelfExploded = FALSE; + stop; + } + } + // clear time limit for launcher + //m_fIgnoreTime = 0.0f; + BounceSound(((FLOAT3D&)etouch.plCollision) % en_vCurrentTranslationAbsolute); + resume; + } + on (EForceExplode) : { stop; } + on (EDeath) : { stop; } + on (ETimer) : { stop; } + } + m_bSelfExploded = TRUE; + return EEnd(); + }; + + // --->>> MAIN + Main(ELaunchCannonBall eLaunch) { + // remember the initial parameters + ASSERT(eLaunch.penLauncher!=NULL); + m_penLauncher = eLaunch.penLauncher; + m_fLaunchPower = eLaunch.fLaunchPower; + m_cbtType = eLaunch.cbtType; + m_tmInvisibility = 0.05f; + m_bSelfExploded = FALSE; + m_tmExpandBox = 0.0001f; + // setup time for forced expolding + m_tmForceExplode=_pTimer->CurrentTick()+30.0f; + + // initialization + Initialize(); + + SendEvent(EReturn()); + wait() { + on (EBegin) : { resume;} + on (EReturn) : { stop;} + } + + // cast ray to check possible collision + FLOAT tmCastCoverPath = _pTimer->TickQuantum*1.5f; + CCastRay crRay(m_penLauncher, GetPlacement(), m_fLaunchPower*tmCastCoverPath); + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_fTestR = 0.75f/2.0f*CANNONBALL_STRETCH; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + GetWorld()->CastRay(crRay); + + // can't hurt player time + m_fIgnoreTime = _pTimer->CurrentTick() + 0.1f; + + // bounce + m_fStartTime = _pTimer->CurrentTick(); + + if (crRay.cr_penHit!=NULL && crRay.cr_penHit->GetRenderType()==RT_MODEL) + { + if (BallTouchExplode(crRay.cr_penHit)) + { + m_tmForceExplode = _pTimer->CurrentTick()+tmCastCoverPath; + } + } + + autocall Bounce() EEnd; + + // dissapear + SwitchToEditorModel(); + // stop in place + ForceFullStop(); + + // sound event + ESound eSound; + eSound.EsndtSound = SNDT_EXPLOSION; + eSound.penTarget = m_penLauncher; + SendEventInRange(eSound, FLOATaabbox3D(GetPlacement().pl_PositionVector, SOUND_RANGE)); + + if(m_cbtType == CBT_IRON) + { + // Explosion( FLOAT3D(0.0f,0.0f,0.0f), STRETCH_3, STRETCH_3, STRETCH_3, TRUE, TRUE, TRUE, TRUE); + // autowait(0.15f); + Explosion( FLOAT3D(0.0f,0.0f,0.0f), STRETCH_3, STRETCH_3, STRETCH_4, TRUE, TRUE, TRUE, TRUE); + Explosion( FLOAT3D(1.0f,1.5f,1.5f), STRETCH_3, STRETCH_3, STRETCH_4, TRUE, FALSE, FALSE, FALSE); + Explosion( FLOAT3D(-2.0f,1.0f,-1.5f), STRETCH_3, STRETCH_3, STRETCH_4, TRUE, FALSE, FALSE, FALSE); + Explosion( FLOAT3D(-1.0f,0.5f,1.0f), STRETCH_4, STRETCH_4, STRETCH_4, TRUE, FALSE, FALSE, FALSE); + } + else if( m_cbtType == CBT_NUKE) + { + Explosion( FLOAT3D(0.0f,0.0f,0.0f), STRETCH_6, STRETCH_6, STRETCH_10, TRUE, TRUE, TRUE, TRUE); + autowait(0.15f); + Explosion( FLOAT3D(4.0f,5.0f,5.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.2f); + Explosion( FLOAT3D(-5.0f,3.0f,-4.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.15f); + Explosion( FLOAT3D(-3.0f,2.0f,3.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.15f); + Explosion( FLOAT3D(2.0f,1.0f,4.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, TRUE, FALSE, FALSE); + autowait(0.2f); + Explosion( FLOAT3D(-2.0f,5.0f,-4.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.18f); + Explosion( FLOAT3D(-3.0f,2.0f,2.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.25f); + Explosion( FLOAT3D(0.0f,4.0f,-1.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.15f); + Explosion( FLOAT3D(2.0f,0.0f,-3.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, TRUE, FALSE, FALSE); + autowait(0.25f); + Explosion( FLOAT3D(-1.0f,2.0f,0.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.125f); + Explosion( FLOAT3D(3.0f,1.0f,1.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.1f); + Explosion( FLOAT3D(3.0f,2.0f,2.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, FALSE, FALSE, FALSE); + autowait(0.125f); + Explosion( FLOAT3D(3.0f,2.0f,2.0f), STRETCH_4, STRETCH_6, STRETCH_10, TRUE, TRUE, FALSE, FALSE); + } + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/Catman.es b/Sources/Entities/Catman.es new file mode 100644 index 0000000..2db516c --- /dev/null +++ b/Sources/Entities/Catman.es @@ -0,0 +1,182 @@ +301 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Catman/CatMan.h" +%} + +uses "Entities/EnemyBase"; + +enum CatmanType { + 0 CMT_SOLDIER "Soldier", + 1 CMT_GENERAL "General", + 2 CMT_ROGUE "Rogue" +}; + + +%{ +// info structure +static EntityInfo eiCatman = { + EIBT_FLESH, 140.0f, + 0.0f, 2.0f, 0.0f, + 0.0f, 1.5f, 0.0f, +}; +%} + + +class CCatman : CEnemyBase { +name "Catman"; +thumbnail "Thumbnails\\Catman.tbn"; + +properties: + 1 enum CatmanType m_cmtType "Type" 'T' = CMT_SOLDIER, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 model MODEL_CATMAN "Models\\Enemies\\Catman\\Catman.mdl", + 2 texture TEXTURE_SOLDIER "Models\\Enemies\\Catman\\Catman03.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Catman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Catman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Catman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Catman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Catman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Catman\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiCatman; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // catman can't harm catman + if (!IsOfClass(penInflictor, "Catman")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = CATMAN_ANIM_WOUND01; break; + case 1: iAnim = CATMAN_ANIM_WOUND02; break; + case 2: iAnim = CATMAN_ANIM_WOUND03; break; + default: ASSERTALWAYS("Catman unknown damage"); + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = CATMAN_ANIM_DEATH01; break; + case 1: iAnim = CATMAN_ANIM_DEATH02; break; + default: ASSERTALWAYS("Catman unknown death"); + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(CATMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(CATMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { + StartModelAnim(CATMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { + StartModelAnim(CATMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + StartModelAnim(CATMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire { + // wait for a while + StandingAnim(); + autowait(0.2f + FRnd()/4); + + // fire projectile + StartModelAnim(CATMAN_ANIM_ATTACK02, 0); + ShootProjectile(PRT_CATMAN_FIRE, FLOAT3D(0.0f, 1.5f, 0.5f), ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(FRnd()/3+0.6f); + + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(15.0f); + m_fMaxHealth = 15.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 2000.0f; + + // set your appearance + SetModel(MODEL_CATMAN); + SetModelMainTexture(TEXTURE_SOLDIER); + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); + m_fAttackRunSpeed = FRnd()*2.0f + 4.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 4.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 40.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 10.0f; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 35.0f; + m_fBodyParts = 4; + m_fDamageWounded = 0.0f; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Common/Common.cpp b/Sources/Entities/Common/Common.cpp new file mode 100644 index 0000000..18ffff3 --- /dev/null +++ b/Sources/Entities/Common/Common.cpp @@ -0,0 +1,1117 @@ +#include "../StdH/StdH.h" +#include "Entities/Reminder.h" +//#include "Entities/Flame.h" +#include "Entities/Debris.h" +#include "Game/PlayerSettings.h" +#include "Models/Player/SeriousSam/Player.h" +#include "Models/Player/SeriousSam/Body.h" +#include "Models/Player/SeriousSam/Head.h" +extern INDEX ent_bReportBrokenChains; + +void CCompMessageID::Clear(void) +{ + cmi_fnmFileName.Clear(); + cmi_ulHash = 0; +} + +void CCompMessageID::Read_t(CTStream &strm) // throw char * +{ + strm>>cmi_fnmFileName; + strm>>(INDEX&)cmi_cmtType; + strm>>(INDEX&)cmi_bRead; + cmi_ulHash = cmi_fnmFileName.GetHash(); +} + +void CCompMessageID::Write_t(CTStream &strm) // throw char * +{ + strm<GetPlacement().pl_PositionVector; + if (pf != NULL) { + FLOATmatrix3D mRotation; + MakeRotationMatrixFast(mRotation, pen->GetPlacement().pl_OrientationAngle); + vPos += FLOAT3D(pf[0], pf[1], pf[2])*mRotation; + } +}; + +// get source and target positions for ray cast +void GetPositionCastRay(CEntity *penSource, CEntity *penTarget, FLOAT3D &vSource, FLOAT3D &vTarget) { + EntityInfo *peiSource = (EntityInfo*) (penSource->GetEntityInfo()); + EntityInfo *peiTarget = (EntityInfo*) (penTarget->GetEntityInfo()); + + ASSERT(peiSource!=NULL && peiTarget!=NULL); + + // source + if (peiSource!=NULL) { + GetEntityInfoPosition(penSource, peiSource->vSourceCenter, vSource); + } else { + vSource = penSource->GetPlacement().pl_PositionVector; + } + // target + if (peiTarget!=NULL) { + GetEntityInfoPosition(penTarget, peiTarget->vTargetCenter, vTarget); + } else { + vTarget = penTarget->GetPlacement().pl_PositionVector; + } +}; + +// set bool from bool enum type +void SetBoolFromBoolEType(BOOL &bSet, BoolEType bet) { + switch (bet) { + case BET_TRUE: + bSet = TRUE; + break; + case BET_FALSE: + bSet = FALSE; + break; + //case BET_IGNORE: + //bSet = bSet; + // break + } +}; + +// send event to target +void SendToTarget(CEntity *penSendEvent, EventEType eetEventType, CEntity *penCaused) { + // if target is valid + if (penSendEvent != NULL) { + switch (eetEventType) { + // send START event + case EET_START: { + EStart eStart; + eStart.penCaused = penCaused; + penSendEvent->SendEvent(eStart); + } break; + // send STOP event + case EET_STOP: + penSendEvent->SendEvent(EStop()); + break; + // send TRIGGER event + case EET_TRIGGER: { + ETrigger eTrigger; + eTrigger.penCaused = penCaused; + penSendEvent->SendEvent(eTrigger); + } break; + // don't send event (IGNORE) + case EET_IGNORE: + break; + // send ACTIVATE event + case EET_ACTIVATE: + penSendEvent->SendEvent(EActivate()); + break; + // send DEACTIVATE event + case EET_DEACTIVATE: + penSendEvent->SendEvent(EDeactivate()); + break; + // send ENVIRONMENTSTART event + case EET_ENVIRONMENTSTART: + penSendEvent->SendEvent(EEnvironmentStart()); + break; + // send ENVIRONMENTSTOP event + case EET_ENVIRONMENTSTOP: + penSendEvent->SendEvent(EEnvironmentStop()); + break; + // send STARTATTACK event + case EET_STARTATTACK: + penSendEvent->SendEvent(EStartAttack()); + break; + // send STOPATTACK event + case EET_STOPATTACK: + penSendEvent->SendEvent(EStopAttack()); + break; + case EET_STOPBLINDNESS: + penSendEvent->SendEvent(EStopBlindness()); + break; + case EET_STOPDEAFNESS: + penSendEvent->SendEvent(EStopDeafness()); + break; + case EET_TELEPORTMOVINGBRUSH: + penSendEvent->SendEvent(ETeleportMovingBrush()); + break; + } + } +}; + +// send event in range +void SendInRange(CEntity *penSource, EventEType eetEventType, const FLOATaabbox3D &boxRange) { + switch (eetEventType) { + // send START event + case EET_START: + penSource->SendEventInRange(EStart(), boxRange); + break; + // send STOP event + case EET_STOP: + penSource->SendEventInRange(EStop(), boxRange); + break; + // send TRIGGER event + case EET_TRIGGER: + penSource->SendEventInRange(ETrigger(), boxRange); + break; + // don't send event (IGNORE) + case EET_IGNORE: + break; + // send ACTIVATE event + case EET_ACTIVATE: + penSource->SendEventInRange(EActivate(), boxRange); + break; + // send DEACTIVATE event + case EET_DEACTIVATE: + penSource->SendEventInRange(EDeactivate(), boxRange); + break; + // send ENVIRONMENTSTART event + case EET_ENVIRONMENTSTART: + penSource->SendEventInRange(EEnvironmentStart(), boxRange); + break; + // send ENVIRONMENTSTOP event + case EET_ENVIRONMENTSTOP: + penSource->SendEventInRange(EEnvironmentStop(), boxRange); + break; + // send STARTATTACK event + case EET_STARTATTACK: + penSource->SendEventInRange(EStartAttack(), boxRange); + break; + // send STOPATTACK event + case EET_STOPATTACK: + penSource->SendEventInRange(EStopAttack(), boxRange); + break; + case EET_STOPBLINDNESS: + penSource->SendEventInRange(EStopBlindness(), boxRange); + break; + case EET_STOPDEAFNESS: + penSource->SendEventInRange(EStopDeafness(), boxRange); + break; + } +}; + +// spawn reminder +CEntityPointer SpawnReminder(CEntity *penOwner, FLOAT fWaitTime, INDEX iValue) { + CEntityPointer penReminder; + try { + penReminder = penOwner->GetWorld()->CreateEntity_t + (penOwner->GetPlacement(), CTFILENAME("Classes\\Reminder.ecl")); + } catch (char *strError) { + FatalError(TRANS("Cannot create reminder entity class: %s"), strError); + } + EReminderInit eri; + eri.penOwner = penOwner; + eri.fWaitTime = fWaitTime; + eri.iValue = iValue; + penReminder->Initialize(eri); + + return penReminder; +}; + +/* +// spawn flame +CEntityPointer SpawnFlame(CEntity *penOwner, CEntity *penAttach, const FLOAT3D &vSource) +{ + FLOAT3D vPos = vSource; + // prepare flame event + EFlame ef; + ef.penOwner = penOwner; + ef.penAttach = penAttach; + + CEntityPointer penFlame; + + // if the target entity is model + if (penAttach->GetRenderType()==CEntity::RT_MODEL) { + + vPos = penAttach->GetPlacement().pl_PositionVector; + // if the entity already has a flame attached + penFlame = penAttach->GetChildOfClass("Flame"); + if (penFlame!=NULL) { + // just send it the event + penFlame->SendEvent(ef); + return penFlame; + } + } + + // create new flame + try { + CPlacement3D plFlame(vPos, ANGLE3D(0, 0, 0)); + penFlame = penAttach->GetWorld()->CreateEntity_t(plFlame, CTFILENAME("Classes\\Flame.ecl")); + } catch (char *strError) { + FatalError(TRANS("Cannot create flame entity class: %s"), strError); + } + penFlame->Initialize(ef); + + return penFlame; +}; +*/ +// Kick entity +void KickEntity(CEntity *penTarget, FLOAT3D vSpeed) { + // if the entity is not allowed to execute now + if (!penTarget->IsAllowedForPrediction()) { + // do nothing + return; + } + EntityInfo *peiTarget = (EntityInfo*) (penTarget->GetEntityInfo()); + if (penTarget->GetPhysicsFlags()&EPF_MOVABLE && peiTarget!=NULL) { + // calc new speed acording to target mass + vSpeed *= 100.0f/peiTarget->fMass; + ((CMovableEntity&)*penTarget).en_vCurrentTranslationAbsolute = vSpeed; + ((CMovableEntity&)*penTarget).AddToMovers(); + } +}; + + + +/************************************************************ + * SET MODEL AND ATTACHMENT * + ************************************************************/ + // Set components + void SetComponents(CEntity *pen, CModelObject &mo, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) { + // model data + mo.SetData(pen->GetModelDataForComponent(ulIDModel)); + // texture data + mo.mo_toTexture.SetData(pen->GetTextureDataForComponent(ulIDTexture)); + // reflection texture data + if (ulIDReflectionTexture>0) { + mo.mo_toReflection.SetData(pen->GetTextureDataForComponent(ulIDReflectionTexture)); + } else { + mo.mo_toReflection.SetData(NULL); + } + // specular texture data + if (ulIDSpecularTexture>0) { + mo.mo_toSpecular.SetData(pen->GetTextureDataForComponent(ulIDSpecularTexture)); + } else { + mo.mo_toSpecular.SetData(NULL); + } + // bump texture data + if (ulIDBumpTexture>0) { + mo.mo_toBump.SetData(pen->GetTextureDataForComponent(ulIDBumpTexture)); + } else { + mo.mo_toBump.SetData(NULL); + } + }; + + // Add attachment to model + void AddAttachmentToModel(CEntity *pen, CModelObject &mo, INDEX iAttachment, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) { + SetComponents(pen, mo.AddAttachmentModel(iAttachment)->amo_moModelObject, ulIDModel, + ulIDTexture, ulIDReflectionTexture, ulIDSpecularTexture, ulIDBumpTexture); + }; + + // Remove attachment from model + void RemoveAttachmentFromModel(CModelObject &mo, INDEX iAttachment) { + mo.RemoveAttachmentModel(iAttachment); + }; + + + +/************************************************************ + * FLARES * + ************************************************************/ +// lens flare variables +CLensFlareType _lftStandard; +CLensFlareType _lftStandardReflections; +CLensFlareType _lftYellowStarRedRing; +CLensFlareType _lftYellowStarRedRingFar; +CLensFlareType _lftWhiteGlowStarRedRing; +CLensFlareType _lftWhiteGlowStar; +CLensFlareType _lftWhiteGlowStarNG; +CLensFlareType _lftWhiteStarRedRingStreaks; +CLensFlareType _lftWhiteStarRedReflections; +CLensFlareType _lftBlueStarBlueReflections; +CLensFlareType _lftProjectileStarGlow; +CLensFlareType _lftProjectileWhiteBubbleGlow; +CLensFlareType _lftProjectileYellowBubbleGlow; +CLensFlareType _lftPVSpaceShipWindowFlare; +CLensFlareType _lftCatmanFireGlow; +CLensFlareType _lftWhiteGlowFar; + +#define FLARE_CREATE(type,noof,tex,pos,rot,i,j,flags,amp,des,falloff)\ + type.lft_aolfFlares.New(noof);\ + type.lft_aolfFlares[0].olf_toTexture.SetData_t(CTFILENAME("Textures\\Effects\\Flares\\" tex));\ + type.lft_aolfFlares[0].olf_fReflectionPosition = pos;\ + type.lft_aolfFlares[0].olf_aRotationFactor = AngleDeg(rot);\ + type.lft_aolfFlares[0].olf_fSizeIOverScreenSizeI = i;\ + type.lft_aolfFlares[0].olf_fSizeJOverScreenSizeI = j;\ + type.lft_aolfFlares[0].olf_ulFlags = flags;\ + type.lft_aolfFlares[0].olf_fLightAmplification = amp;\ + type.lft_aolfFlares[0].olf_fLightDesaturation = des;\ + type.lft_aolfFlares[0].oft_fFallOffFactor = falloff; +#define FLARE_GLARE(type,compression,intensity,des,falloff)\ + type.lft_fGlareCompression = compression;\ + type.lft_fGlareIntensity = intensity;\ + type.lft_fGlareDesaturation = des;\ + type.lft_fGlareFallOffFactor = falloff; +#define REFLECTION(type,i,fnm,pos,size) \ + type.lft_aolfFlares[i].olf_toTexture.SetData_t(CTFILENAME("Textures\\Effects\\Flares\\" fnm));\ + type.lft_aolfFlares[i].olf_fReflectionPosition = pos;\ + type.lft_aolfFlares[i].olf_aRotationFactor = AngleDeg(0.0f);\ + type.lft_aolfFlares[i].olf_fSizeIOverScreenSizeI = size;\ + type.lft_aolfFlares[i].olf_fSizeJOverScreenSizeI = size;\ + type.lft_aolfFlares[i].olf_ulFlags = OLF_FADEINTENSITY|OLF_FADEOFCENTER;\ + type.lft_aolfFlares[i].olf_fLightAmplification = 7.0f;\ + type.lft_aolfFlares[i].olf_fLightDesaturation = 0.5f;\ + type.lft_aolfFlares[i].oft_fFallOffFactor = 5.0f; + +// init lens flare effects +void InitLensFlares(void) { + // standard flare + FLARE_CREATE(_lftStandard, 1, "01\\WhiteRedRing2.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftStandard, 20.0f, 0.3f, 0.8f, 1.0f); + + // standard flare with huge reflections + FLARE_CREATE(_lftStandardReflections, 15, "01\\WhiteRedRing2.tex", 0.0f, 180.0f, 1.36f, 1.36f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftStandardReflections, 20.0f, 0.3f, 0.8f, 1.0f); + REFLECTION(_lftStandardReflections, 1, "01\\WhiteRing.tex", -0.3f, 0.1f); + REFLECTION(_lftStandardReflections, 2, "01\\BlueDisc.tex", 1-0.5f, 0.047f); + REFLECTION(_lftStandardReflections, 3, "01\\BlueDisc.tex", 1-0.41f, 0.078f); + REFLECTION(_lftStandardReflections, 4, "01\\BlueDiscWeak.tex", 1-0.45f, 0.15f); + REFLECTION(_lftStandardReflections, 5, "01\\BrownDisc.tex", 1-0.2f, 0.05f); + REFLECTION(_lftStandardReflections, 6, "01\\WhiteGradient.tex", 1-0.1f, 0.016f); + REFLECTION(_lftStandardReflections, 7, "01\\WhiteGradient.tex", 1+0.29f, 0.027f); + REFLECTION(_lftStandardReflections, 8, "01\\BrownDisc.tex", 1+0.5f, 0.05f); + REFLECTION(_lftStandardReflections, 9, "01\\BrownDisc.tex", 1+0.43f, 0.11f); + REFLECTION(_lftStandardReflections,10, "01\\BrownRing.tex", 1+0.49f, 0.19f); + REFLECTION(_lftStandardReflections,11, "01\\BlueDisc.tex", 1+0.68f, 0.08f); + REFLECTION(_lftStandardReflections,12, "01\\BlueGradient.tex", 1+0.7f, 0.043f); + REFLECTION(_lftStandardReflections,13, "01\\GreenRing.tex", 1+1.04f, 0.27f); + REFLECTION(_lftStandardReflections,14, "01\\RainbowRing.tex", 1+1.35f, 0.53f); + + // nice yellow star with red ring + FLARE_CREATE(_lftYellowStarRedRing, 1, "02\\Flare05.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftYellowStarRedRing, 20.0f, 0.3f, 0.8f, 1.0f); + + // same yellow star with red ring but visible from far away + FLARE_CREATE(_lftYellowStarRedRingFar, 1, "02\\Flare05.tex", 0.0f, 180.0f, 1/12.0f, 1/12.0f, OLF_FADESIZE, 0.25f, 0.5f, 128.0f); + FLARE_GLARE(_lftYellowStarRedRingFar, 20.0f, 0.3f, 0.8f, 1.0f); + + // nice yellow star with red ring + FLARE_CREATE(_lftWhiteGlowStarRedRing, 1, "03\\Flare06.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftWhiteGlowStarRedRing, 20.0f, 0.3f, 0.8f, 1.0f); + + FLARE_CREATE(_lftWhiteGlowStar, 1, "04\\Flare07.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftWhiteGlowStar, 20.0f, 0.3f, 0.8f, 1.0f); + + FLARE_CREATE(_lftWhiteGlowStarNG, 1, "04\\Flare07.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + + FLARE_CREATE(_lftWhiteStarRedRingStreaks, 1, "05\\Flare09.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftWhiteStarRedRingStreaks, 20.0f, 0.3f, 0.8f, 1.0f); + + // white star flare with many red and brown hexagons + FLARE_CREATE(_lftWhiteStarRedReflections, 12, "06\\WhiteStarManyStreaks.tex", 0.0f, 0.0f, 0.20625f, 0.20625f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftWhiteStarRedReflections, 20.0f, 0.3f, 0.8f, 1.0f); + REFLECTION(_lftWhiteStarRedReflections, 1, "06\\DarkRedPentagram.tex" ,-0.92424242f,0.06875f); + REFLECTION(_lftWhiteStarRedReflections, 2, "06\\LillaPentagram.tex" ,0.28787879f,0.0296875f); + REFLECTION(_lftWhiteStarRedReflections, 3, "06\\MagentaPentagram.tex" ,0.43939394f,0.05f); + REFLECTION(_lftWhiteStarRedReflections, 4, "06\\MagentaGlow.tex" ,1.52272727f,0.009375f); + REFLECTION(_lftWhiteStarRedReflections, 5, "06\\DarkRedPentagram.tex" ,1.9469697f,0.06875f); + REFLECTION(_lftWhiteStarRedReflections, 6, "06\\MagentaGlow.tex" ,1.96212121f,0.05f); + REFLECTION(_lftWhiteStarRedReflections, 7, "06\\DarkRedPentagram.tex" ,1.08333333f,0.06875f); + REFLECTION(_lftWhiteStarRedReflections, 8, "06\\DarkRedPentagram.tex" ,1.59848485f,0.06875f); + REFLECTION(_lftWhiteStarRedReflections, 9, "06\\DarkRedPentagram.tex" ,1.67424242f,0.06875f); + REFLECTION(_lftWhiteStarRedReflections,10, "06\\DarkRedPentagram.tex" ,-0.12878788f,0.03125f); + REFLECTION(_lftWhiteStarRedReflections,11, "06\\BrownPentagram.tex" ,0.03030303f,0.021875f); + + // blue star flare with many blue flares + FLARE_CREATE(_lftBlueStarBlueReflections, 21, "07\\BlueStarManyStreaks.tex", 0.0f, 0.0f, 0.4f, 0.4f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f); + FLARE_GLARE(_lftBlueStarBlueReflections, 20.0f, 0.3f, 0.8f, 1.0f); + REFLECTION(_lftBlueStarBlueReflections, 1, "07\\BlueGlow.tex", -0.5f,0.05f); + REFLECTION(_lftBlueStarBlueReflections, 2, "07\\BluePentagram.tex", -0.25f,0.03f); + REFLECTION(_lftBlueStarBlueReflections, 3, "07\\GreenGlow.tex", -0.05f,0.04f); + REFLECTION(_lftBlueStarBlueReflections, 4, "07\\GreenGlow.tex", 0.3f,0.02f); + REFLECTION(_lftBlueStarBlueReflections, 5, "07\\BluePentagram.tex", 0.5f,0.05f); + REFLECTION(_lftBlueStarBlueReflections, 6, "07\\DarkBluePentagram.tex", 0.8f,0.04f); + REFLECTION(_lftBlueStarBlueReflections, 7, "07\\LittleBluePentagram.tex", 1.2f,0.02f); + REFLECTION(_lftBlueStarBlueReflections, 8, "07\\MagentaPentagram.tex", 1.13f,0.08f); + REFLECTION(_lftBlueStarBlueReflections, 9, "07\\DarkBluePentagram.tex", 1.24f,0.03f); + REFLECTION(_lftBlueStarBlueReflections,10, "07\\BlueGlow.tex", 1.4f,0.06f); + REFLECTION(_lftBlueStarBlueReflections,11, "07\\GreenGlow.tex", 1.5f,0.02f); + REFLECTION(_lftBlueStarBlueReflections,12, "07\\BluePentagram.tex", 1.64f,0.05f); + REFLECTION(_lftBlueStarBlueReflections,13, "07\\LittleBluePentagram.tex", 1.7f,0.05f); + REFLECTION(_lftBlueStarBlueReflections,14, "07\\BluePentagram.tex", 1.8f,0.06f); + REFLECTION(_lftBlueStarBlueReflections,15, "07\\MagentaPentagram.tex", 2.0f,0.01f); + REFLECTION(_lftBlueStarBlueReflections,16, "07\\BlueGlow.tex", 2.0f,0.06f); + REFLECTION(_lftBlueStarBlueReflections,17, "07\\MagentaPentagram.tex", 2.0f,0.02f); + REFLECTION(_lftBlueStarBlueReflections,18, "07\\GreenGlow.tex", 2.1f,0.015f); + REFLECTION(_lftBlueStarBlueReflections,19, "07\\BluePentagram.tex", 2.4f,0.05f); + REFLECTION(_lftBlueStarBlueReflections,20, "07\\DarkBluePentagram.tex", 2.8f,0.03f); + + FLARE_CREATE(_lftProjectileStarGlow, 1, "08\\FlarePower.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 10.0f); + FLARE_GLARE(_lftProjectileStarGlow, 20.0f, 0.3f, 0.8f, 1.0f); + + FLARE_CREATE(_lftProjectileWhiteBubbleGlow, 1, "09\\FlareWhiteBubble.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 10.0f); + FLARE_GLARE(_lftProjectileWhiteBubbleGlow, 20.0f, 0.3f, 0.8f, 1.0f); + + FLARE_CREATE(_lftProjectileYellowBubbleGlow, 1, "10\\FlareYellowBubble.tex", 0.0f, 180.0f, 1/10.0f, 1/10.0f, OLF_FADESIZE, 7.0f, 0.5f, 10.0f); + FLARE_GLARE(_lftProjectileYellowBubbleGlow, 20.0f, 0.3f, 0.8f, 1.0f); + + FLARE_CREATE(_lftPVSpaceShipWindowFlare, 1, "05\\Flare09.tex", 0.0f, 180.0f, 1/10.0f, 1/10.0f, OLF_FADESIZE, 1.0f, 0.0f, 10.0f); + + FLARE_CREATE(_lftCatmanFireGlow, 1, "12\\Flare12.tex", 0.0f, 180.0f, 1/12.0f, 1/12.0f, OLF_FADESIZE, 7.0f, 0.5f, 128.0f); + + FLARE_CREATE(_lftWhiteGlowFar, 1, "13\\Flare13.tex", 0.0f, 180.0f, 1/16.0f, 1/16.0f, OLF_FADESIZE, 7.0f, 0.5f, 128.0f); +}; + +// close lens flares effects +void CloseLensFlares(void) { + _lftStandard.lft_aolfFlares.Clear(); + _lftStandardReflections.lft_aolfFlares.Clear(); + _lftYellowStarRedRing.lft_aolfFlares.Clear(); + _lftYellowStarRedRingFar.lft_aolfFlares.Clear(); + _lftWhiteGlowStarRedRing.lft_aolfFlares.Clear(); + _lftWhiteGlowStar.lft_aolfFlares.Clear(); + _lftWhiteGlowStarNG.lft_aolfFlares.Clear(); + _lftWhiteStarRedRingStreaks.lft_aolfFlares.Clear(); + _lftWhiteStarRedReflections.lft_aolfFlares.Clear(); + _lftBlueStarBlueReflections.lft_aolfFlares.Clear(); + _lftProjectileStarGlow.lft_aolfFlares.Clear(); + _lftProjectileWhiteBubbleGlow.lft_aolfFlares.Clear(); + _lftProjectileYellowBubbleGlow.lft_aolfFlares.Clear(); + _lftPVSpaceShipWindowFlare.lft_aolfFlares.Clear(); + _lftCatmanFireGlow.lft_aolfFlares.Clear(); + _lftWhiteGlowFar.lft_aolfFlares.Clear(); +}; + +static BOOL _bFatalChecks = FALSE; + + +/************************************************************ + * PLAYER APPEARANCE * + ************************************************************/ +/* Set the model data */ +void SetModelData_t(CModelObject *pmo, const CTFileName &fnmModel) { + ASSERT(pmo != NULL); + pmo->SetData_t(fnmModel); // load the new model data +}; + +/* Set the texture data */ +void SetTextureData_t(CModelObject *pmo, const CTFileName &fnmTexture) { + ASSERT(pmo != NULL); + pmo->mo_toTexture.SetData_t(fnmTexture); // load the texture data +}; + +/* Set model */ +void SetModel_t(CModelObject *pmo, const CTFileName &fnmModel, const CTFileName &fnmTexture) { + SetModelData_t(pmo, fnmModel); + SetTextureData_t(pmo, fnmTexture); +}; + +/* Add attachment to model */ +void ModelAddAttachment_t(CModelObject *pmo, INDEX iAttachment, + const CTFileName &fnmModel, const CTFileName &fnmTexture) { + ASSERT(pmo != NULL); + if (fnmModel==CTString("")) return; + if (pmo==NULL) return; + + CAttachmentModelObject *pamo = pmo->AddAttachmentModel(iAttachment); + SetModel_t(&(pamo->amo_moModelObject), fnmModel, fnmTexture); +}; + +CTString _strFile; +INDEX _ctLines; + +CTString GetNonEmptyLine_t(CTStream &strm) +{ + FOREVER { + if(strm.AtEOF()) { + ThrowF_t(TRANS("Unexpected end of file")); + } + CTString str; + _ctLines++; + strm.GetLine_t(str); + str.TrimSpacesLeft(); + if (str.RemovePrefix("//")) { // skip comments + continue; + } + if (str!="") { + str.TrimSpacesRight(); + return str; + } + } +} + +void FixupFileName_t(CTString &strFnm) +{ + strFnm.TrimSpacesLeft(); + if (!strFnm.RemovePrefix(CTString("TF") +"NM ")) { // must not directly have ids in code + ThrowF_t(TRANS("Expected %s%s before filename"), "TF", "NM"); + } +} + +// skip one block in pmc +void SkipBlock_t(CTStream &strm) +{ + CTString strLine; + // expect to begin with an open bracket + strLine = GetNonEmptyLine_t(strm); + if (strLine!="{") { + ThrowF_t(TRANS("Expected '{'")); + } + // start at level one + INDEX ctLevel = 1; + // repeat + do { + strLine = GetNonEmptyLine_t(strm); + // count brackets + if (strLine=="{") { + ctLevel++; + } else if (strLine=="}") { + ctLevel--; + } + // until we close down all brackets + } while(ctLevel>0); +} + +void ParseAMC_t(CModelObject *pmo, CTStream &strm, BOOL bPreview) +{ + CTString strLine; + // expect to begin with an open bracket + strLine = GetNonEmptyLine_t(strm); + if (strLine!="{") { + ThrowF_t(TRANS("Expected '{'")); + } + + // repeat + FOREVER { + // read one line + strLine = GetNonEmptyLine_t(strm); + + // if closed bracket + if (strLine == "}") { + // finish parsing + return; + } + + + // if a preview-only block + if (strLine.RemovePrefix("PreviewOnly")) { + // if this is a preview + if (bPreview) { + // keep parsing it + ParseAMC_t(pmo, strm, bPreview); + // if this is not a preview + } else { + // skip that block + SkipBlock_t(strm); + } + // if include block + } else if (strLine.RemovePrefix("Include:")) { + // open the new file + FixupFileName_t(strLine); + CTFileStream strmIncluded; + strmIncluded.Open_t(strLine); + + // include it + INDEX ctLinesOld = _ctLines; + CTString strFileOld = _strFile; + _ctLines = 0; + _strFile = strLine; + ParseAMC_t(pmo, strmIncluded, bPreview); + strmIncluded.Close(); + _ctLines = ctLinesOld; + _strFile = strFileOld; + + // if setting the model + } else if (strLine.RemovePrefix("Model:")) { + // set the model + FixupFileName_t(strLine); + pmo->SetData_t(strLine); + + // if setting an anim for the model + } else if (strLine.RemovePrefix("Animation:")) { + // get animation number + INDEX iAnim = -1; + strLine.ScanF("%d", &iAnim); + if (iAnim<0) { + ThrowF_t(TRANS("Invalid animation number")); + } + // check it + if (iAnim>=pmo->GetAnimsCt()) { + ThrowF_t(TRANS("Animation %d does not exist in that model"), iAnim); + }; + // set it + pmo->PlayAnim(iAnim, AOF_LOOPING); + + // if texture + } else if (strLine.RemovePrefix("Texture:")) { + // set texture + FixupFileName_t(strLine); + pmo->mo_toTexture.SetData_t(strLine); + + // if specular + } else if (strLine.RemovePrefix("Specular:")) { + // set texture + FixupFileName_t(strLine); + pmo->mo_toSpecular.SetData_t(strLine); + + // if reflection + } else if (strLine.RemovePrefix("Reflection:")) { + // set texture + FixupFileName_t(strLine); + pmo->mo_toReflection.SetData_t(strLine); + + // if specular + } else if (strLine.RemovePrefix("Bump:")) { + // set texture + FixupFileName_t(strLine); + pmo->mo_toBump.SetData_t(strLine); + + // if attachment + } else if (strLine.RemovePrefix("Attachment:")) { + // get attachment number + INDEX iAtt = -1; + strLine.ScanF("%d", &iAtt); + if (iAtt<0) { + ThrowF_t(TRANS("Invalid attachment number")); + } + // create attachment + CModelData *pmd = (CModelData*)pmo->GetData(); + if (iAtt>=pmd->md_aampAttachedPosition.Count()) { + ThrowF_t(TRANS("Attachment %d does not exist in that model"), iAtt); + }; + CAttachmentModelObject *pamo = pmo->AddAttachmentModel(iAtt); + + // recursively parse it + ParseAMC_t(&pamo->amo_moModelObject, strm, bPreview); + } else { + ThrowF_t(TRANS("Expected texture or attachment")); + } + } +} + +/* Set player appearance */ +BOOL SetPlayerAppearance_internal(CModelObject *pmo, const CTFileName &fnmAMC, CTString &strName, BOOL bPreview) +{ + // try to + try { + // open the config file + CTFileStream strm; + strm.Open_t(fnmAMC); + + _ctLines = 0; + _strFile = fnmAMC; + + // read the name + CTString strLine = GetNonEmptyLine_t(strm); + if (!strLine.RemovePrefix("Name: ")) { + ThrowF_t(TRANS("Expected name")); + } + strName = strLine; + strName.TrimSpacesLeft(); + + // parse the file recursively starting at root model object and add everything + ParseAMC_t(pmo, strm, bPreview); + return TRUE; + + // if anything failed + } catch (char *strError) { + // report error + CPrintF(TRANS("Cannot load player model:\n%s (%d) : %s\n"), + (const char*)_strFile, _ctLines, strError); + return FALSE; + } +} + +BOOL SetPlayerAppearance(CModelObject *pmo, CPlayerCharacter *ppc, CTString &strName, BOOL bPreview) +{ + // first kill any existing model + pmo->SetData(NULL); + pmo->mo_toTexture.SetData(NULL); + pmo->mo_toSpecular.SetData(NULL); + pmo->mo_toReflection.SetData(NULL); + pmo->mo_toBump.SetData(NULL); + pmo->RemoveAllAttachmentModels(); + + DECLARE_CTFILENAME(fnmDefault, "Models\\Player\\SeriousSam.amc"); + + // if no character, or player models are disabled + if (ppc==NULL) { + // set default appearance + BOOL bSucceeded = SetPlayerAppearance_internal(pmo, fnmDefault, strName, bPreview); + if (!bSucceeded) { + FatalError(TRANS("Cannot load default player model!")); + } + return FALSE; + } + + // get filename from the settings + CPlayerSettings *pps = (CPlayerSettings *)ppc->pc_aubAppearance; + CTFileName fnmModelFile = pps->GetModelFilename(); + // if dummy (empty settings) + if (fnmModelFile.FileName()=="") { + // use default + fnmModelFile = fnmDefault; + } + + extern INDEX plr_bOnlySam; + if (!plr_bOnlySam && SetPlayerAppearance_internal(pmo, fnmModelFile, strName, bPreview)) { + return TRUE; + } else if (SetPlayerAppearance_internal(pmo, fnmDefault, strName, bPreview)) { // HAVE TO SET DEFAULT HERE! + return TRUE; + } else { + return FALSE; + } +} + + +/************************************************************ + * DEBUGGING FUNCTIONS * + ************************************************************/ +// debugging functions +const char *PrintConsole(void) +{ + _RPT1(_CRT_WARN, "%s", CON_GetBuffer()); + return NULL; +} + +const char *PrintStack(CEntity *pen) +{ + return pen->PrintStackDebug(); +} + + + +/************************************************************ + * DEBRIS * + ************************************************************/ +EntityInfoBodyType _Eeibt; +enum DebrisParticlesType _dptParticles; +enum BasicEffectType _betStain; +FLOAT3D _vSpeed; +FLOAT3D _vSpawnerSpeed; +FLOAT _fEntitySize; +FLOAT _fConeSize; +FLOAT _fSpeedUp; +COLOR _colDebris; + +// debris spawning +void Debris_Begin( + EntityInfoBodyType Eeibt, + enum DebrisParticlesType dptParticles, + enum BasicEffectType betStain, + FLOAT fEntitySize, // entity size in meters + const FLOAT3D &vSpeed, + const FLOAT3D &vSpawnerSpeed, // how fast was the entity moving + const FLOAT fConeSize, // size multiplier for debris cone + const FLOAT fSpeedUp, // size multiplier for debris catapulting up (0-no multiply) + const COLOR colDebris /*=C_WHITE*/ // multiply color +) +{ + _Eeibt = Eeibt ; + _dptParticles = dptParticles; + _betStain = betStain ; + _vSpeed = vSpeed ; + _vSpawnerSpeed = vSpawnerSpeed; + _fEntitySize = fEntitySize ; + _fConeSize = fConeSize ; + _fSpeedUp = fSpeedUp ; + _colDebris = colDebris ; +} + +CEntityPointer Debris_Spawn( + CEntity *penSpawner, + CEntity *penComponents, + SLONG idModelComponent, + SLONG idTextureComponent, + SLONG idReflectionTextureComponent, + SLONG idSpecularTextureComponent, + SLONG idBumpTextureComponent, + INDEX iModelAnim, + FLOAT fSize, + const FLOAT3D &vPosRatio) +{ + // create debris at same world as spawner + FLOAT3D vPos; + penSpawner->GetEntityPointRatio(vPosRatio, vPos); + CEntityPointer penDebris = penSpawner->GetWorld()->CreateEntity_t( + CPlacement3D(vPos, ANGLE3D(0,0,0)), CTFILENAME("Classes\\Debris.ecl")); + // prepare parameters + ESpawnDebris eSpawn; + eSpawn.Eeibt = _Eeibt; + eSpawn.dptParticles = _dptParticles; + eSpawn.betStain = _betStain; + eSpawn.pmd = penComponents->GetModelDataForComponent(idModelComponent); + eSpawn.ptd = penComponents->GetTextureDataForComponent(idTextureComponent); + eSpawn.ptdRefl = penComponents->GetTextureDataForComponent(idReflectionTextureComponent); + eSpawn.ptdSpec = penComponents->GetTextureDataForComponent(idSpecularTextureComponent); + eSpawn.ptdBump = penComponents->GetTextureDataForComponent(idBumpTextureComponent); + eSpawn.iModelAnim = iModelAnim; + eSpawn.colDebris = _colDebris; + if (fSize==0) { + eSpawn.fSize = 1.0f; + } else { + eSpawn.fSize = _fEntitySize*fSize; + } + // initialize it + penDebris->Initialize(eSpawn); + + FLOAT fCone = _fEntitySize*1.0f; + if (_vSpeed.Length()==0) { + fCone = 0; + } + FLOAT fRndX = (penSpawner->FRnd()*2-1)*fCone*_fConeSize; + FLOAT fRndY = (penSpawner->FRnd()*2-1)*fCone*_fConeSize; + FLOAT fRndZ = (penSpawner->FRnd()*2-1)*fCone*_fConeSize; + + FLOAT fRndH = penSpawner->FRnd(); + FLOAT fRndP = penSpawner->FRnd(); + FLOAT fRndB = penSpawner->FRnd(); + + FLOAT3D vUp; + const FLOATmatrix3D &m = penSpawner->GetRotationMatrix(); + vUp(1) = m(1,2); + vUp(2) = m(2,2); + vUp(3) = m(3,2); + + //FLOAT fStrength = _vSpeed.Length(); + + // speed it up + ((CMovableEntity&)*penDebris).LaunchAsFreeProjectile( + _vSpawnerSpeed+_vSpeed+FLOAT3D(fRndX, fRndY, fRndZ)+vUp*_fSpeedUp, (CMovableEntity*)penSpawner); + ((CMovableEntity&)*penDebris).SetDesiredRotation( + ANGLE3D(fRndH*360.0f-180.0f, fRndP*360.0f-180.0f, fRndB*360.0f-180.0f)); + + return penDebris; +} + +// info structure +static EntityInfo eiFlesh = {EIBT_FLESH}; +static EntityInfo eiWater = {EIBT_WATER}; +static EntityInfo eiRock = {EIBT_ROCK }; +static EntityInfo eiFire = {EIBT_FIRE }; +static EntityInfo eiAir = {EIBT_AIR }; +static EntityInfo eiBones = {EIBT_BONES}; +static EntityInfo eiWood = {EIBT_WOOD }; +static EntityInfo eiMetal = {EIBT_METAL}; +static EntityInfo eiRobot = {EIBT_ROBOT}; + +// get default entity info for given body type +EntityInfo *GetStdEntityInfo(EntityInfoBodyType eibt) +{ + switch(eibt) { + case EIBT_FLESH: {return &eiFlesh; } break; + case EIBT_WATER: {return &eiWater; } break; + case EIBT_ROCK : {return &eiRock ; } break; + case EIBT_FIRE : {return &eiFire ; } break; + case EIBT_AIR : {return &eiAir ; } break; + case EIBT_BONES: {return &eiBones; } break; + case EIBT_WOOD : {return &eiWood ; } break; + case EIBT_METAL: {return &eiMetal; } break; + case EIBT_ROBOT: {return &eiRobot; } break; + default: {return NULL;} break; + }; +} + + + +/************************************************************ + * DAMAGE CONTROL FUNCTIONS * + ************************************************************/ +// damage control functions +FLOAT DamageStrength(EntityInfoBodyType eibtBody, enum DamageType dtDamage) +{ + switch(eibtBody) { + case EIBT_FLESH: + return 1.0f; + case EIBT_WATER: + switch(dtDamage) { + case DMT_CLOSERANGE: return 0.0f; + case DMT_BURNING: return 0.0f; + case DMT_DROWNING: return 0.0f; + } + return 1.0f; + case EIBT_ROCK : + switch(dtDamage) { + case DMT_CLOSERANGE: return 0.0f; + case DMT_BURNING: return 0.0f; + case DMT_FREEZING: return 0.0f; + } + return 1.0f; + case EIBT_ICE : + switch(dtDamage) { + case DMT_CLOSERANGE: return 0.5f; + case DMT_BURNING: return 3.0f; + case DMT_FREEZING: return 0.0f; + } + return 1.0f; + case EIBT_FIRE : + switch(dtDamage) { + case DMT_CLOSERANGE: return 0.5f; + case DMT_BURNING: return 0.0f; + } + return 1.0f; + case EIBT_AIR : + switch(dtDamage) { + case DMT_CLOSERANGE: return 0.0f; + case DMT_BURNING: return 0.5f; + } + return 1.0f; + case EIBT_BONES: + switch(dtDamage) { + case DMT_FREEZING: return 0.0f; + } + return 1.0f; + case EIBT_WOOD : + switch(dtDamage) { + case DMT_FREEZING: return 0.0f; + } + return 1.0f; + case EIBT_METAL: + switch(dtDamage) { + case DMT_CLOSERANGE: return 0.0f; + case DMT_BURNING: return 0.0f; + case DMT_FREEZING: return 0.0f; + } + return 1.0f; + case EIBT_ROBOT: + switch(dtDamage) { + case DMT_CLOSERANGE:return 0.5f; + case DMT_BURNING: return 0.5f; + case DMT_FREEZING: return 0.5f; + } + return 1.0f; + default: + ASSERT(FALSE); + return 1.0f; + } +} + +// Print center screen message +void PrintCenterMessage(CEntity *penThis, CEntity *penCaused, + const CTString &strMessage, TIME tmLength, enum MessageSound mssSound) +{ + penCaused = FixupCausedToPlayer(penThis, penCaused); + + ECenterMessage eMsg; + eMsg.strMessage = strMessage; + eMsg.tmLength = tmLength; + eMsg.mssSound = mssSound; + penCaused->SendEvent(eMsg); +} + + +// i.e. weapon sound when fireing or exploding +void SpawnRangeSound( CEntity *penPlayer, CEntity *penPos, enum SoundType st, FLOAT fRange) +{ + // if not really player + if (!IsDerivedFromClass(penPlayer, "Player")) { + // do nothing + return; + } + // sound event + ESound eSound; + eSound.EsndtSound = st; + eSound.penTarget = penPlayer; + penPos->SendEventInRange( eSound, FLOATaabbox3D(penPos->GetPlacement().pl_PositionVector, fRange)); +} + +// get some player for trigger source if any is existing +CEntity *FixupCausedToPlayer(CEntity *penThis, CEntity *penCaused, BOOL bWarning/*=TRUE*/) +{ + if (penCaused!=NULL && IsOfClass(penCaused, "Player")) { + return penCaused; + } + + if (bWarning && (ent_bReportBrokenChains || GetSP()->sp_bQuickTest)) { + CPrintF(TRANS("WARNING: Triggering chain broken, entity: %s-%s(%s)\n"), + (const char*)penThis->GetName(), + (const char*)penThis->GetDescription(), + (const char*)penThis->GetClass()->GetName()); + } + + INDEX ctPlayers = penThis->GetMaxPlayers(); + if (ctPlayers==0) { + return NULL; + } + + CEntity *penClosestPlayer = NULL; + FLOAT fClosestPlayer = UpperLimit(0.0f); + + // for all players + for (INDEX iPlayer=0; iPlayerGetMaxPlayers(); iPlayer++) { + CEntity *penPlayer = penThis->GetPlayerEntity(iPlayer); + // if player exists + if (penPlayer!=NULL) { + // calculate distance to player + FLOAT fDistance = + (penPlayer->GetPlacement().pl_PositionVector-penThis->GetPlacement().pl_PositionVector).Length(); + // update if closer + if (fDistancesp_fExtraEnemyStrength; + if (fExtraStrength>0) { + fGameDamageMultiplier*=1.0f/(1+fExtraStrength); + } + FLOAT fExtraStrengthPerPlayer = GetSP()->sp_fExtraEnemyStrengthPerPlayer; + if (fExtraStrengthPerPlayer>0) { + INDEX ctPlayers = _pNetwork->ga_sesSessionState.GetPlayersCount(); + fGameDamageMultiplier*=1.0f/(1+fExtraStrengthPerPlayer*ClampDn(ctPlayers-1, 0)); + } + return fGameDamageMultiplier; +} diff --git a/Sources/Entities/Common/Common.h b/Sources/Entities/Common/Common.h new file mode 100644 index 0000000..14fc1f3 --- /dev/null +++ b/Sources/Entities/Common/Common.h @@ -0,0 +1,215 @@ +// common headers for flesh entity classes + +#include /* rcg10062001 need enum definition... */ +#include /* rcg10062001 need enum definition... */ + +#define SURFACE_SAND 9 +#define SURFACE_WATER 12 +#define SURFACE_RED_SAND 13 + +// Max ammo +#define MAX_BULLETS INDEX(500) +#define MAX_SHELLS INDEX(100) +#define MAX_ROCKETS INDEX(50) +#define MAX_GRENADES INDEX(50) +//#define MAX_NAPALM INDEX(250) +#define MAX_ELECTRICITY INDEX(400) +#define MAX_IRONBALLS INDEX(30) +//#define MAX_NUKEBALLS INDEX(3) + +// Bit shifters for ammo +#define AMMO_BULLETS 0 +#define AMMO_SHELLS 1 +#define AMMO_ROCKETS 2 +#define AMMO_GRENADES 3 +//#define AMMO_NAPALM 4 +#define AMMO_ELECTRICITY 5 +//#define AMMO_NUKEBALLS 6 +#define AMMO_IRONBALLS 7 + + +// Ammo mana Value +#define AV_SHELLS INDEX(70) +#define AV_BULLETS INDEX(10) +#define AV_ROCKETS INDEX(150) +#define AV_GRENADES INDEX(150) +#define AV_ELECTRICITY INDEX(250) +#define AV_IRONBALLS INDEX(700) +//#define AV_NUKEBALLS INDEX(1800) +//#define AV_NAPALM INDEX(200) + +enum EmptyShellType { + ESL_BULLET = 0, + ESL_SHOTGUN = 1, + ESL_BUBBLE = 2, + ESL_BULLET_SMOKE = 3, + ESL_SHOTGUN_SMOKE = 4, + ESL_COLT_SMOKE = 5, +}; +// empty shell launch info +#define MAX_FLYING_SHELLS 32 +struct ShellLaunchData { + FLOAT sld_fSize; // size multiplier + FLOAT3D sld_vPos; // launch position + FLOAT3D sld_vSpeed; // launch speed + FLOAT3D sld_vUp; // up vector in moment of launch + FLOAT sld_tmLaunch; // time of launch + EmptyShellType sld_estType; // shell type +}; +#define ShellLaunchData_array m_asldData[MAX_FLYING_SHELLS] + +// world change +struct WorldChange { + CTString strGroup; // group name + CPlacement3D plLink; // link placement for relative change + INDEX iType; // change type +}; +extern struct WorldChange _SwcWorldChange; + +// entity info +struct EntityInfo { + EntityInfoBodyType Eeibt; // body type + FLOAT fMass; // mass (in kg) + FLOAT vSourceCenter[3]; // body point (offset from handle) when entity look another entity + FLOAT vTargetCenter[3]; // body point (offset from handle) when entity is target of look +}; + +// entity info +struct EntityStats { + CTString es_strName; + INDEX es_ctCount; + INDEX es_ctAmmount; + FLOAT es_fValue; + INDEX es_iScore; + inline void Clear() { es_strName.Clear(); } +}; + +// statistics data for player stats management +struct DECL_DLL PlayerStats { + INDEX ps_iScore; + INDEX ps_iKills; + INDEX ps_iDeaths; + INDEX ps_iSecrets; + TIME ps_tmTime; + + PlayerStats(void) + { + ps_iScore = 0; + ps_iKills = 0; + ps_iDeaths = 0; + ps_iSecrets = 0; + ps_tmTime = 0.0f; + } +}; + +// get info position for entity +DECL_DLL void GetEntityInfoPosition(CEntity *pen, FLOAT *pf, FLOAT3D &vPos); +// get source and target positions for ray cast +DECL_DLL void GetPositionCastRay(CEntity *penSource, CEntity *penTarget, FLOAT3D &vSource, FLOAT3D &vTarget); + +// set bool from bool enum type +DECL_DLL void SetBoolFromBoolEType(BOOL &bSet, BoolEType bet); +// send event to target +DECL_DLL void SendToTarget(CEntity *penSendEvent, EventEType eetEventType, CEntity *penCaused = NULL); +// send event in range +DECL_DLL void SendInRange(CEntity *penSource, EventEType eetEventType, const FLOATaabbox3D &boxRange); + +// spawn reminder +DECL_DLL CEntityPointer SpawnReminder(CEntity *penOwner, FLOAT fWaitTime, INDEX iValue); +// spawn flame +//CEntityPointer SpawnFlame(CEntity *penOwner, CEntity *penAttach, const FLOAT3D &vSource); + +// Set components +DECL_DLL void SetComponents(CEntity *pen, CModelObject &mo, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture); +// Add attachment to model +DECL_DLL void AddAttachmentToModel(CEntity *pen, CModelObject &mo, INDEX iAttachment, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture); +// Remove attachment from model +DECL_DLL void RemoveAttachmentFromModel(CModelObject &mo, INDEX iAttachment); + +// Kick entity +DECL_DLL void KickEntity(CEntity *penTarget, FLOAT3D vSpeed); + + +// lens flare variables +extern CLensFlareType _lftStandard; +extern CLensFlareType _lftStandardReflections; +extern CLensFlareType _lftYellowStarRedRing; +extern CLensFlareType _lftYellowStarRedRingFar; +extern CLensFlareType _lftWhiteGlowStarRedRing; +extern CLensFlareType _lftWhiteGlowStar; +extern CLensFlareType _lftWhiteGlowStarNG; +extern CLensFlareType _lftWhiteStarRedRingStreaks; +extern CLensFlareType _lftWhiteStarRedReflections; +extern CLensFlareType _lftBlueStarBlueReflections; +extern CLensFlareType _lftProjectileStarGlow; +extern CLensFlareType _lftProjectileWhiteBubbleGlow; +extern CLensFlareType _lftProjectileYellowBubbleGlow; +extern CLensFlareType _lftPVSpaceShipWindowFlare; +extern CLensFlareType _lftCatmanFireGlow; +extern CLensFlareType _lftWhiteGlowFar; +// init lens flare effects +void InitLensFlares(void); +// close lens flares effects +void CloseLensFlares(void); + +DECL_DLL BOOL SetPlayerAppearance(CModelObject *mo, CPlayerCharacter *ppc, CTString &strName, BOOL bPreview); + +// debugging functions +DECL_DLL const char *PrintConsole(void); +DECL_DLL const char *PrintStack(CEntity *pen); + +// debris spawning +DECL_DLL void Debris_Begin( + EntityInfoBodyType Eeibt, + enum DebrisParticlesType dptParticles, + enum BasicEffectType betStain, + FLOAT fEntitySize, // entity size in meters + const FLOAT3D &vSpeed, + const FLOAT3D &vSpawnerSpeed, // how fast was the entity moving + const FLOAT fConeSize, // size multiplier for debris cone + const FLOAT fSpeedUp, // size multiplier for debris catapulting up (0-no multiply) + const COLOR colDebris=C_WHITE // multiply color +); +DECL_DLL CEntityPointer Debris_Spawn( + CEntity *penSpawner, + CEntity *penComponents, + SLONG idModelComponent, + SLONG idTextureComponent, + SLONG idReflectionTextureComponent, + SLONG idSpecularTextureComponent, + SLONG idBumpTextureComponent, + INDEX iModelAnim, + FLOAT fSize, // size relative to entity size (or 0 for absolute stretch of 1) + const FLOAT3D &vPosRatio); + +// get default entity info for given body type +DECL_DLL EntityInfo *GetStdEntityInfo(EntityInfoBodyType eibt); +// damage control functions +DECL_DLL FLOAT DamageStrength(EntityInfoBodyType eibtBody, enum DamageType dtDamage); + +// Print center screen message +DECL_DLL void PrintCenterMessage(CEntity *penThis, CEntity *penTarget, + const CTString &strMessage, TIME tmLength, enum MessageSound mssSound); + +// get name of a key item +DECL_DLL const char *GetKeyName(enum KeyItemType kit); + +// get session properties +DECL_DLL inline const CSessionProperties *GetSP(void) +{ + return ((const CSessionProperties *)_pNetwork->GetSessionProperties()); +} + +// i.e. weapon sound when fireing or exploding +DECL_DLL void SpawnRangeSound( CEntity *penPlayer, CEntity *penPos, enum SoundType st, FLOAT fRange); + +// get some player for trigger source if any is existing +DECL_DLL CEntity *FixupCausedToPlayer(CEntity *penThis, CEntity *penCaused, BOOL bWarning=TRUE); + +// precisely lerp between two placement using quaternions +DECL_DLL CPlacement3D LerpPlacementsPrecise(const CPlacement3D &pl0, const CPlacement3D &pl1, FLOAT fRatio); + +// obtain game extra damage per enemy and per player +DECL_DLL FLOAT GetGameDamageMultiplier(void); diff --git a/Sources/Entities/Common/Debris.cpp b/Sources/Entities/Common/Debris.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Entities/Common/Flags.h b/Sources/Entities/Common/Flags.h new file mode 100644 index 0000000..d0681db --- /dev/null +++ b/Sources/Entities/Common/Flags.h @@ -0,0 +1,157 @@ +#ifndef SE_INCL_FLAGS_H +#define SE_INCL_FLAGS_H +#ifdef PRAGMA_ONCE + #pragma once +#endif + +// collision flags +#define ECBI_BRUSH (1UL<<0) +#define ECBI_MODEL (1UL<<1) +#define ECBI_PROJECTILE_MAGIC (1UL<<2) +#define ECBI_PROJECTILE_SOLID (1UL<<3) +#define ECBI_ITEM (1UL<<4) +#define ECBI_CORPSE (1UL<<5) +#define ECBI_MODEL_HOLDER (1UL<<6) +#define ECBI_CORPSE_SOLID (1UL<<7) +#define ECBI_PLAYER (1UL<<8) + +// standard flag combinations: + +/* + * COLLISION COMBINATIONS + */ +#define ECF_IMMATERIAL (0UL) + +// brush +#define ECF_BRUSH ( \ + ((ECBI_MODEL|ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID|ECBI_ITEM|ECBI_CORPSE|ECBI_CORPSE_SOLID)< +#include +#include +#include +#include +#include + + +// armor & health constants +// NOTE: these _do not_ reflect easy/tourist maxvalue adjustments. that is by design! +#define TOP_ARMOR 100 +#define TOP_HEALTH 100 + + +// cheats +extern INDEX cht_bEnable; +extern INDEX cht_bGod; +extern INDEX cht_bFly; +extern INDEX cht_bGhost; +extern INDEX cht_bInvisible; +extern FLOAT cht_fTranslationMultiplier; + +// interface control +extern INDEX hud_bShowInfo; +extern INDEX hud_bShowLatency; +extern INDEX hud_bShowMessages; +extern INDEX hud_iShowPlayers; +extern INDEX hud_iSortPlayers; +extern FLOAT hud_fOpacity; +extern FLOAT hud_fScaling; +extern FLOAT hud_tmWeaponsOnScreen; + + +// player statistics sorting keys +enum SortKeys { + PSK_NAME = 1, + PSK_HEALTH = 2, + PSK_SCORE = 3, + PSK_MANA = 4, + PSK_FRAGS = 5, + PSK_DEATHS = 6, +}; + +// where is the bar lowest value +enum BarOrientations { + BO_LEFT = 1, + BO_RIGHT = 2, + BO_UP = 3, + BO_DOWN = 4, +}; + + + +// maximal mana for master status +#define MANA_MASTER 10000 + +// drawing variables +static const CPlayer *_penPlayer; +static CPlayerWeapons *_penWeapons; +static CDrawPort *_pDP; +static PIX _pixDPWidth, _pixDPHeight; +static FLOAT _fResolutionScaling; +static FLOAT _fCustomScaling; +static ULONG _ulAlphaHUD; +static COLOR _colHUD; +static TIME _tmNow = -1.0f; +static CFontData _fdNumbersFont; + +// array for pointers of all players +CPlayer *_apenPlayers[NET_MAXGAMEPLAYERS] = {0}; + +// status bar textures +static CTextureObject _toHealth; +static CTextureObject _toArmor; +static CTextureObject _toOxygen; +static CTextureObject _toScore; +static CTextureObject _toHiScore; +static CTextureObject _toMessage; +static CTextureObject _toMana; +static CTextureObject _toFrags; +static CTextureObject _toDeaths; +// ammo textures +static CTextureObject _toAShells; +static CTextureObject _toABullets; +static CTextureObject _toARockets; +static CTextureObject _toAGrenades; +static CTextureObject _toANapalm; +static CTextureObject _toAElectricity; +static CTextureObject _toAIronBall; +// weapon textures +static CTextureObject _toWKnife; +static CTextureObject _toWColt; +static CTextureObject _toWSingleShotgun; +static CTextureObject _toWDoubleShotgun; +static CTextureObject _toWTommygun; +static CTextureObject _toWMinigun; +static CTextureObject _toWRocketLauncher; +static CTextureObject _toWGrenadeLauncher; +static CTextureObject _toWPipeBomb; +static CTextureObject _toWFlamer; +static CTextureObject _toWGhostBuster; +static CTextureObject _toWLaser; +static CTextureObject _toWIronCannon; +// tile texture (one has corners, edges and center) +static CTextureObject _toTile; + + +// all info about color transitions +struct ColorTransitionTable { + COLOR ctt_colFine; // color for values over 1.0 + COLOR ctt_colHigh; // color for values from 1.0 to 'fMedium' + COLOR ctt_colMedium; // color for values from 'fMedium' to 'fLow' + COLOR ctt_colLow; // color for values under fLow + FLOAT ctt_fMediumHigh; // when to switch to high color (normalized float!) + FLOAT ctt_fLowMedium; // when to switch to medium color (normalized float!) + BOOL ctt_bSmooth; // should colors have smooth transition +}; +static struct ColorTransitionTable _cttHUD; + + +// ammo's info structure +struct AmmoInfo { + CTextureObject *ai_ptoAmmo; + struct WeaponInfo *ai_pwiWeapon1; + struct WeaponInfo *ai_pwiWeapon2; + INDEX ai_iAmmoAmmount; + INDEX ai_iMaxAmmoAmmount; + INDEX ai_iLastAmmoAmmount; + TIME ai_tmAmmoChanged; + BOOL ai_bHasWeapon; +}; + +// weapons' info structure +struct WeaponInfo { + enum WeaponType wi_wtWeapon; + CTextureObject *wi_ptoWeapon; + struct AmmoInfo *wi_paiAmmo; + BOOL wi_bHasWeapon; +}; + +extern struct WeaponInfo _awiWeapons[18]; +static struct AmmoInfo _aaiAmmo[8] = { + { &_toAShells, &_awiWeapons[4], &_awiWeapons[5], 0, 0, 0, -9, FALSE }, + { &_toABullets, &_awiWeapons[6], &_awiWeapons[7], 0, 0, 0, -9, FALSE }, + { &_toARockets, &_awiWeapons[8], NULL, 0, 0, 0, -9, FALSE }, + { &_toAGrenades, &_awiWeapons[9], &_awiWeapons[10], 0, 0, 0, -9, FALSE }, + { &_toANapalm, &_awiWeapons[12], NULL, 0, 0, 0, -9, FALSE }, + { &_toAElectricity, &_awiWeapons[14], &_awiWeapons[15], 0, 0, 0, -9, FALSE }, + { &_toAIronBall, &_awiWeapons[16], NULL, 0, 0, 0, -9, FALSE }, + { &_toAIronBall, &_awiWeapons[17], NULL, 0, 0, 0, -9, FALSE }, +}; + +struct WeaponInfo _awiWeapons[18] = { + { WEAPON_NONE, NULL, NULL, FALSE }, // 0 + { WEAPON_KNIFE, &_toWKnife, NULL, FALSE }, // 1 + { WEAPON_COLT, &_toWColt, NULL, FALSE }, // 2 + { WEAPON_DOUBLECOLT, &_toWColt, NULL, FALSE }, // 3 + { WEAPON_SINGLESHOTGUN, &_toWSingleShotgun, &_aaiAmmo[0], FALSE }, // 4 + { WEAPON_DOUBLESHOTGUN, &_toWDoubleShotgun, &_aaiAmmo[0], FALSE }, // 5 + { WEAPON_TOMMYGUN, &_toWTommygun, &_aaiAmmo[1], FALSE }, // 6 + { WEAPON_MINIGUN, &_toWMinigun, &_aaiAmmo[1], FALSE }, // 7 + { WEAPON_ROCKETLAUNCHER, &_toWRocketLauncher, &_aaiAmmo[2], FALSE }, // 8 + { WEAPON_GRENADELAUNCHER, &_toWGrenadeLauncher, &_aaiAmmo[3], FALSE }, // 9 + { WEAPON_NONE, NULL, NULL, FALSE }, //{ WEAPON_PIPEBOMB, &_toWPipeBomb, &_aaiAmmo[3], FALSE }, // 10 + { WEAPON_NONE, NULL, NULL, FALSE }, // 11 + { WEAPON_NONE, NULL, NULL, FALSE }, //{ WEAPON_FLAMER, &_toWFlamer, &_aaiAmmo[4], FALSE }, // 12 + { WEAPON_NONE, NULL, NULL, FALSE }, // 13 + { WEAPON_LASER, &_toWLaser, &_aaiAmmo[5], FALSE }, // 14 + { WEAPON_NONE, NULL, NULL, FALSE }, //{ WEAPON_GHOSTBUSTER, &_toWGhostBuster, &_aaiAmmo[5], FALSE }, // 15 + { WEAPON_IRONCANNON, &_toWIronCannon, &_aaiAmmo[6], FALSE }, // 16 + { WEAPON_NONE, NULL, NULL, FALSE }, //{ WEAPON_NUKECANNON, &_toWNukeCannon, &_aaiAmmo[7], FALSE }, // 17 +}; + + +// compare functions for qsort() +static int qsort_CompareNames( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + CTString strName0 = en0.GetPlayerName(); + CTString strName1 = en1.GetPlayerName(); + return strnicmp( strName0, strName1, 8); +} + +static int qsort_CompareScores( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + SLONG sl0 = en0.m_psGameStats.ps_iScore; + SLONG sl1 = en1.m_psGameStats.ps_iScore; + if( sl0sl1) return -1; + else return 0; +} + +static int qsort_CompareHealth( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + SLONG sl0 = (SLONG)ceil(en0.GetHealth()); + SLONG sl1 = (SLONG)ceil(en1.GetHealth()); + if( sl0sl1) return -1; + else return 0; +} + +static int qsort_CompareManas( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + SLONG sl0 = en0.m_iMana; + SLONG sl1 = en1.m_iMana; + if( sl0sl1) return -1; + else return 0; +} + +static int qsort_CompareFrags( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + SLONG sl0 = en0.m_psGameStats.ps_iKills; + SLONG sl1 = en1.m_psGameStats.ps_iKills; + if( sl0sl1) return -1; + else return 0; +} + +static int qsort_CompareDeaths( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + SLONG sl0 = en0.m_psGameStats.ps_iDeaths; + SLONG sl1 = en1.m_psGameStats.ps_iDeaths; + if( sl0sl1) return -1; + else return 0; +} + +static int qsort_CompareLatencies( const void *ppPEN0, const void *ppPEN1) { + CPlayer &en0 = **(CPlayer**)ppPEN0; + CPlayer &en1 = **(CPlayer**)ppPEN1; + SLONG sl0 = (SLONG)ceil(en0.m_tmLatency); + SLONG sl1 = (SLONG)ceil(en1.m_tmLatency); + if( sl0sl1) return -1; + else return 0; +} + +// prepare color transitions +static void PrepareColorTransitions( COLOR colFine, COLOR colHigh, COLOR colMedium, COLOR colLow, + FLOAT fMediumHigh, FLOAT fLowMedium, BOOL bSmooth) +{ + _cttHUD.ctt_colFine = colFine; + _cttHUD.ctt_colHigh = colHigh; + _cttHUD.ctt_colMedium = colMedium; + _cttHUD.ctt_colLow = colLow; + _cttHUD.ctt_fMediumHigh = fMediumHigh; + _cttHUD.ctt_fLowMedium = fLowMedium; + _cttHUD.ctt_bSmooth = bSmooth; +} + + + +// calculates shake ammount and color value depanding on value change +#define SHAKE_TIME (2.0f) +static COLOR AddShaker( PIX const pixAmmount, INDEX const iCurrentValue, INDEX &iLastValue, + TIME &tmChanged, FLOAT &fMoverX, FLOAT &fMoverY) +{ + // update shaking if needed + fMoverX = fMoverY = 0.0f; + const TIME tmNow = _pTimer->GetLerpedCurrentTick(); + if( iCurrentValue != iLastValue) { + iLastValue = iCurrentValue; + tmChanged = tmNow; + } else { + // in case of loading (timer got reseted) + tmChanged = ClampUp( tmChanged, tmNow); + } + + // no shaker? + const TIME tmDelta = tmNow - tmChanged; + if( tmDelta > SHAKE_TIME) return NONE; + ASSERT( tmDelta>=0); + // shake, baby shake! + const FLOAT fAmmount = _fResolutionScaling * _fCustomScaling * pixAmmount; + const FLOAT fMultiplier = (SHAKE_TIME-tmDelta)/SHAKE_TIME *fAmmount; + const INDEX iRandomizer = (INDEX)(tmNow*511.0f)*fAmmount*iCurrentValue; + const FLOAT fNormRnd1 = (FLOAT)((iRandomizer ^ (iRandomizer>>9)) & 1023) * 0.0009775f; // 1/1023 - normalized + const FLOAT fNormRnd2 = (FLOAT)((iRandomizer ^ (iRandomizer>>7)) & 1023) * 0.0009775f; // 1/1023 - normalized + fMoverX = (fNormRnd1 -0.5f) * fMultiplier; + fMoverY = (fNormRnd2 -0.5f) * fMultiplier; + // clamp to adjusted ammount (pixels relative to resolution and HUD scale + fMoverX = Clamp( fMoverX, -fAmmount, fAmmount); + fMoverY = Clamp( fMoverY, -fAmmount, fAmmount); + if( tmDelta < SHAKE_TIME/3) return C_WHITE; + else return NONE; +//return FloatToInt(tmDelta*4) & 1 ? C_WHITE : NONE; +} + + +// get current color from local color transitions table +static COLOR GetCurrentColor( FLOAT fNormalizedValue) +{ + // if value is in 'low' zone just return plain 'low' alert color + if( fNormalizedValue < _cttHUD.ctt_fLowMedium) return( _cttHUD.ctt_colLow & 0xFFFFFF00); + // if value is in out of 'extreme' zone just return 'extreme' color + if( fNormalizedValue > 1.0f) return( _cttHUD.ctt_colFine & 0xFFFFFF00); + + COLOR col; + // should blend colors? + if( _cttHUD.ctt_bSmooth) + { // lets do some interpolations + FLOAT fd, f1, f2; + COLOR col1, col2; + UBYTE ubH,ubS,ubV, ubH2,ubS2,ubV2; + // determine two colors for interpolation + if( fNormalizedValue > _cttHUD.ctt_fMediumHigh) { + f1 = 1.0f; + f2 = _cttHUD.ctt_fMediumHigh; + col1 = _cttHUD.ctt_colHigh; + col2 = _cttHUD.ctt_colMedium; + } else { // fNormalizedValue > _cttHUD.ctt_fLowMedium == TRUE ! + f1 = _cttHUD.ctt_fMediumHigh; + f2 = _cttHUD.ctt_fLowMedium; + col1 = _cttHUD.ctt_colMedium; + col2 = _cttHUD.ctt_colLow; + } + // determine interpolation strength + fd = (fNormalizedValue-f2) / (f1-f2); + // convert colors to HSV + ColorToHSV( col1, ubH, ubS, ubV); + ColorToHSV( col2, ubH2, ubS2, ubV2); + // interpolate H, S and V components + ubH = (UBYTE)(ubH*fd + ubH2*(1.0f-fd)); + ubS = (UBYTE)(ubS*fd + ubS2*(1.0f-fd)); + ubV = (UBYTE)(ubV*fd + ubV2*(1.0f-fd)); + // convert HSV back to COLOR + col = HSVToColor( ubH, ubS, ubV); + } + else + { // simple color picker + col = _cttHUD.ctt_colMedium; + if( fNormalizedValue > _cttHUD.ctt_fMediumHigh) col = _cttHUD.ctt_colHigh; + } + // all done + return( col & 0xFFFFFF00); +} + + + +// fill array with players' statistics (returns current number of players in game) +extern INDEX SetAllPlayersStats( INDEX iSortKey) +{ + // determine maximum number of players for this session + INDEX iPlayers = 0; + INDEX iMaxPlayers = _penPlayer->GetMaxPlayers(); + CPlayer *penCurrent; + // loop thru potentional players + for( INDEX i=0; iGetPlayerEntity(i); + if( penCurrent==NULL) continue; + // fill in player parameters + _apenPlayers[iPlayers] = penCurrent; + // advance to next real player + iPlayers++; + } + // sort statistics by some key if needed + switch( iSortKey) { + case PSK_NAME: qsort( _apenPlayers, iPlayers, sizeof(CPlayer*), qsort_CompareNames); break; + case PSK_SCORE: qsort( _apenPlayers, iPlayers, sizeof(CPlayer*), qsort_CompareScores); break; + case PSK_HEALTH: qsort( _apenPlayers, iPlayers, sizeof(CPlayer*), qsort_CompareHealth); break; + case PSK_MANA: qsort( _apenPlayers, iPlayers, sizeof(CPlayer*), qsort_CompareManas); break; + case PSK_FRAGS: qsort( _apenPlayers, iPlayers, sizeof(CPlayer*), qsort_CompareFrags); break; + case PSK_DEATHS: qsort( _apenPlayers, iPlayers, sizeof(CPlayer*), qsort_CompareDeaths); break; + default: break; // invalid or NONE key specified so do nothing + } + // all done + return iPlayers; +} + + + +// ----------------------- drawing functions + +// draw border with filter +static void HUD_DrawBorder( FLOAT fCenterX, FLOAT fCenterY, FLOAT fSizeX, FLOAT fSizeY, COLOR colTiles) +{ + // determine location + const FLOAT fCenterI = fCenterX*_pixDPWidth / 640.0f; + const FLOAT fCenterJ = fCenterY*_pixDPHeight / (480.0f * _pDP->dp_fWideAdjustment); + const FLOAT fSizeI = _fResolutionScaling*fSizeX; + const FLOAT fSizeJ = _fResolutionScaling*fSizeY; + const FLOAT fTileSize = 8*_fResolutionScaling*_fCustomScaling; + // determine exact positions + const FLOAT fLeft = fCenterI - fSizeI/2 -1; + const FLOAT fRight = fCenterI + fSizeI/2 +1; + const FLOAT fUp = fCenterJ - fSizeJ/2 -1; + const FLOAT fDown = fCenterJ + fSizeJ/2 +1; + const FLOAT fLeftEnd = fLeft + fTileSize; + const FLOAT fRightBeg = fRight - fTileSize; + const FLOAT fUpEnd = fUp + fTileSize; + const FLOAT fDownBeg = fDown - fTileSize; + // prepare texture + colTiles |= _ulAlphaHUD; + // put corners + _pDP->InitTexture( &_toTile, TRUE); // clamping on! + _pDP->AddTexture( fLeft, fUp, fLeftEnd, fUpEnd, colTiles); + _pDP->AddTexture( fRight,fUp, fRightBeg,fUpEnd, colTiles); + _pDP->AddTexture( fRight,fDown, fRightBeg,fDownBeg, colTiles); + _pDP->AddTexture( fLeft, fDown, fLeftEnd, fDownBeg, colTiles); + // put edges + _pDP->AddTexture( fLeftEnd,fUp, fRightBeg,fUpEnd, 0.4f,0.0f, 0.6f,1.0f, colTiles); + _pDP->AddTexture( fLeftEnd,fDown, fRightBeg,fDownBeg, 0.4f,0.0f, 0.6f,1.0f, colTiles); + _pDP->AddTexture( fLeft, fUpEnd, fLeftEnd, fDownBeg, 0.0f,0.4f, 1.0f,0.6f, colTiles); + _pDP->AddTexture( fRight, fUpEnd, fRightBeg,fDownBeg, 0.0f,0.4f, 1.0f,0.6f, colTiles); + // put center + _pDP->AddTexture( fLeftEnd, fUpEnd, fRightBeg, fDownBeg, 0.4f,0.4f, 0.6f,0.6f, colTiles); + _pDP->FlushRenderingQueue(); +} + + +// draw icon texture (if color = NONE, use colortransitions structure) +static void HUD_DrawIcon( FLOAT fCenterX, FLOAT fCenterY, CTextureObject &toIcon, + COLOR colDefault, FLOAT fNormValue, BOOL bBlink) +{ + // determine color + COLOR col = colDefault; + if( col==NONE) col = GetCurrentColor( fNormValue); + // determine blinking state + if( bBlink && fNormValue<=(_cttHUD.ctt_fLowMedium/2)) { + // activate blinking only if value is <= half the low edge + INDEX iCurrentTime = (INDEX)(_tmNow*4); + if( iCurrentTime&1) col = C_vdGRAY; + } + // determine location + const FLOAT fCenterI = fCenterX*_pixDPWidth / 640.0f; + const FLOAT fCenterJ = fCenterY*_pixDPHeight / (480.0f * _pDP->dp_fWideAdjustment); + // determine dimensions + CTextureData *ptd = (CTextureData*)toIcon.GetData(); + const FLOAT fHalfSizeI = _fResolutionScaling*_fCustomScaling * ptd->GetPixWidth() *0.5f; + const FLOAT fHalfSizeJ = _fResolutionScaling*_fCustomScaling * ptd->GetPixHeight() *0.5f; + // done + _pDP->InitTexture( &toIcon); + _pDP->AddTexture( fCenterI-fHalfSizeI, fCenterJ-fHalfSizeJ, + fCenterI+fHalfSizeI, fCenterJ+fHalfSizeJ, col|_ulAlphaHUD); + _pDP->FlushRenderingQueue(); +} + + +// draw text (or numbers, whatever) +static void HUD_DrawText( FLOAT fCenterX, FLOAT fCenterY, const CTString &strText, + COLOR colDefault, FLOAT fNormValue) +{ + // determine color + COLOR col = colDefault; + if( col==NONE) col = GetCurrentColor( fNormValue); + // determine location + PIX pixCenterI = (PIX)(fCenterX*_pixDPWidth / 640.0f); + PIX pixCenterJ = (PIX)(fCenterY*_pixDPHeight / (480.0f * _pDP->dp_fWideAdjustment)); + // done + _pDP->SetTextScaling( _fResolutionScaling*_fCustomScaling); + _pDP->PutTextCXY( strText, pixCenterI, pixCenterJ, col|_ulAlphaHUD); +} + + +// draw bar +static void HUD_DrawBar( FLOAT fCenterX, FLOAT fCenterY, PIX pixSizeX, PIX pixSizeY, + enum BarOrientations eBarOrientation, COLOR colDefault, FLOAT fNormValue) +{ + // determine color + COLOR col = colDefault; + if( col==NONE) col = GetCurrentColor( fNormValue); + // determine location and size + PIX pixCenterI = (PIX)(fCenterX*_pixDPWidth / 640.0f); + PIX pixCenterJ = (PIX)(fCenterY*_pixDPHeight / (480.0f * _pDP->dp_fWideAdjustment)); + PIX pixSizeI = (PIX)(_fResolutionScaling*pixSizeX); + PIX pixSizeJ = (PIX)(_fResolutionScaling*pixSizeY); + // fill bar background area + PIX pixLeft = pixCenterI-pixSizeI/2; + PIX pixUpper = pixCenterJ-pixSizeJ/2; + // determine bar position and inner size + switch( eBarOrientation) { + case BO_UP: + pixSizeJ *= fNormValue; + break; + case BO_DOWN: + pixUpper = pixUpper + (PIX)ceil(pixSizeJ * (1.0f-fNormValue)); + pixSizeJ *= fNormValue; + break; + case BO_LEFT: + pixSizeI *= fNormValue; + break; + case BO_RIGHT: + pixLeft = pixLeft + (PIX)ceil(pixSizeI * (1.0f-fNormValue)); + pixSizeI *= fNormValue; + break; + } + // done + _pDP->Fill( pixLeft, pixUpper, pixSizeI, pixSizeJ, col|_ulAlphaHUD); +} + + +// helper functions + +// fill weapon and ammo table with current state +static void FillWeaponAmmoTables(void) +{ + // ammo quantities + _aaiAmmo[0].ai_iAmmoAmmount = _penWeapons->m_iShells; + _aaiAmmo[0].ai_iMaxAmmoAmmount = _penWeapons->m_iMaxShells; + _aaiAmmo[1].ai_iAmmoAmmount = _penWeapons->m_iBullets; + _aaiAmmo[1].ai_iMaxAmmoAmmount = _penWeapons->m_iMaxBullets; + _aaiAmmo[2].ai_iAmmoAmmount = _penWeapons->m_iRockets; + _aaiAmmo[2].ai_iMaxAmmoAmmount = _penWeapons->m_iMaxRockets; + _aaiAmmo[3].ai_iAmmoAmmount = _penWeapons->m_iGrenades; + _aaiAmmo[3].ai_iMaxAmmoAmmount = _penWeapons->m_iMaxGrenades; + _aaiAmmo[4].ai_iAmmoAmmount = 0;//_penWeapons->m_iNapalm; + _aaiAmmo[4].ai_iMaxAmmoAmmount = 0;//_penWeapons->m_iMaxNapalm; + _aaiAmmo[5].ai_iAmmoAmmount = _penWeapons->m_iElectricity; + _aaiAmmo[5].ai_iMaxAmmoAmmount = _penWeapons->m_iMaxElectricity; + _aaiAmmo[6].ai_iAmmoAmmount = _penWeapons->m_iIronBalls; + _aaiAmmo[6].ai_iMaxAmmoAmmount = _penWeapons->m_iMaxIronBalls; + _aaiAmmo[7].ai_iAmmoAmmount = 0;//_penWeapons->m_iNukeBalls; + _aaiAmmo[7].ai_iMaxAmmoAmmount = 0;//_penWeapons->m_iMaxNukeBalls; + + // prepare ammo table for weapon possesion + INDEX i, iAvailableWeapons = _penWeapons->m_iAvailableWeapons; + for( i=0; i<8; i++) _aaiAmmo[i].ai_bHasWeapon = FALSE; + // weapon possesion + for( i=WEAPON_NONE+1; iai_bHasWeapon |= _awiWeapons[i].wi_bHasWeapon; + } + } +} + + + +// main + +// render interface (frontend) to drawport +// (units are in pixels for 640x480 resolution - for other res HUD will be scalled automatically) +extern void DrawHUD( const CPlayer *penPlayerCurrent, CDrawPort *pdpCurrent, BOOL bSnooping) +{ + // no player - no info, sorry + if( penPlayerCurrent==NULL || (penPlayerCurrent->GetFlags()&ENF_DELETED)) return; + + // find last values in case of predictor + CPlayer *penLast = (CPlayer*)penPlayerCurrent; + if( penPlayerCurrent->IsPredictor()) penLast = (CPlayer*)(((CPlayer*)penPlayerCurrent)->GetPredicted()); + ASSERT( penLast!=NULL); + if( penLast==NULL) return; // !!!! just in case + + // cache local variables + hud_fOpacity = Clamp( hud_fOpacity, 0.1f, 1.0f); + hud_fScaling = Clamp( hud_fScaling, 0.5f, 1.2f); + _penPlayer = penPlayerCurrent; + _penWeapons = (CPlayerWeapons*)&*_penPlayer->m_penWeapons; + _pDP = pdpCurrent; + _pixDPWidth = _pDP->GetWidth(); + _pixDPHeight = _pDP->GetHeight(); + _fCustomScaling = hud_fScaling; + _fResolutionScaling = (FLOAT)_pixDPWidth /640.0f; + _colHUD = C_GREEN; + _ulAlphaHUD = NormFloatToByte(hud_fOpacity); + _tmNow = _pTimer->CurrentTick(); + + // set HUD colorization; + COLOR colMax = _colHUD; + COLOR colTop = _colHUD; + COLOR colMid = _colHUD; + + // adjust borders color in case of spying mode + COLOR colBorder = _colHUD; + if( bSnooping) { + UBYTE ubR,ubG,ubB; + ColorToRGB( colBorder, ubR,ubG,ubB); + colBorder = RGBToColor( ubG,ubB,ubR); // shift and xor color components + if( ((ULONG)(_tmNow*5))&1) { + colBorder = (colBorder>>1) & 0x7F7F7F00; // darken flash and scale + _fCustomScaling *= 0.933f; + } + } + + // prepare font and text dimensions + CTString strValue; + PIX pixCharWidth; + FLOAT fValue, fNormValue, fCol, fRow; + _pDP->SetFont( &_fdNumbersFont); + pixCharWidth = _fdNumbersFont.GetWidth() + _fdNumbersFont.GetCharSpacing() +1; + FLOAT fChrUnit = pixCharWidth * _fCustomScaling; + + const PIX pixTopBound = 6; + const PIX pixLeftBound = 6; + const PIX pixBottomBound = (480 * _pDP->dp_fWideAdjustment) -pixTopBound; + const PIX pixRightBound = 640-pixLeftBound; + FLOAT fOneUnit = (32+0) * _fCustomScaling; // unit size + FLOAT fAdvUnit = (32+4) * _fCustomScaling; // unit advancer + FLOAT fNextUnit = (32+8) * _fCustomScaling; // unit advancer + FLOAT fHalfUnit = fOneUnit * 0.5f; + FLOAT fMoverX, fMoverY; + COLOR colDefault; + + // prepare and draw health info + fValue = ClampDn( _penPlayer->GetHealth(), 0.0f); // never show negative health + fNormValue = fValue/TOP_HEALTH; + strValue.PrintF( "%d", (SLONG)ceil(fValue)); + PrepareColorTransitions( colMax, colTop, colMid, C_RED, 0.5f, 0.25f, FALSE); + fRow = pixBottomBound-fHalfUnit; + fCol = pixLeftBound+fHalfUnit; + colDefault = AddShaker( 5, fValue, penLast->m_iLastHealth, penLast->m_tmHealthChanged, fMoverX, fMoverY); + HUD_DrawBorder( fCol+fMoverX, fRow+fMoverY, fOneUnit, fOneUnit, colBorder); + fCol += fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fChrUnit*3, fOneUnit, colBorder); + HUD_DrawText( fCol, fRow, strValue, colDefault, fNormValue); + fCol -= fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawIcon( fCol+fMoverX, fRow+fMoverY, _toHealth, _colHUD, fNormValue, TRUE); + + // prepare and draw armor info (eventually) + fValue = _penPlayer->m_fArmor; + if( fValue > 0.0f) { + fNormValue = fValue/TOP_ARMOR; + strValue.PrintF( "%d", (SLONG)ceil(fValue)); + PrepareColorTransitions( colMax, colTop, colMid, C_lGRAY, 0.5f, 0.25f, FALSE); + fRow = pixBottomBound- (fNextUnit+fHalfUnit);//*_pDP->dp_fWideAdjustment; + fCol = pixLeftBound+ fHalfUnit; + colDefault = AddShaker( 3, fValue, penLast->m_iLastArmor, penLast->m_tmArmorChanged, fMoverX, fMoverY); + HUD_DrawBorder( fCol+fMoverX, fRow+fMoverY, fOneUnit, fOneUnit, colBorder); + fCol += fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fChrUnit*3, fOneUnit, colBorder); + HUD_DrawText( fCol, fRow, strValue, NONE, fNormValue); + fCol -= fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawIcon( fCol+fMoverX, fRow+fMoverY, _toArmor, _colHUD, fNormValue, FALSE); + } + + // prepare and draw ammo and weapon info + CTextureObject *ptoCurrentAmmo=NULL, *ptoCurrentWeapon=NULL, *ptoWantedWeapon=NULL; + INDEX iCurrentWeapon = _penWeapons->m_iCurrentWeapon; + INDEX iWantedWeapon = _penWeapons->m_iWantedWeapon; + // determine corresponding ammo and weapon texture component + ptoCurrentWeapon = _awiWeapons[iCurrentWeapon].wi_ptoWeapon; + ptoWantedWeapon = _awiWeapons[iWantedWeapon].wi_ptoWeapon; + + AmmoInfo *paiCurrent = _awiWeapons[iCurrentWeapon].wi_paiAmmo; + if( paiCurrent!=NULL) ptoCurrentAmmo = paiCurrent->ai_ptoAmmo; + + // draw complete weapon info if knife isn't current weapon + if( ptoCurrentAmmo!=NULL && !GetSP()->sp_bInfiniteAmmo) { + // determine ammo quantities + FLOAT fMaxValue = _penWeapons->GetMaxAmmo(); + fValue = _penWeapons->GetAmmo(); + fNormValue = fValue / fMaxValue; + strValue.PrintF( "%d", (SLONG)ceil(fValue)); + PrepareColorTransitions( colMax, colTop, colMid, C_RED, 0.5f, 0.25f, FALSE); + BOOL bDrawAmmoIcon = _fCustomScaling<=1.0f; + // draw ammo, value and weapon + fRow = pixBottomBound-fHalfUnit; + fCol = 175 + fHalfUnit; + colDefault = AddShaker( 4, fValue, penLast->m_iLastAmmo, penLast->m_tmAmmoChanged, fMoverX, fMoverY); + HUD_DrawBorder( fCol+fMoverX, fRow+fMoverY, fOneUnit, fOneUnit, colBorder); + fCol += fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fChrUnit*3, fOneUnit, colBorder); + if( bDrawAmmoIcon) { + fCol += fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawIcon( fCol, fRow, *ptoCurrentAmmo, _colHUD, fNormValue, TRUE); + fCol -= fAdvUnit+fChrUnit*3/2 -fHalfUnit; + } + HUD_DrawText( fCol, fRow, strValue, colDefault, fNormValue); + fCol -= fAdvUnit+fChrUnit*3/2 -fHalfUnit; + HUD_DrawIcon( fCol+fMoverX, fRow+fMoverY, *ptoCurrentWeapon, _colHUD, fNormValue, !bDrawAmmoIcon); + } else if( ptoCurrentWeapon!=NULL) { + // draw only knife or colt icons (ammo is irrelevant) + fRow = pixBottomBound-fHalfUnit; + fCol = 205 + fHalfUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawIcon( fCol, fRow, *ptoCurrentWeapon, _colHUD, fNormValue, FALSE); + } + + + // display all ammo infos + INDEX i; + FLOAT fAdv; + COLOR colIcon, colBar; + PrepareColorTransitions( colMax, colTop, colMid, C_RED, 0.5f, 0.25f, FALSE); + // reduce the size of icon slightly + _fCustomScaling = ClampDn( _fCustomScaling*0.8f, 0.5f); + const FLOAT fOneUnitS = fOneUnit *0.8f; + const FLOAT fAdvUnitS = fAdvUnit *0.8f; + const FLOAT fNextUnitS = fNextUnit *0.8f; + const FLOAT fHalfUnitS = fHalfUnit *0.8f; + + // prepare postition and ammo quantities + fRow = pixBottomBound-fHalfUnitS; + fCol = pixRightBound -fHalfUnitS; + const FLOAT fBarPos = fHalfUnitS*0.7f; + FillWeaponAmmoTables(); + + // loop thru all ammo types + if (!GetSP()->sp_bInfiniteAmmo) { + for( i=7; i>=0; i--) { + // if no ammo and hasn't got that weapon - just skip this ammo + AmmoInfo &ai = _aaiAmmo[i]; + ASSERT( ai.ai_iAmmoAmmount>=0); + if( ai.ai_iAmmoAmmount==0 && !ai.ai_bHasWeapon) continue; + // display ammo info + colIcon = _colHUD; + if( ai.ai_iAmmoAmmount==0) colIcon = C_GRAY; + if( ptoCurrentAmmo == ai.ai_ptoAmmo) colIcon = C_WHITE; + fNormValue = (FLOAT)ai.ai_iAmmoAmmount / ai.ai_iMaxAmmoAmmount; + colBar = AddShaker( 4, ai.ai_iAmmoAmmount, ai.ai_iLastAmmoAmmount, ai.ai_tmAmmoChanged, fMoverX, fMoverY); + HUD_DrawBorder( fCol, fRow+fMoverY, fOneUnitS, fOneUnitS, colBorder); + HUD_DrawIcon( fCol, fRow+fMoverY, *_aaiAmmo[i].ai_ptoAmmo, colIcon, fNormValue, FALSE); + HUD_DrawBar( fCol+fBarPos, fRow+fMoverY, fOneUnitS/5, fOneUnitS-2, BO_DOWN, colBar, fNormValue); + // advance to next position + fCol -= fAdvUnitS; + } + } + + // if weapon change is in progress + _fCustomScaling = hud_fScaling; + hud_tmWeaponsOnScreen = Clamp( hud_tmWeaponsOnScreen, 0.0f, 10.0f); + if( (_tmNow - _penWeapons->m_tmWeaponChangeRequired) < hud_tmWeaponsOnScreen) { + // determine number of weapons that player has + INDEX ctWeapons = 0; + for( i=WEAPON_NONE+1; iai_iAmmoAmmount==0) colIcon = C_dGRAY; + if( ptoWantedWeapon == _awiWeapons[i].wi_ptoWeapon) colIcon = C_WHITE; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colIcon); + HUD_DrawIcon( fCol, fRow, *_awiWeapons[i].wi_ptoWeapon, colIcon, 1.0f, FALSE); + // advance to next position + fCol += fAdvUnit; + } + } + + const FLOAT fUpperSize = ClampDn(_fCustomScaling*0.5f, 0.5f)/_fCustomScaling; + _fCustomScaling*=fUpperSize; + ASSERT( _fCustomScaling>=0.5f); + fChrUnit *= fUpperSize; + fOneUnit *= fUpperSize; + fHalfUnit *= fUpperSize; + fAdvUnit *= fUpperSize; + fNextUnit *= fUpperSize; + + // draw oxygen info if needed + BOOL bOxygenOnScreen = FALSE; + fValue = _penPlayer->en_tmMaxHoldBreath - (_pTimer->CurrentTick() - _penPlayer->en_tmLastBreathed); + if( _penPlayer->IsConnected() && (_penPlayer->GetFlags()&ENF_ALIVE) && fValue<30.0f) { + // prepare and draw oxygen info + fRow = pixTopBound + fOneUnit + fNextUnit; + fCol = 280.0f; + fAdv = fAdvUnit + fOneUnit*4/2 - fHalfUnit; + PrepareColorTransitions( colMax, colTop, colMid, C_RED, 0.5f, 0.25f, FALSE); + fNormValue = fValue/30.0f; + fNormValue = ClampDn(fNormValue, 0.0f); + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawBorder( fCol+fAdv, fRow, fOneUnit*4, fOneUnit, colBorder); + HUD_DrawBar( fCol+fAdv, fRow, fOneUnit*4*0.975, fOneUnit*0.9375, BO_LEFT, NONE, fNormValue); + HUD_DrawIcon( fCol, fRow, _toOxygen, _colHUD, fNormValue, TRUE); + bOxygenOnScreen = TRUE; + } + + // draw boss energy if needed + if( _penPlayer->m_penMainMusicHolder!=NULL) { + CMusicHolder &mh = (CMusicHolder&)*_penPlayer->m_penMainMusicHolder; + fNormValue = 0; + + if( mh.m_penBoss!=NULL && (mh.m_penBoss->en_ulFlags&ENF_ALIVE)) { + CEnemyBase &eb = (CEnemyBase&)*mh.m_penBoss; + ASSERT( eb.m_fMaxHealth>0); + fValue = eb.GetHealth(); + fNormValue = fValue/eb.m_fMaxHealth; + } + if( mh.m_penCounter!=NULL) { + CEnemyCounter &ec = (CEnemyCounter&)*mh.m_penCounter; + if (ec.m_iCount>0) { + fValue = ec.m_iCount; + fNormValue = fValue/ec.m_iCountFrom; + } + } + if (fNormValue>0) { + // prepare and draw boss energy info + PrepareColorTransitions( colMax, colTop, colMid, C_RED, 0.5f, 0.25f, FALSE); + fRow = pixTopBound + fOneUnit + fNextUnit; + fCol = 184.0f; + fAdv = fAdvUnit+ fOneUnit*16/2 -fHalfUnit; + if( bOxygenOnScreen) fRow += fNextUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawBorder( fCol+fAdv, fRow, fOneUnit*16, fOneUnit, colBorder); + HUD_DrawBar( fCol+fAdv, fRow, fOneUnit*16*0.995, fOneUnit*0.9375, BO_LEFT, NONE, fNormValue); + HUD_DrawIcon( fCol, fRow, _toHealth, _colHUD, fNormValue, FALSE); + } + } + + // determine scaling of normal text and play mode + const FLOAT fTextScale = (_fResolutionScaling+1) *0.5f; + const BOOL bSinglePlay = GetSP()->sp_bSinglePlayer; + const BOOL bCooperative = GetSP()->sp_bCooperative && !bSinglePlay; + const BOOL bScoreMatch = !GetSP()->sp_bCooperative && !GetSP()->sp_bUseFrags; + const BOOL bFragMatch = !GetSP()->sp_bCooperative && GetSP()->sp_bUseFrags; + COLOR colMana, colFrags, colDeaths, colHealth, colArmor; + COLOR colScore = _colHUD; + INDEX iScoreSum = 0; + + // if not in single player mode, we'll have to calc (and maybe printout) other players' info + if( !bSinglePlay) + { + // set font and prepare font parameters + _pfdDisplayFont->SetVariableWidth(); + _pDP->SetFont( _pfdDisplayFont); + _pDP->SetTextScaling( fTextScale); + FLOAT fCharHeight = (_pfdDisplayFont->GetHeight()-2)*fTextScale; + // generate and sort by mana list of active players + BOOL bMaxScore=TRUE, bMaxMana=TRUE, bMaxFrags=TRUE, bMaxDeaths=TRUE; + hud_iSortPlayers = Clamp( hud_iSortPlayers, -1, 6); + SortKeys eKey = (SortKeys)hud_iSortPlayers; + if (hud_iSortPlayers==-1) { + if (bCooperative) eKey = PSK_HEALTH; + else if (bScoreMatch) eKey = PSK_SCORE; + else if (bFragMatch) eKey = PSK_FRAGS; + else { ASSERT(FALSE); eKey = PSK_NAME; } + } + if( bCooperative) eKey = (SortKeys)Clamp( (INDEX)eKey, 0, 3); + if( eKey==PSK_HEALTH && (bScoreMatch || bFragMatch)) { eKey = PSK_NAME; }; // prevent health snooping in deathmatch + INDEX iPlayers = SetAllPlayersStats(eKey); + // loop thru players + for( INDEX i=0; iGetPlayerName(); + const INDEX iScore = penPlayer->m_psGameStats.ps_iScore; + const INDEX iMana = penPlayer->m_iMana; + const INDEX iFrags = penPlayer->m_psGameStats.ps_iKills; + const INDEX iDeaths = penPlayer->m_psGameStats.ps_iDeaths; + const INDEX iHealth = ClampDn( (INDEX)ceil( penPlayer->GetHealth()), 0); + const INDEX iArmor = ClampDn( (INDEX)ceil( penPlayer->m_fArmor), 0); + CTString strScore, strMana, strFrags, strDeaths, strHealth, strArmor; + strScore.PrintF( "%d", iScore); + strMana.PrintF( "%d", iMana); + strFrags.PrintF( "%d", iFrags); + strDeaths.PrintF( "%d", iDeaths); + strHealth.PrintF( "%d", iHealth); + strArmor.PrintF( "%d", iArmor); + // detemine corresponding colors + colHealth = C_mlRED; + colMana = colScore = colFrags = colDeaths = colArmor = C_lGRAY; + if( iMana > _penPlayer->m_iMana) { bMaxMana = FALSE; colMana = C_WHITE; } + if( iScore > _penPlayer->m_psGameStats.ps_iScore) { bMaxScore = FALSE; colScore = C_WHITE; } + if( iFrags > _penPlayer->m_psGameStats.ps_iKills) { bMaxFrags = FALSE; colFrags = C_WHITE; } + if( iDeaths > _penPlayer->m_psGameStats.ps_iDeaths) { bMaxDeaths = FALSE; colDeaths = C_WHITE; } + if( penPlayer==_penPlayer) colScore = colMana = colFrags = colDeaths = _colHUD; // current player + if( iHealth>25) colHealth = _colHUD; + if( iArmor >25) colArmor = _colHUD; + // eventually print it out + if( hud_iShowPlayers==1 || hud_iShowPlayers==-1 && !bSinglePlay) { + // printout location and info aren't the same for deathmatch and coop play + const FLOAT fCharWidth = (PIX)((_pfdDisplayFont->GetWidth()-2) *fTextScale); + if( bCooperative) { + _pDP->PutTextR( strName+":", _pixDPWidth-8*fCharWidth, fCharHeight*i+fOneUnit*2, colScore |_ulAlphaHUD); + _pDP->PutText( "/", _pixDPWidth-4*fCharWidth, fCharHeight*i+fOneUnit*2, _colHUD |_ulAlphaHUD); + _pDP->PutTextC( strHealth, _pixDPWidth-6*fCharWidth, fCharHeight*i+fOneUnit*2, colHealth|_ulAlphaHUD); + _pDP->PutTextC( strArmor, _pixDPWidth-2*fCharWidth, fCharHeight*i+fOneUnit*2, colArmor |_ulAlphaHUD); + } else if( bScoreMatch) { + _pDP->PutTextR( strName+":", _pixDPWidth-12*fCharWidth, fCharHeight*i+fOneUnit*2, _colHUD |_ulAlphaHUD); + _pDP->PutText( "/", _pixDPWidth- 5*fCharWidth, fCharHeight*i+fOneUnit*2, _colHUD |_ulAlphaHUD); + _pDP->PutTextC( strScore, _pixDPWidth- 8*fCharWidth, fCharHeight*i+fOneUnit*2, colScore|_ulAlphaHUD); + _pDP->PutTextC( strMana, _pixDPWidth- 2*fCharWidth, fCharHeight*i+fOneUnit*2, colMana |_ulAlphaHUD); + } else { // fragmatch! + _pDP->PutTextR( strName+":", _pixDPWidth-8*fCharWidth, fCharHeight*i+fOneUnit*2, _colHUD |_ulAlphaHUD); + _pDP->PutText( "/", _pixDPWidth-4*fCharWidth, fCharHeight*i+fOneUnit*2, _colHUD |_ulAlphaHUD); + _pDP->PutTextC( strFrags, _pixDPWidth-6*fCharWidth, fCharHeight*i+fOneUnit*2, colFrags |_ulAlphaHUD); + _pDP->PutTextC( strDeaths, _pixDPWidth-2*fCharWidth, fCharHeight*i+fOneUnit*2, colDeaths|_ulAlphaHUD); + } + } + // calculate summ of scores (for coop mode) + iScoreSum += iScore; + } + + // prepare color for local player printouts + bMaxScore ? colScore = C_WHITE : colScore = C_lGRAY; + bMaxMana ? colMana = C_WHITE : colMana = C_lGRAY; + bMaxFrags ? colFrags = C_WHITE : colFrags = C_lGRAY; + bMaxDeaths ? colDeaths = C_WHITE : colDeaths = C_lGRAY; + } + + // printout player latency if needed + if( hud_bShowLatency) { + CTString strLatency; + strLatency.PrintF( "%4.0fms", _penPlayer->m_tmLatency*1000.0f); + PIX pixFontHeight = (PIX)(_pfdDisplayFont->GetHeight() *fTextScale +fTextScale+1); + _pfdDisplayFont->SetFixedWidth(); + _pDP->SetFont( _pfdDisplayFont); + _pDP->SetTextScaling( fTextScale); + _pDP->SetTextCharSpacing( -2.0f*fTextScale); + _pDP->PutTextR( strLatency, _pixDPWidth, _pixDPHeight-pixFontHeight, C_WHITE|CT_OPAQUE); + } + // restore font defaults + _pfdDisplayFont->SetVariableWidth(); + _pDP->SetFont( &_fdNumbersFont); + _pDP->SetTextCharSpacing(1); + + // prepare output strings and formats depending on game type + FLOAT fWidthAdj = 8; + INDEX iScore = _penPlayer->m_psGameStats.ps_iScore; + INDEX iMana = _penPlayer->m_iMana; + if( bFragMatch) { + fWidthAdj = 4; + iScore = _penPlayer->m_psGameStats.ps_iKills; + iMana = _penPlayer->m_psGameStats.ps_iDeaths; + } else if( bCooperative) { + // in case of coop play, show squad (common) score + iScore = iScoreSum; + } + + // prepare and draw score or frags info + strValue.PrintF( "%d", iScore); + fRow = pixTopBound +fHalfUnit; + fCol = pixLeftBound +fHalfUnit; + fAdv = fAdvUnit+ fChrUnit*fWidthAdj/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawBorder( fCol+fAdv, fRow, fChrUnit*fWidthAdj, fOneUnit, colBorder); + HUD_DrawText( fCol+fAdv, fRow, strValue, colScore, 1.0f); + HUD_DrawIcon( fCol, fRow, _toFrags, colScore, 1.0f, FALSE); + + // eventually draw mana info + if( bScoreMatch || bFragMatch) { + strValue.PrintF( "%d", iMana); + fRow = pixTopBound + fNextUnit+fHalfUnit; + fCol = pixLeftBound + fHalfUnit; + fAdv = fAdvUnit+ fChrUnit*fWidthAdj/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawBorder( fCol+fAdv, fRow, fChrUnit*fWidthAdj, fOneUnit, colBorder); + HUD_DrawText( fCol+fAdv, fRow, strValue, colMana, 1.0f); + HUD_DrawIcon( fCol, fRow, _toDeaths, colMana, 1.0f, FALSE); + } + + // if single player or cooperative mode + if( bSinglePlay || bCooperative) + { + // prepare and draw hiscore info + strValue.PrintF( "%d", Max(_penPlayer->m_iHighScore, _penPlayer->m_psGameStats.ps_iScore)); + BOOL bBeating = _penPlayer->m_psGameStats.ps_iScore>_penPlayer->m_iHighScore; + fRow = pixTopBound+fHalfUnit; + fCol = 320.0f-fOneUnit-fChrUnit*8/2; + fAdv = fAdvUnit+ fChrUnit*8/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, colBorder); + HUD_DrawBorder( fCol+fAdv, fRow, fChrUnit*8, fOneUnit, colBorder); + HUD_DrawText( fCol+fAdv, fRow, strValue, NONE, bBeating ? 0.0f : 1.0f); + HUD_DrawIcon( fCol, fRow, _toHiScore, _colHUD, 1.0f, FALSE); + + // prepare and draw unread messages + if( hud_bShowMessages && _penPlayer->m_ctUnreadMessages>0) { + strValue.PrintF( "%d", _penPlayer->m_ctUnreadMessages); + fRow = pixTopBound+fHalfUnit; + fCol = pixRightBound-fHalfUnit-fAdvUnit-fChrUnit*4; + const FLOAT tmIn = 0.5f; + const FLOAT tmOut = 0.5f; + const FLOAT tmStay = 2.0f; + FLOAT tmDelta = _pTimer->GetLerpedCurrentTick()-_penPlayer->m_tmAnimateInbox; + COLOR col = _colHUD; + if (tmDelta>0 && tmDelta<(tmIn+tmStay+tmOut) && bSinglePlay) { + FLOAT fRatio = 0.0f; + if (tmDeltatmIn+tmStay) { + fRatio = (tmIn+tmStay+tmOut-tmDelta)/tmOut; + } else { + fRatio = 1.0f; + } + fRow+=fAdvUnit*5*fRatio; + fCol-=fAdvUnit*15*fRatio; + col = LerpColor(_colHUD, C_WHITE|0xFF, fRatio); + } + fAdv = fAdvUnit+ fChrUnit*4/2 -fHalfUnit; + HUD_DrawBorder( fCol, fRow, fOneUnit, fOneUnit, col); + HUD_DrawBorder( fCol+fAdv, fRow, fChrUnit*4, fOneUnit, col); + HUD_DrawText( fCol+fAdv, fRow, strValue, col, 1.0f); + HUD_DrawIcon( fCol, fRow, _toMessage, col, 0.0f, TRUE); + } + } + + // draw cheat modes + if( GetSP()->sp_ctMaxPlayers==1) { + INDEX iLine=1; + ULONG ulAlpha = sin(_tmNow*16)*96 +128; + PIX pixFontHeight = _pfdConsoleFont->fd_pixCharHeight; + const COLOR colCheat = _colHUD; + _pDP->SetFont( _pfdConsoleFont); + _pDP->SetTextScaling( 1.0f); + const FLOAT fchtTM = cht_fTranslationMultiplier; // for text formatting sake :) + if( fchtTM > 1.0f) { _pDP->PutTextR( "turbo", _pixDPWidth-1, _pixDPHeight-pixFontHeight*iLine, colCheat|ulAlpha); iLine++; } + if( cht_bInvisible) { _pDP->PutTextR( "invisible", _pixDPWidth-1, _pixDPHeight-pixFontHeight*iLine, colCheat|ulAlpha); iLine++; } + if( cht_bGhost) { _pDP->PutTextR( "ghost", _pixDPWidth-1, _pixDPHeight-pixFontHeight*iLine, colCheat|ulAlpha); iLine++; } + if( cht_bFly) { _pDP->PutTextR( "fly", _pixDPWidth-1, _pixDPHeight-pixFontHeight*iLine, colCheat|ulAlpha); iLine++; } + if( cht_bGod) { _pDP->PutTextR( "god", _pixDPWidth-1, _pixDPHeight-pixFontHeight*iLine, colCheat|ulAlpha); iLine++; } + } +} + + + +// initialized all whats need for drawing HUD +extern void InitHUD(void) +{ + // try to + try { + // initialize and load HUD numbers font + DECLARE_CTFILENAME( fnFont, "Fonts\\Numbers3.fnt"); + _fdNumbersFont.Load_t( fnFont); + //_fdNumbersFont.SetCharSpacing(0); + + // initialize status bar textures + _toHealth.SetData_t( CTFILENAME("Textures\\Interface\\HSuper.tex")); + _toArmor.SetData_t( CTFILENAME("Textures\\Interface\\ArStrong.tex")); + _toOxygen.SetData_t( CTFILENAME("Textures\\Interface\\Oxygen-2.tex")); + _toFrags.SetData_t( CTFILENAME("Textures\\Interface\\IBead.tex")); + _toDeaths.SetData_t( CTFILENAME("Textures\\Interface\\ISkull.tex")); + _toScore.SetData_t( CTFILENAME("Textures\\Interface\\IScore.tex")); + _toHiScore.SetData_t( CTFILENAME("Textures\\Interface\\IHiScore.tex")); + _toMessage.SetData_t( CTFILENAME("Textures\\Interface\\IMessage.tex")); + _toMana.SetData_t( CTFILENAME("Textures\\Interface\\IValue.tex")); + // initialize ammo textures + _toAShells.SetData_t( CTFILENAME("Textures\\Interface\\AmShells.tex")); + _toABullets.SetData_t( CTFILENAME("Textures\\Interface\\AmBullets.tex")); + _toARockets.SetData_t( CTFILENAME("Textures\\Interface\\AmRockets.tex")); + _toAGrenades.SetData_t( CTFILENAME("Textures\\Interface\\AmGrenades.tex")); + _toANapalm.SetData_t( CTFILENAME("Textures\\Interface\\AmFuelReservoir.tex")); + _toAElectricity.SetData_t( CTFILENAME("Textures\\Interface\\AmElectricity.tex")); + _toAIronBall.SetData_t( CTFILENAME("Textures\\Interface\\AmCannon.tex")); + // initialize weapon textures + _toWKnife.SetData_t( CTFILENAME("Textures\\Interface\\WKnife.tex")); + _toWColt.SetData_t( CTFILENAME("Textures\\Interface\\WColt.tex")); + _toWSingleShotgun.SetData_t( CTFILENAME("Textures\\Interface\\WSingleShotgun.tex")); + _toWDoubleShotgun.SetData_t( CTFILENAME("Textures\\Interface\\WDoubleShotgun.tex")); + _toWTommygun.SetData_t( CTFILENAME("Textures\\Interface\\WTommygun.tex")); + _toWMinigun.SetData_t( CTFILENAME("Textures\\Interface\\WMinigun.tex")); + _toWRocketLauncher.SetData_t( CTFILENAME("Textures\\Interface\\WRocketLauncher.tex")); + _toWGrenadeLauncher.SetData_t( CTFILENAME("Textures\\Interface\\WGrenadeLauncher.tex")); + _toWPipeBomb.SetData_t( CTFILENAME("Textures\\Interface\\WPipeBomb.tex")); + _toWFlamer.SetData_t( CTFILENAME("Textures\\Interface\\WFlamer.tex")); + _toWGhostBuster.SetData_t( CTFILENAME("Textures\\Interface\\WGhostBuster.tex")); + _toWLaser.SetData_t( CTFILENAME("Textures\\Interface\\WLaser.tex")); + _toWIronCannon.SetData_t( CTFILENAME("Textures\\Interface\\WCannon.tex")); + // initialize tile texture + _toTile.SetData_t( CTFILENAME("Textures\\Interface\\Tile.tex")); + + // set all textures as constant + ((CTextureData*)_toHealth .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toArmor .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toOxygen .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toFrags .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toDeaths .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toScore .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toHiScore.GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toMessage.GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toMana .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toAShells .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toABullets .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toARockets .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toAGrenades .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toANapalm .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toAElectricity.GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toAIronBall .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWKnife .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWColt .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWSingleShotgun .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWDoubleShotgun .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWTommygun .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWMinigun .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWRocketLauncher .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWGrenadeLauncher.GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWPipeBomb .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWFlamer .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWGhostBuster .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWLaser .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toWIronCannon .GetData())->Force(TEX_CONSTANT); + ((CTextureData*)_toTile .GetData())->Force(TEX_CONSTANT); + } + catch( char *strError) { + FatalError( strError); + } + +} + + +// clean up +extern void EndHUD(void) +{ + +} + diff --git a/Sources/Entities/Common/HUD.h b/Sources/Entities/Common/HUD.h new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Entities/Common/Particles.cpp b/Sources/Entities/Common/Particles.cpp new file mode 100644 index 0000000..82bf0e1 --- /dev/null +++ b/Sources/Entities/Common/Particles.cpp @@ -0,0 +1,2988 @@ +#include "../StdH/StdH.h" +#include "Entities/BloodSpray.h" +#include "Entities/PlayerWeapons.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/BackgroundViewer.h" + +static CTextureObject _toRomboidTrail; +static CTextureObject _toBombTrail; +static CTextureObject _toFirecrackerTrail; +static CTextureObject _toSpiralTrail; +static CTextureObject _toColoredStarsTrail; +static CTextureObject _toFireball01Trail; +static CTextureObject _toGrenadeTrail; +static CTextureObject _toCannonBall; +static CTextureObject _toRocketTrail; +static CTextureObject _toVerticalGradient; +static CTextureObject _toVerticalGradientAlpha; +static CTextureObject _toBlood01Trail; +static CTextureObject _toLavaTrailGradient; +static CTextureObject _toLavaTrailSmoke; +static CTextureObject _toFlamethrowerTrail; +static CTextureObject _toBoubble01; +static CTextureObject _toBoubble02; +static CTextureObject _toBoubble03; +static CTextureObject _toStar01; +static CTextureObject _toStar02; +static CTextureObject _toStar03; +static CTextureObject _toStar04; +static CTextureObject _toStar05; +static CTextureObject _toStar06; +static CTextureObject _toStar07; +static CTextureObject _toStar08; +static CTextureObject _toBlood; +static CTextureObject _toWaterfallGradient; +static CTextureObject _toGhostbusterBeam; +static CTextureObject _toLightning; +static CTextureObject _toSand; +static CTextureObject _toSandFlowGradient; +static CTextureObject _toWater; +static CTextureObject _toWaterFlowGradient; +static CTextureObject _toLava; +static CTextureObject _toLavaFlowGradient; +static CTextureObject _toBloodSprayTexture; +static CTextureObject _toFlowerSprayTexture; +static CTextureObject _toBonesSprayTexture; +static CTextureObject _toFeatherSprayTexture; +static CTextureObject _toStonesSprayTexture; +static CTextureObject _toLavaSprayTexture; +static CTextureObject _toBeastProjectileSprayTexture; +static CTextureObject _toLavaEruptingTexture; +static CTextureObject _toWoodSprayTexture; +static CTextureObject _toLavaBombTrailSmoke; +static CTextureObject _toLavaBombTrailGradient; +static CTextureObject _toElectricitySparks; +static CTextureObject _toBeastProjectileTrailTexture; +static CTextureObject _toBeastProjectileTrailGradient; +static CTextureObject _toBeastBigProjectileTrailTexture; +static CTextureObject _toBeastBigProjectileTrailGradient; +static CTextureObject _toBeastDebrisTrailGradient; +static CTextureObject _toBeastDebrisTrailTexture; +static CTextureObject _toRaindrop; +static CTextureObject _toSnowdrop; +static CTextureObject _toBulletStone; +static CTextureObject _toBulletSand; +static CTextureObject _toBulletSpark; +static CTextureObject _toBulletSmoke; +static CTextureObject _toBulletWater; +static CTextureObject _toPlayerParticles; +static CTextureObject _toWaterfallFoam; +static CTextureObject _toMetalSprayTexture; + +// array for model vertices in absolute space +CStaticStackArray avVertices; + +#define CT_MAX_PARTICLES_TABLE 512 + +FLOAT afTimeOffsets[CT_MAX_PARTICLES_TABLE]; +FLOAT afStarsPositions[CT_MAX_PARTICLES_TABLE][3]; +UBYTE auStarsColors[CT_MAX_PARTICLES_TABLE][3]; + +void InitParticleTables(void); + +// init particle effects +void InitParticles(void) +{ + try + { + _toRomboidTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Romboid.tex")); + _toBombTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\WhiteBubble.tex")); + _toFirecrackerTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\FireCracker.tex")); + _toSpiralTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Smoke01.tex")); + _toColoredStarsTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Star01.tex")); + _toFireball01Trail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Fireball01.tex")); + _toGrenadeTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Smoke02.tex")); + _toCannonBall.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\CannonBall.tex")); + _toRocketTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Smoke06.tex")); + _toVerticalGradient.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\VerticalGradient.tex")); + _toVerticalGradientAlpha.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\VerticalGradientAlpha.tex")); + _toBlood01Trail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Blood02.tex")); + _toLavaTrailGradient.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\LavaTrailGradient.tex")); + _toLavaTrailSmoke.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\LavaTrailSmoke.tex")); + _toFlamethrowerTrail.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\FlameThrower01.tex")); + _toBoubble01.SetData_t(CTFILENAME("Models\\Items\\Particles\\Boubble01.tex")); + _toBoubble02.SetData_t(CTFILENAME("Models\\Items\\Particles\\Boubble02.tex")); + _toBoubble03.SetData_t(CTFILENAME("Models\\Items\\Particles\\Boubble03.tex")); + _toStar01.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star01.tex")); + _toStar02.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star02.tex")); + _toStar03.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star03.tex")); + _toStar04.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star04.tex")); + _toStar05.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star05.tex")); + _toStar06.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star06.tex")); + _toStar07.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star07.tex")); + _toStar08.SetData_t(CTFILENAME("Models\\Items\\Particles\\Star08.tex")); + _toWaterfallGradient.SetData_t(CTFILENAME("Models\\Effects\\Heatmaps\\Waterfall08.tex")); + _toGhostbusterBeam.SetData_t(CTFILENAME("Models\\Weapons\\GhostBuster\\Projectile\\Ray.tex")); + _toLightning.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Lightning.tex")); + _toSand.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Sand.tex")); + _toSandFlowGradient.SetData_t(CTFILENAME("Models\\Effects\\Heatmaps\\SandFlow01.tex")); + _toWater.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Water.tex")); + _toWaterFlowGradient.SetData_t(CTFILENAME("Models\\Effects\\Heatmaps\\WaterFlow01.tex")); + _toLava.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Lava.tex")); + _toLavaFlowGradient.SetData_t(CTFILENAME("Models\\Effects\\Heatmaps\\LavaFlow01.tex")); + _toBloodSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Blood03.tex")); + _toFlowerSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Flowers.tex")); + _toBonesSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BonesSpill01.tex")); + _toFeatherSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\FeatherSpill01.tex")); + _toStonesSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\StonesSpill01.tex")); + _toLavaSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\LavaSpill01.tex")); + _toBeastProjectileSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastProjectileSpill.tex")); + _toLavaEruptingTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\LavaErupting.tex")); + _toWoodSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\WoodSpill01.tex")); + _toLavaBombTrailSmoke.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\LavaBomb.tex")); + _toLavaBombTrailGradient.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\LavaBombGradient.tex")); + _toBeastDebrisTrailGradient.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastDebrisTrailGradient.tex")); + _toBeastProjectileTrailTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastProjectileTrail.tex")); + _toBeastProjectileTrailGradient.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastProjectileTrailGradient.tex")); + _toBeastBigProjectileTrailTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastBigProjectileTrail.tex")); + _toBeastBigProjectileTrailGradient.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastBigProjectileTrailGradient.tex")); + _toBeastDebrisTrailTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BeastDebrisTrail.tex")); + _toElectricitySparks.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\ElectricitySparks.tex")); + _toRaindrop.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Raindrop.tex")); + _toSnowdrop.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\Snowdrop.tex")); + _toBulletStone.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BulletSpray.tex")); + _toBulletWater.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BulletSprayWater.tex")); + _toBulletSand.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BulletSpraySand.tex")); + _toBulletSpark.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\BulletSpark.tex")); + _toBulletSmoke.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\SmokeAnim01.tex")); + _toPlayerParticles.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\PlayerParticles.tex")); + _toWaterfallFoam.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\WaterfallFoam.tex")); + _toMetalSprayTexture.SetData_t(CTFILENAME("Textures\\Effects\\Particles\\MetalSpill.tex")); + + ((CTextureData*)_toLavaTrailGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toLavaBombTrailGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toBeastDebrisTrailGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toBeastProjectileTrailGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toBeastBigProjectileTrailGradient.GetData())->Force(TEX_STATIC); + ((CTextureData*)_toWaterfallGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toSandFlowGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toWaterFlowGradient .GetData())->Force(TEX_STATIC); + ((CTextureData*)_toLavaFlowGradient .GetData())->Force(TEX_STATIC); + } + catch(char *strError) + { + FatalError(TRANS("Unable to obtain texture: %s"), strError); + } + InitParticleTables(); +} + +// close particle effects +void CloseParticles(void) +{ + _toRomboidTrail.SetData(NULL); + _toBombTrail.SetData(NULL); + _toFirecrackerTrail.SetData(NULL); + _toSpiralTrail.SetData(NULL); + _toColoredStarsTrail.SetData(NULL); + _toFireball01Trail.SetData(NULL); + _toRocketTrail.SetData(NULL); + _toGrenadeTrail.SetData(NULL); + _toCannonBall.SetData(NULL); + _toVerticalGradient.SetData(NULL); + _toVerticalGradientAlpha.SetData(NULL); + _toBlood01Trail.SetData(NULL); + _toLavaTrailGradient.SetData(NULL); + _toWaterfallGradient.SetData(NULL); + _toGhostbusterBeam.SetData( NULL); + _toLightning.SetData( NULL); + _toLavaTrailSmoke.SetData(NULL); + _toFlamethrowerTrail.SetData(NULL); + _toBoubble01.SetData(NULL); + _toBoubble02.SetData(NULL); + _toBoubble03.SetData(NULL); + _toStar01.SetData(NULL); + _toStar02.SetData(NULL); + _toStar03.SetData(NULL); + _toStar04.SetData(NULL); + _toStar05.SetData(NULL); + _toStar06.SetData(NULL); + _toStar07.SetData(NULL); + _toStar08.SetData(NULL); + _toSand.SetData(NULL); + _toSandFlowGradient.SetData(NULL); + _toWater.SetData(NULL); + _toWaterFlowGradient.SetData(NULL); + _toLava.SetData(NULL); + _toLavaFlowGradient.SetData(NULL); + _toLavaBombTrailSmoke.SetData(NULL); + _toLavaBombTrailGradient.SetData(NULL); + _toBloodSprayTexture.SetData(NULL); + _toFlowerSprayTexture.SetData(NULL); + _toBonesSprayTexture.SetData(NULL); + _toFeatherSprayTexture.SetData(NULL); + _toStonesSprayTexture.SetData(NULL); + _toLavaSprayTexture.SetData(NULL); + _toBeastProjectileSprayTexture.SetData(NULL); + _toLavaEruptingTexture.SetData(NULL); + _toWoodSprayTexture.SetData(NULL); + _toElectricitySparks.SetData(NULL); + _toBeastDebrisTrailGradient.SetData(NULL); + _toBeastProjectileTrailTexture.SetData(NULL); + _toBeastProjectileTrailGradient.SetData(NULL); + _toBeastBigProjectileTrailTexture.SetData(NULL); + _toBeastBigProjectileTrailGradient.SetData(NULL); + _toBeastDebrisTrailTexture.SetData(NULL); + _toRaindrop.SetData(NULL); + _toSnowdrop.SetData(NULL); + _toBulletStone.SetData(NULL); + _toBulletWater.SetData(NULL); + _toBulletSand.SetData(NULL); + _toBulletSpark.SetData(NULL); + _toBulletSmoke.SetData(NULL); + _toPlayerParticles.SetData(NULL); + _toWaterfallFoam.SetData(NULL); + _toMetalSprayTexture.SetData(NULL); +} + +void Particles_ViewerLocal(CEntity *penView) +{ + ASSERT(penView!=NULL); + + // ----------- Obtain world settings controller + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) penView->GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) + { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + + // ***** Storm appearing effects + // if world settings controller is valid + if( (pwsc != NULL) && (pwsc->m_tmStormStart != -1)) + { + FLOAT fStormFactor = pwsc->GetStormFactor(); + if( fStormFactor != 0.0f) + { + FLOATaabbox3D boxRainMap; + CTextureData *ptdRainMap; + pwsc->GetHeightMapData( ptdRainMap, boxRainMap); + Particles_Rain( penView, 1.25f, 32, fStormFactor, ptdRainMap, boxRainMap); + } + } +} + +// different particle effects +#define ROMBOID_TRAIL_POSITIONS 16 +void Particles_RomboidTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(ROMBOID_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toRomboidTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + for(INDEX iPos = 0; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos = plp->GetPosition(iPos); + FLOAT fRand = rand()/FLOAT(RAND_MAX); + FLOAT fAngle = fSeconds*256+iPos*2.0f*PI/ROMBOID_TRAIL_POSITIONS; + FLOAT fSin = FLOAT(sin(fAngle)); + vPos(2) += fSin*iPos/ROMBOID_TRAIL_POSITIONS; + FLOAT fSize = (ROMBOID_TRAIL_POSITIONS-iPos)*0.5f/ROMBOID_TRAIL_POSITIONS+0.1f; + UBYTE ub = 255-iPos*255/ROMBOID_TRAIL_POSITIONS; + Particle_RenderSquare( vPos, fSize, fAngle, RGBToColor(255-ub,ub,255-ub)|ub); + } + // all done + Particle_Flush(); +} + +#define BOMB_TRAIL_POSITIONS 8 +#define BOMB_TRAIL_INTERPOSITIONS 4 +void Particles_BombTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(BOMB_TRAIL_POSITIONS); +} +void Particles_BombTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(BOMB_TRAIL_POSITIONS); + + Particle_PrepareTexture(&_toBombTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(plp->lp_ctUsed-1); + for(INDEX iPos = plp->lp_ctUsed-1; iPos>=1; iPos--) + { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + for (INDEX iInter=0; iInterGetLastPositions(FIRECRACKER_TRAIL_POSITIONS); +} +void Particles_FirecrackerTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(FIRECRACKER_TRAIL_POSITIONS); + Particle_PrepareTexture(&_toFirecrackerTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + if( plp->lp_ctUsed<2) return; + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(plp->lp_ctUsed-1); + INDEX iParticle = plp->lp_ctUsed*FIRECRACKER_TRAIL_INTERPOSITIONS; + for(INDEX iPos = plp->lp_ctUsed-2; iPos>=0; iPos--) + { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + for (INDEX iInter=0; iInterGetLastPositions(SPIRAL_TRAIL_POSITIONS); + + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + Particle_PrepareTexture(&_toSpiralTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + for(INDEX iPos = 0; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos = plp->GetPosition(iPos); + FLOAT fAngle = fSeconds*32.0f+iPos*2*PI/SPIRAL_TRAIL_POSITIONS; + FLOAT fSin = FLOAT(sin(fAngle)); + FLOAT fCos = FLOAT(cos(fAngle)); + + vPos(1) += fSin*iPos*1.0f/SPIRAL_TRAIL_POSITIONS; + vPos(2) += fCos*iPos*1.0f/SPIRAL_TRAIL_POSITIONS; + + UBYTE ub = iPos*SPIRAL_TRAIL_POSITIONS; + Particle_RenderSquare( vPos, 0.2f, fAngle, RGBToColor(ub,ub,ub)|ub); + } + // all done + Particle_Flush(); +} + +static COLOR _aColors[] = { C_WHITE, C_GRAY, + C_RED, C_GREEN, C_BLUE, C_CYAN, C_MAGENTA, C_YELLOW, C_ORANGE, C_BROWN, C_PINK, + C_lRED, C_lGREEN, C_lBLUE, C_lCYAN, C_lMAGENTA, C_lYELLOW, C_lORANGE, C_lBROWN, C_lPINK +}; + +#define COLORED_STARS_TRAIL_POSITIONS 16 +void Particles_ColoredStarsTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(COLORED_STARS_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toColoredStarsTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + for(INDEX iPos = 0; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos1 = plp->GetPosition(iPos); + //FLOAT3D vPos2 = vPos1; + + FLOAT fAngle = fSeconds*64.0f+iPos*2*PI/COLORED_STARS_TRAIL_POSITIONS; + FLOAT fSin = FLOAT(sin(fAngle)); + //FLOAT fCos = FLOAT(cos(fAngle)); + + FLOAT fDeltaY = fSin/2.0f; + vPos1(2) += fDeltaY; + //vPos2(2) -= fDeltaY; + + FLOAT fRand = rand()/FLOAT(RAND_MAX); + INDEX iRandColor = INDEX(fRand*sizeof(_aColors)/sizeof(COLOR)); + COLOR colColor1 = _aColors[ iRandColor]; + Particle_RenderSquare( vPos1, 0.4f, fAngle, colColor1); + } + // all done + Particle_Flush(); +} + +#define WHITE_LINE_TRAIL_POSITIONS 8 +void Particles_WhiteLineTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(WHITE_LINE_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toSpiralTrail, PBT_ADD); + Particle_SetTexturePart( 1, 1, 256, 256); + + FLOAT3D vOldPos = plp->GetPosition(0); + for(INDEX iPos = 1; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos = plp->GetPosition(iPos); + FLOAT fAngle = fSeconds*4.0f+iPos*PI/WHITE_LINE_TRAIL_POSITIONS; + FLOAT fSin = FLOAT(sin(fAngle)); + FLOAT fCos = FLOAT(cos(fAngle)); + + vPos(1) += fSin*iPos*1.0f/WHITE_LINE_TRAIL_POSITIONS; + vPos(2) += fCos*iPos*1.0f/WHITE_LINE_TRAIL_POSITIONS; + + UBYTE ub = 255-iPos*256/WHITE_LINE_TRAIL_POSITIONS; + FLOAT fLerpFactor = FLOAT(iPos)/WHITE_LINE_TRAIL_POSITIONS; + COLOR colColor = LerpColor( C_YELLOW, C_dRED, fLerpFactor); + Particle_RenderLine( vPos, vOldPos, 0.05f, colColor); + vOldPos =vPos; + } + // all done + Particle_Flush(); +} + + +#define FIREBALL01_TRAIL_POSITIONS 8 +#define FIREBALL01_TRAIL_INTERPOSITIONS 4 +#define FIREBALL01_TRAIL_PARTICLES (FIREBALL01_TRAIL_INTERPOSITIONS*FIREBALL01_TRAIL_POSITIONS) +void Particles_Fireball01Trail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(FIREBALL01_TRAIL_POSITIONS); +} +void Particles_Fireball01Trail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(FIREBALL01_TRAIL_POSITIONS); + Particle_PrepareTexture(&_toFireball01Trail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(plp->lp_ctUsed-1); + INDEX iParticle = 0; + INDEX iParticlesLiving = plp->lp_ctUsed*FIREBALL01_TRAIL_INTERPOSITIONS; + for(INDEX iPos = plp->lp_ctUsed-2; iPos>=0; iPos--) { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + COLOR colColor; + for (INDEX iInter=0; iInterGetLastPositions(GRENADE_TRAIL_POSITIONS); +} +void Particles_GrenadeTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(GRENADE_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toGrenadeTrail, PBT_MULTIPLY); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(0); + INDEX iParticle = 0; + INDEX iParticlesLiving = plp->lp_ctUsed*GRENADE_TRAIL_INTERPOSITIONS; + for(INDEX iPos = 1; iPoslp_ctUsed; iPos++) + { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + for (INDEX iInter=0; iInterGetLastPositions(CANNON_TRAIL_POSITIONS); +} +void Particles_CannonBall(CEntity *pen, FLOAT fSpeedRatio) +{ + CLastPositions *plp = pen->GetLastPositions(CANNON_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toCannonBall, PBT_BLEND); + Particle_SetTexturePart( 512, 512, 0, 0); + + FLOAT3D vOldPos = plp->GetPosition(1); + for( INDEX iPos=2; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos = plp->GetPosition(iPos); + UBYTE ub = UBYTE((255-iPos*256/plp->lp_ctUsed)*fSpeedRatio); + FLOAT fSize = (CANNON_TRAIL_POSITIONS-iPos)*0.04f+0.04f; + Particle_RenderLine( vPos, vOldPos, fSize, RGBToColor(ub,ub,ub)|ub); + vOldPos=vPos; + } + // all done + Particle_Flush(); +} + +#define LAVA_TRAIL_POSITIONS 32 +#define LAVA_TRAIL_INTERPOSITIONS 1 +void Particles_LavaTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(LAVA_TRAIL_POSITIONS); +} +void Particles_LavaTrail(CEntity *pen) +{ + CLastPositions *plp = pen->GetLastPositions(LAVA_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + CTextureData *pTD = (CTextureData *) _toLavaTrailGradient.GetData(); + Particle_PrepareTexture(&_toLavaTrailSmoke, PBT_BLEND); + //Particle_PrepareTexture(&_toLavaTrailSmoke, PBT_MULTIPLY); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(0); + INDEX iParticle = 0; + INDEX iParticlesLiving = plp->lp_ctUsed*LAVA_TRAIL_INTERPOSITIONS; + for(INDEX iPos = 1; iPoslp_ctUsed; iPos++) + { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + for (INDEX iInter=0; iInterGetTexel(PIX(FLOAT(iParticle)/iParticlesLiving*8*1024), 0); + Particle_RenderSquare( vPos, fSize, fAngle, col); + iParticle++; + } + } + // all done + Particle_Flush(); +} + +#define LAVA_BOMB_TRAIL_POSITIONS 16 +#define LAVA_BOMB_TRAIL_INTERPOSITIONS 1 +void Particles_LavaBombTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(LAVA_BOMB_TRAIL_POSITIONS); +} + +void Particles_LavaBombTrail(CEntity *pen, FLOAT fSizeMultiplier) +{ + CLastPositions *plp = pen->GetLastPositions(LAVA_BOMB_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + CTextureData *pTD = (CTextureData *) _toLavaBombTrailGradient.GetData(); + Particle_PrepareTexture(&_toLavaBombTrailSmoke, PBT_BLEND); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(0); + INDEX iParticle = 0; + INDEX iParticlesLiving = plp->lp_ctUsed*LAVA_BOMB_TRAIL_INTERPOSITIONS; + for(INDEX iPos = 1; iPoslp_ctUsed; iPos++) + { + INDEX iRnd = ((ULONG)fSeconds+iPos)%CT_MAX_PARTICLES_TABLE; + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + if( *pvPos1 == *pvPos2) continue; + for (INDEX iInter=0; iInterGetTexel(PIX(FLOAT(iParticle)/iParticlesLiving*8*1024), 0); + Particle_RenderSquare( vPos, fSize, fAngle, col); + iParticle++; + } + } + // all done + Particle_Flush(); +} + +#define BEAST_PROJECTILE_DEBRIS_TRAIL_POSITIONS 8 +#define BEAST_PROJECTILE_DEBRIS_TRAIL_INTERPOSITIONS 1 +void Particles_BeastProjectileDebrisTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(BEAST_PROJECTILE_DEBRIS_TRAIL_POSITIONS); +} + +void Particles_BeastProjectileDebrisTrail(CEntity *pen, FLOAT fSizeMultiplier) +{ + CLastPositions *plp = pen->GetLastPositions(BEAST_PROJECTILE_DEBRIS_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + CTextureData *pTD = (CTextureData *) _toBeastDebrisTrailGradient.GetData(); + Particle_PrepareTexture(&_toBeastDebrisTrailTexture, PBT_BLEND); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(0); + INDEX iParticle = 0; + INDEX iParticlesLiving = plp->lp_ctUsed*BEAST_PROJECTILE_DEBRIS_TRAIL_INTERPOSITIONS; + for(INDEX iPos = 1; iPoslp_ctUsed; iPos++) + { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + for (INDEX iInter=0; iInterGetTexel(PIX(FLOAT(iParticle)/iParticlesLiving*8*1024), 0); + Particle_RenderSquare( vPos, fSize, fAngle, col); + iParticle++; + } + } + // all done + Particle_Flush(); +} + +#define BEAST_PROJECTILE_TRAIL_POSITIONS 32 +#define BEAST_PROJECTILE_TRAIL_INTERPOSITIONS 1 +void Particles_BeastProjectileTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(BEAST_PROJECTILE_TRAIL_POSITIONS); +} + +#define BEAST_PROJECTILE_LINE_PARTICLES 0.4f +#define BEAST_PROJECTILE_FADE_OUT 0.3f +#define BEAST_PROJECTILE_TOTAL_TIME 0.6f +void Particles_BeastProjectileTrail( CEntity *pen, FLOAT fSize, FLOAT fHeight, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toBeastProjectileTrailTexture, PBT_BLEND); + Particle_SetTexturePart( 512, 2048, 0, 0); + + CTextureData *pTD = (CTextureData *) _toBeastProjectileTrailGradient.GetData(); + + CPlacement3D pl = pen->GetLerpedPlacement(); + FLOATmatrix3D m; + MakeRotationMatrixFast(m, pl.pl_OrientationAngle); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( -m(1,3), -m(2,3), -m(3,3)); + FLOAT3D vZ( m(1,2), m(2,2), m(3,2)); + FLOAT3D vCenter = pl.pl_PositionVector+vY*fHeight; + + for( INDEX iStar=0; iStar(1.0f-BEAST_PROJECTILE_FADE_OUT)) fFade=(1-fT)*(1/BEAST_PROJECTILE_FADE_OUT); + else fFade=1.0f; + +#define GET_POS( time) vCenter + \ + vX*(afStarsPositions[iStar][0]*time*fSize*1.5) +\ + vY*(-time*time*10.0f+(afStarsPositions[iStar][1]*2+2.0f)*1.2f*time) +\ + vZ*(afStarsPositions[iStar][2]*time*fSize*1.5); + + FLOAT3D vPos = GET_POS( fT); + COLOR colStar = pTD->GetTexel( FloatToInt(fT*8192), 0); + + if( fT>BEAST_PROJECTILE_LINE_PARTICLES) + { + FLOAT fTimeOld = fT-0.25f; + FLOAT3D vOldPos = GET_POS( fTimeOld); + Particle_RenderLine( vOldPos, vPos, 0.4f, colStar); + } + else + { + Particle_RenderSquare( vPos, 0.5f, fT*360.0f, colStar); + } + } + // all done + Particle_Flush(); +} + +#define BEAST_BIG_PROJECTILE_TRAIL_POSITIONS 32 +#define BEAST_BIG_PROJECTILE_TRAIL_INTERPOSITIONS 1 +void Particles_BeastBigProjectileTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(BEAST_BIG_PROJECTILE_TRAIL_POSITIONS); +} + +#define BIG_BEAST_PROJECTILE_LINE_PARTICLES 0.4f +#define BIG_BEAST_PROJECTILE_FADE_OUT 0.4f +#define BIG_BEAST_PROJECTILE_TOTAL_TIME 0.6f +void Particles_BeastBigProjectileTrail( CEntity *pen, FLOAT fSize, FLOAT fZOffset, FLOAT fYOffset, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toBeastBigProjectileTrailTexture, PBT_BLEND); + Particle_SetTexturePart( 512, 2048, 0, 0); + + CTextureData *pTD = (CTextureData *) _toBeastBigProjectileTrailGradient.GetData(); + + CPlacement3D pl = pen->GetLerpedPlacement(); + FLOATmatrix3D m; + MakeRotationMatrixFast(m, pl.pl_OrientationAngle); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( -m(1,3), -m(2,3), -m(3,3)); + FLOAT3D vZ( m(1,2), m(2,2), m(3,2)); + FLOAT3D vCenter = pl.pl_PositionVector+vY*fZOffset+vZ*fYOffset; + + for( INDEX iStar=0; iStar(1.0f-BIG_BEAST_PROJECTILE_FADE_OUT)) fFade=(1-fT)*(1/BIG_BEAST_PROJECTILE_FADE_OUT); + else fFade=1.0f; + +#define GET_POS_BIG( time) vCenter + \ + vX*(afStarsPositions[iStar][0]*time*fSize*1.5) +\ + vY*(time*time*-15.0f+(afStarsPositions[iStar][1]*2+3.0f)*1.2f*time) +\ + vZ*(afStarsPositions[iStar][2]*time*fSize*1.5); + + FLOAT3D vPos = GET_POS_BIG( fT); + COLOR colStar = pTD->GetTexel( FloatToInt(fT*8192), 0); + + if( fT>BIG_BEAST_PROJECTILE_LINE_PARTICLES) + { + FLOAT fTimeOld = fT-0.125f; + FLOAT3D vOldPos = GET_POS_BIG( fTimeOld); + Particle_RenderLine( vOldPos, vPos, 0.6f*fFade, colStar); + } + else + { + Particle_RenderSquare( vPos, 0.5, fT*360.0f, colStar); + } + } + // all done + Particle_Flush(); +} + +#define ROCKET_TRAIL_POSITIONS 16 +#define ROCKET_TRAIL_INTERPOSITIONS 3 +void Particles_RocketTrail_Prepare(CEntity *pen) +{ + pen->GetLastPositions(ROCKET_TRAIL_POSITIONS); +} +void Particles_RocketTrail(CEntity *pen, FLOAT fStretch) +{ + CLastPositions *plp = pen->GetLastPositions(ROCKET_TRAIL_POSITIONS); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toRocketTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D *pvPos1; + const FLOAT3D *pvPos2 = &plp->GetPosition(1); + INDEX iParticle = 0; + INDEX iParticlesLiving = plp->lp_ctUsed*ROCKET_TRAIL_INTERPOSITIONS; + for( INDEX iPos=2; iPoslp_ctUsed; iPos++) + { + pvPos1 = pvPos2; + pvPos2 = &plp->GetPosition(iPos); + if( (*pvPos2 - *pvPos1).Length() == 0.0f) + { + continue; + } + for (INDEX iInter=0; iInterGetPosition(1); + for( INDEX iPos=2; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos = plp->GetPosition(iPos); + if( (vPos - vOldPos).Length() == 0.0f) + { + continue; + } + UBYTE ub = UBYTE(255-iPos*256/plp->lp_ctUsed); + FLOAT fSize = iPos*0.01f*fStretch+0.005f; + Particle_RenderLine( vPos, vOldPos, fSize, RGBToColor(ub,ub,ub)|ub); + vOldPos=vPos; + } + // all done + Particle_Flush(); +} + + +#define BLOOD01_TRAIL_POSITIONS 15 +void Particles_BloodTrail(CEntity *pen) +{ + // get blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + if( iBloodType<1) return; + COLOR col; + if( iBloodType==3) Particle_PrepareTexture( &_toFlowerSprayTexture, PBT_BLEND); + else Particle_PrepareTexture( &_toBloodSprayTexture, PBT_BLEND); + + CLastPositions *plp = pen->GetLastPositions(BLOOD01_TRAIL_POSITIONS); + FLOAT fGA = ((CMovableEntity *)pen)->en_fGravityA; + FLOAT3D vGDir = ((CMovableEntity *)pen)->en_vGravityDir; + + for( INDEX iPos=0; iPoslp_ctUsed; iPos++) + { + Particle_SetTexturePart( 256, 256, iPos%8, 0); + FLOAT3D vPos = plp->GetPosition(iPos); + FLOAT fRand = rand()/FLOAT(RAND_MAX); + FLOAT fAngle = iPos*2.0f*PI/BLOOD01_TRAIL_POSITIONS; + FLOAT fSin = FLOAT(sin(fAngle)); + FLOAT fT = iPos*_pTimer->TickQuantum; + vPos += vGDir*fGA*fT*fT/8.0f; + FLOAT fSize = 0.2f-iPos*0.15f/BLOOD01_TRAIL_POSITIONS; + UBYTE ub = 255-iPos*255/BLOOD01_TRAIL_POSITIONS; + if( iBloodType==3) col = C_WHITE|ub; + else if( iBloodType==2) col = RGBAToColor(ub,20,20,ub); + else col = RGBAToColor(0,ub,0,ub); + Particle_RenderSquare( vPos, fSize, fAngle, col); + } + // all done + Particle_Flush(); +} + + +INDEX Particles_FireBreath(CEntity *pen, FLOAT3D vSource, FLOAT3D vTarget, FLOAT tmStart, FLOAT tmStop) +{ + Particle_PrepareTexture( &_toFlamethrowerTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fFlameLife = 2; + INDEX ctFlames = 32; + INDEX ctRendered = 0; + FLOAT tmFlameDelta = 0.25f; + FLOAT3D vFocus = Lerp( vSource, vTarget, 0.25f); + for( INDEX iFlame=0; iFlamefFlameLife || tmFakeStart>tmStop) continue; + // calculate fraction part + FLOAT fT=fPassedTime/fFlameLife; + fT=fT-INDEX(fT); + // lerp position + FLOAT3D vRnd = FLOAT3D( afStarsPositions[iFlame][0],afStarsPositions[iFlame][1], + afStarsPositions[iFlame][2])*10; + FLOAT3D vPos = Lerp( vSource, vFocus+vRnd, fT); + FLOAT fSize = 5.0f*fT+5.0f; + UBYTE ub = CalculateRatio( fT, 0.0f, 1.0f, 0.1f, 0.2f)*255; + Particle_RenderSquare( vPos, fSize, fT*(1.0f+afStarsPositions[iFlame*3][1])*360.0f, RGBToColor(ub,ub,ub)|0xFF); + ctRendered++; + } + // all done + Particle_Flush(); + return ctRendered; +} + +INDEX Particles_Regeneration(CEntity *pen, FLOAT tmStart, FLOAT tmStop, FLOAT fYFactor, BOOL bDeath) +{ + Particle_PrepareTexture( &_toElectricitySparks, PBT_BLEND); + Particle_SetTexturePart( 512, 1024, 0, 0); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fLife = 1.5; + INDEX ctRendered = 0; + FLOAT tmDelta = 0.001f; + for( INDEX iVtx=0; iVtx<1024*4; iVtx++) + { + FLOAT tmFakeStart = tmStart+iVtx*tmDelta; + FLOAT fPassedTime = fNow-tmFakeStart; + if(fPassedTime<0.0f || fPassedTime>fLife || tmFakeStart>tmStop) continue; + // calculate fraction part + FLOAT fT=fPassedTime/fLife; + fT=fT-INDEX(fT); + + INDEX iRnd = iVtx%CT_MAX_PARTICLES_TABLE; + FLOAT3D vRnd= FLOAT3D(afStarsPositions[iRnd][0],afStarsPositions[iRnd][1]+0.5f,afStarsPositions[iRnd][2]); + vRnd(1) *= 800.0f; + vRnd(2) *= 400.0f; + vRnd(3) *= 800.0f; + FLOAT3D vSource = vCenter+vRnd; + FLOAT3D vDestination = vCenter+vRnd*0.05f; + vDestination(2) += 40.0f*fYFactor+vRnd(2)/8.0f*fYFactor; + FLOAT3D vPos, vPos2; + // lerp position + if(bDeath) { + vPos = Lerp( vSource, vDestination, 1.0f-fT); + } else { + vPos = Lerp( vSource, vDestination, fT); + } + FLOAT fT2 = Clamp(fT-0.025f-fT*fT*0.025f, 0.0f, 1.0f); + + if(bDeath) { + vPos2 = Lerp( vSource, vDestination, 1.0f-fT2); + } else { + vPos2 = Lerp( vSource, vDestination, fT2); + } + + UBYTE ubR = 192+afStarsPositions[iRnd][1]*64; + UBYTE ubG = 192+afStarsPositions[iRnd][2]*64; + UBYTE ubB = 192+afStarsPositions[iRnd][3]*64; + UBYTE ubA = CalculateRatio( fT, 0.0f, 1.0f, 0.4f, 0.01f)*255; + COLOR colLine = RGBToColor( ubR, ubG, ubB) | ubA; + + FLOAT fSize = 1.0f; + Particle_RenderLine( vPos2, vPos, fSize, colLine); + ctRendered++; + } + + // flush array + avVertices.PopAll(); + // all done + Particle_Flush(); + return ctRendered; +} + +#define SECONDS_PER_PARTICLE 0.01f +void Particles_FlameThrower(const CPlacement3D &plEnd, const CPlacement3D &plStart, + FLOAT fEndElapsed, FLOAT fStartElapsed) +{ + Particle_PrepareTexture( &_toFlamethrowerTrail, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + const FLOAT3D &vStart = plStart.pl_PositionVector; + const FLOAT3D &vEnd = plEnd.pl_PositionVector; + FLOAT3D vDelta = (vEnd-vStart)/(fEndElapsed-fStartElapsed); + FLOAT fSeconds = _pTimer->GetLerpedCurrentTick(); + + for(FLOAT fTime = ceil(fStartElapsed/SECONDS_PER_PARTICLE)*SECONDS_PER_PARTICLE; + fTime0.75f) ub = 0; + else if( fTime>0.5f) ub = (-4*fTime+3)*96; + + ASSERT(fTime>=0.0f); + ASSERT(fSize>=0.0f); + FLOAT3D vPos = vStart+vDelta*(fTime-fStartElapsed)+FLOAT3D(0.0f, fRise, 0.0f); + Particle_RenderSquare( vPos, fSize, fAngle, RGBToColor(ub,ub,ub)|0xFF); + } + // all done + Particle_Flush(); +} + +void SetupParticleTexture(enum ParticleTexture ptTexture) +{ + switch(ptTexture) { + case PT_STAR01: Particle_PrepareTexture(&_toStar01, PBT_ADD); break; + case PT_STAR02: Particle_PrepareTexture(&_toStar02, PBT_ADD); break; + case PT_STAR03: Particle_PrepareTexture(&_toStar03, PBT_ADD); break; + case PT_STAR04: Particle_PrepareTexture(&_toStar04, PBT_ADD); break; + case PT_STAR05: Particle_PrepareTexture(&_toStar05, PBT_ADD); break; + case PT_STAR06: Particle_PrepareTexture(&_toStar06, PBT_ADD); break; + case PT_STAR07: Particle_PrepareTexture(&_toStar07, PBT_ADD); break; + case PT_STAR08: Particle_PrepareTexture(&_toStar08, PBT_ADD); break; + case PT_BOUBBLE01: Particle_PrepareTexture(&_toBoubble01, PBT_ADD); break; + case PT_BOUBBLE02: Particle_PrepareTexture(&_toBoubble02, PBT_ADD); break; + case PT_WATER01: Particle_PrepareTexture(&_toBoubble03, PBT_BLEND); break; + case PT_WATER02: Particle_PrepareTexture(&_toBoubble03, PBT_BLEND); break; + case PT_SANDFLOW: Particle_PrepareTexture(&_toSand, PBT_BLEND); break; + case PT_WATERFLOW: Particle_PrepareTexture(&_toWater, PBT_BLEND); break; + case PT_LAVAFLOW: Particle_PrepareTexture(&_toLava, PBT_BLEND); break; + default: ASSERT(FALSE); + } + Particle_SetTexturePart( 512, 512, 0, 0); +} + +void InitParticleTables(void) +{ + for( INDEX iStar=0; iStar7.0f) return; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + SetupParticleTexture( ptTexture); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + CPlacement3D plSource = pen->GetLerpedPlacement(); + FLOAT3D vCenter = plSource.pl_PositionVector+vY*fHeight; + + for( INDEX iStar=0; iStarSTARDUST_EXIST_TIME) continue; + FLOAT fFade = -2.0f * Abs(fT*(1.0f/STARDUST_EXIST_TIME)-0.5f)+1.0f; + + INDEX iRandomFromPlacement = + (ULONG)(plSource.pl_PositionVector(1)+plSource.pl_PositionVector(3))&(ctOffsetSpace-1); + INDEX iMemeber = iStar+iRandomFromPlacement; + const FLOAT3D vPos = vCenter+FLOAT3D( afStarsPositions[iMemeber][0], + afStarsPositions[iMemeber][1], + afStarsPositions[iMemeber][2])*fSize; + COLOR colStar = RGBToColor( auStarsColors[iMemeber][0]*fFade, + auStarsColors[iMemeber][1]*fFade, + auStarsColors[iMemeber][2]*fFade); + Particle_RenderSquare( vPos, 0.15f, 0, colStar|0xFF); + } + // all done + Particle_Flush(); +} + +#define RISING_TOTAL_TIME 5.0f +#define RISING_EXIST_TIME 3.0f +#define RISING_FADE_IN 0.3f +#define RISING_FADE_OUT 0.3f + +void Particles_Rising(CEntity *pen, FLOAT fStartTime, FLOAT fStopTime, FLOAT fStretchAll, + FLOAT fStretchX, FLOAT fStretchY, FLOAT fStretchZ, FLOAT fSize, + enum ParticleTexture ptTexture, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + if( Particle_GetMipFactor()>7.0f) return; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + SetupParticleTexture( ptTexture); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector+vY*fStretchY; + + FLOAT fPowerFactor = Clamp((fNow - fStartTime)/5.0f,0.0f,1.0f); + fPowerFactor *= Clamp(1+(fStopTime-fNow)/5.0f,0.0f,1.0f); + //ctParticles = FLOAT(ctParticles) * fPowerFactor; + + for( INDEX iStar=0; iStar1) continue; + FLOAT fFade; + if(fF<(RISING_FADE_IN*fPowerFactor)) fFade=fF*(1/(RISING_FADE_IN*fPowerFactor)); + else if (fF>(1.0f-RISING_FADE_OUT)) fFade=(1-fF)*(1/RISING_FADE_OUT); + else fFade=1.0f; + + FLOAT3D vPos = vCenter+FLOAT3D( + afStarsPositions[iStar][0]*fStretchX, + afStarsPositions[iStar][1]*fStretchY, + afStarsPositions[iStar][2]*fStretchZ)*fStretchAll+vY*(fF*fStretchAll*0.5f); + vPos(1)+=sin(fF*4.0f)*0.05f*fStretchAll; + vPos(3)+=cos(fF*4.0f)*0.05f*fStretchAll; + + UBYTE ub = NormFloatToByte( fFade); + COLOR colStar = RGBToColor( ub, ub, ub>>1); + Particle_RenderSquare( vPos, fSize*fPowerFactor, 0, colStar|(UBYTE(0xFF*fPowerFactor))); + } + // all done + Particle_Flush(); +} + +#define CT_SPIRAL_PARTICLES 4 +#define CT_SPIRAL_TRAIL 10 +void Particles_Spiral( CEntity *pen, FLOAT fSize, FLOAT fHeight, + enum ParticleTexture ptTexture, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + + FLOAT fMipFactor = Particle_GetMipFactor(); + if( fMipFactor>7.0f) return; + fMipFactor = 2.5f-fMipFactor*0.3f; + fMipFactor = Clamp( fMipFactor, 0.0f, 1.0f); + INDEX ctSpiralTrail = fMipFactor*CT_SPIRAL_TRAIL; + if( ctSpiralTrail<=0) return; + FLOAT fTrailDelta = 0.1f/fMipFactor; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + SetupParticleTexture( ptTexture); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector+vY*fHeight; + + for( INDEX iStar=0; iStar>1); + Particle_RenderSquare( vPos, 0.2f, 0, colStar|0xFF); + } + } + // all done + Particle_Flush(); +} + +#define EMANATE_FADE_IN 0.2f +#define EMANATE_FADE_OUT 0.6f +#define EMANATE_TOTAL_TIME 1.0f +#define EMANATE_EXIST_TIME 0.5f +void Particles_Emanate( CEntity *pen, FLOAT fSize, FLOAT fHeight, + enum ParticleTexture ptTexture, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + if( Particle_GetMipFactor()>7.0f) return; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + SetupParticleTexture( ptTexture); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector+vY*fHeight; + + for( INDEX iStar=0; iStar1) continue; + FLOAT fFade; + if(fF(1.0f-EMANATE_FADE_OUT)) fFade=(1-fF)*(1/EMANATE_FADE_OUT); + else fFade=1.0f; + + FLOAT3D vPos = vCenter+FLOAT3D( + afStarsPositions[iStar][0], + afStarsPositions[iStar][1], + afStarsPositions[iStar][2])*fSize*(fF+0.4f); + + UBYTE ub = NormFloatToByte( fFade); + COLOR colStar = RGBToColor( ub, ub, ub>>1); + Particle_RenderSquare( vPos, 0.1f, 0, colStar|0xFF); + } + // all done + Particle_Flush(); +} + +#define WATERFALL_FOAM_FADE_IN 0.1f +#define WATERFALL_FOAM_FADE_OUT 0.4f +void Particles_WaterfallFoam(CEntity *pen, FLOAT fSizeX, FLOAT fSizeY, FLOAT fSizeZ, + FLOAT fParticleSize, FLOAT fSpeed, FLOAT fSpeedY, FLOAT fLife, INDEX ctParticles) +{ + if(fLife<=0) return; + + Particle_PrepareTexture( &_toWaterfallFoam, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + for( INDEX iFoam=0; iFoam7.0f) return; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + SetupParticleTexture( ptTexture); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + for( INDEX iStar=0; iStar1) continue; + FLOAT fFade; + if(fF(1.0f-EMANATE_FADE_OUT)) fFade=(1-fF)*(1/EMANATE_FADE_OUT); + else fFade=1.0f; + + FLOAT fX = (afStarsPositions[iStar][0]+0.5f)*fSizeX*(1+fF*fAway); + FLOAT fY = fSizeY*fF; + FLOAT fZ = (afStarsPositions[iStar][2]+0.5f)*fSizeZ*(1+fF*fAway); + FLOAT3D vPos = vCenter + vX*fX + vY*fY + vZ*fZ; + + UBYTE ub = NormFloatToByte( fFade); + COLOR colStar = RGBToColor( ub, ub, ub); + Particle_RenderSquare( vPos, fParticleSize, 0, colStar|0xFF); + } + // all done + Particle_Flush(); +} + +#define CT_FOUNTAIN_TRAIL 3 +#define FOUNTAIN_FADE_IN 0.6f +#define FOUNTAIN_FADE_OUT 0.4f +#define FOUNTAIN_TOTAL_TIME 0.6f +void Particles_Fountain( CEntity *pen, FLOAT fSize, FLOAT fHeight, + enum ParticleTexture ptTexture, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + SetupParticleTexture( ptTexture); + CTextureData *pTD = (CTextureData *) _toWaterfallGradient.GetData(); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector+vY*fHeight; + + for( INDEX iStar=0; iStar(1.0f-FOUNTAIN_FADE_OUT)) fFade=(1-fT)*(1/FOUNTAIN_FADE_OUT); + else fFade=1.0f; + fFade *= (CT_FOUNTAIN_TRAIL-iTrail)*(1.0f/CT_FOUNTAIN_TRAIL); + + FLOAT3D vPos = vCenter + + vX*(afStarsPositions[iStar][0]*fT*fSize) + + vY*(fT*fT*-5.0f+(afStarsPositions[iStar][1]*2+4.0f)*1.2f*fT) + + vZ*(afStarsPositions[iStar][2]*fT*fSize); + + COLOR colStar = pTD->GetTexel( FloatToInt(fFade*2048), 0); + ULONG ulA = FloatToInt( ((colStar&CT_AMASK)>>CT_ASHIFT) * fFade); + colStar = (colStar&~CT_AMASK) | (ulA<en_ulID)%CT_MAX_PARTICLES_TABLE; + Particle_SetTexturePart( 512, 512, iRnd1%3, 0); + + FLOAT fT = _pTimer->GetLerpedCurrentTick()-tmStarted; + FLOAT fBoxSize = boxOwner.Size().Length(); + for(INDEX iSmoke=0; iSmoke<2+fDamage*2; iSmoke++) + { + INDEX iRnd2 = INDEX(tmStarted*12345.0f+iSmoke+fDamage*10.0f)%(CT_MAX_PARTICLES_TABLE/2); + FLOAT fLifeTime = 2.0f+(afStarsPositions[iRnd2][0]+0.5f)*2.0f; + FLOAT fRatio = CalculateRatio(fT, 0, fLifeTime, 0.4f, 0.6f); + + FLOAT fRndAppearX = afStarsPositions[iRnd2][0]*fBoxSize*0.125f; + FLOAT fRndAppearZ = afStarsPositions[iRnd2][2]*fBoxSize*0.125f; + FLOAT3D vPos = pen->GetLerpedPlacement().pl_PositionVector; + vPos(1) += fRndAppearX; + vPos(3) += fRndAppearZ; + vPos(2) += ((afStarsPositions[iRnd2+4][1]+0.5f)*2.0f+1.5f)*fT+boxOwner.Size()(2)*0.0025f; + + COLOR col = C_dGRAY|UBYTE(64.0f*fRatio); + FLOAT fRotation = afStarsPositions[iRnd2+5][0]*360+fT*200.0f*afStarsPositions[iRnd2+3][0]; + FLOAT fSize = + 0.025f*fDamage+ + (afStarsPositions[iRnd2+6][2]+0.5f)*0.075 + + (0.15f+(afStarsPositions[iRnd2+2][1]+0.5f)*0.075f*fBoxSize)*fT; + Particle_RenderSquare( vPos, fSize, fRotation, col); + } + + // all done + Particle_Flush(); +} + +#define RUNNING_DUST_TRAIL_POSITIONS 3*20 +void Particles_RunningDust_Prepare(CEntity *pen) +{ + pen->GetLastPositions(RUNNING_DUST_TRAIL_POSITIONS); +} +void Particles_RunningDust(CEntity *pen) +{ + Particle_PrepareTexture( &_toBulletSmoke, PBT_BLEND); + CLastPositions *plp = pen->GetLastPositions(RUNNING_DUST_TRAIL_POSITIONS); + FLOAT3D vOldPos = plp->GetPosition(1); + for(INDEX iPos = 2; iPoslp_ctUsed; iPos++) + { + FLOAT3D vPos = plp->GetPosition(iPos); + if( (vPos-vOldPos).Length()<1.0f) continue; + FLOAT tmStarted = _pTimer->CurrentTick()-iPos*_pTimer->TickQuantum; + INDEX iRnd = INDEX(Abs(vPos(1)*1234.234f+vPos(2)*9834.123f+vPos(3)*543.532f+pen->en_ulID))%(CT_MAX_PARTICLES_TABLE/2); + if( iRnd&3) continue; + + INDEX iRndTex = iRnd*324561+pen->en_ulID; + Particle_SetTexturePart( 512, 512, iRndTex%3, 0); + + FLOAT fLifeTime = 2.8f-(afStarsPositions[iRnd][1]+0.5f)*1.0f; + + FLOAT fT = _pTimer->GetLerpedCurrentTick()-tmStarted; + FLOAT fRatio = CalculateRatio(fT, 0, fLifeTime, 0.1f, 0.25f); + + FLOAT fRndAppearX = afStarsPositions[iRnd][0]*1.0f; + FLOAT fRndSpeedY = (afStarsPositions[iRnd][1]+0.5f)*0.5f; + FLOAT fRndAppearZ = afStarsPositions[iRnd][2]*1.0f; + vPos(1) += fRndAppearX; + vPos(2) += (0.5f+fRndSpeedY)*fT; + vPos(3) += fRndAppearZ; + + FLOAT fRndBlend = 8.0f+(afStarsPositions[iRnd*2][1]+0.5f)*64.0f; + UBYTE ubRndH = UBYTE( (afStarsPositions[iRnd][0]+0.5f)*64); + UBYTE ubRndS = UBYTE( (afStarsPositions[iRnd][1]+0.5f)*32); + UBYTE ubRndV = UBYTE( 128+afStarsPositions[iRnd][0]*64.0f); + COLOR col = HSVToColor(ubRndH,ubRndS,ubRndV)|UBYTE(fRndBlend*fRatio); + //col=C_RED|CT_OPAQUE; + FLOAT fRotation = afStarsPositions[iRnd+5][0]*360+fT*50.0f*afStarsPositions[iRnd+3][0]; + FLOAT fSize = + 0.75f+(afStarsPositions[iRnd+6][2]+0.5f)*0.25 + // static size + (0.4f+(afStarsPositions[iRnd+2][1]+0.5f)*0.4f)*fT; // dinamic size + Particle_RenderSquare( vPos, fSize, fRotation, col); + vOldPos=vPos; + } + // all done + Particle_Flush(); +} + +void Particles_MetalParts( CEntity *pen, FLOAT tmStarted, FLOATaabbox3D boxOwner, FLOAT fDamage) +{ + Particle_PrepareTexture( &_toMetalSprayTexture, PBT_BLEND); + FLOAT fT = _pTimer->GetLerpedCurrentTick()-tmStarted; + FLOAT fGA = 30.0f; + + FLOAT fBoxSize = boxOwner.Size().Length(); + for(INDEX iPart=0; iPart<6+fDamage*3.0f; iPart++) + { + INDEX iRnd = INDEX(tmStarted*12345.0f+iPart)%CT_MAX_PARTICLES_TABLE; + FLOAT fLifeTime = 2.0f+(afStarsPositions[iRnd][0]+0.5f)*2.0f; + FLOAT fRatio = CalculateRatio(fT, 0, fLifeTime, 0.1f, 0.1f); + Particle_SetTexturePart( 256, 256, ((int(tmStarted*100.0f))%8+iPart)%8, 0); + + FLOAT3D vPos = pen->GetLerpedPlacement().pl_PositionVector; + vPos(1) += afStarsPositions[iRnd][0]*fT*15; + vPos(2) += afStarsPositions[iRnd][1]*fT*15-fGA/2.0f*fT*fT+boxOwner.Size()(2)*0.25f; + vPos(3) += afStarsPositions[iRnd][2]*fT*15; + + UBYTE ubRndH = UBYTE( 180+afStarsPositions[ int(iPart+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*16); + UBYTE ubRndS = UBYTE( 12+(afStarsPositions[ int(iPart+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1])*8); + UBYTE ubRndV = UBYTE( 192+(afStarsPositions[ int(iPart+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*64); + //ubRndS = 0; + ubRndV = 255; + COLOR col = HSVToColor(ubRndH, ubRndS, ubRndV)|UBYTE(255.0f*fRatio); + FLOAT fRotation = fT*400.0f*afStarsPositions[iRnd][0]; + FLOAT fSize = fBoxSize*0.005f+0.125f+afStarsPositions[iRnd][1]*0.025f; + Particle_RenderSquare( vPos, fSize, fRotation, col); + } + + // all done + Particle_Flush(); +} + +#define ELECTRICITY_SPARKS_FADE_OUT_TIME 0.4f +#define ELECTRICITY_SPARKS_TOTAL_TIME 1.0f +void Particles_ElectricitySparks( CEntity *pen, FLOAT fTimeAppear, FLOAT fSize, FLOAT fHeight, INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE/2); + FLOAT fT = _pTimer->GetLerpedCurrentTick()-fTimeAppear; + + Particle_PrepareTexture( &_toElectricitySparks, PBT_BLEND); + Particle_SetTexturePart( 512, 1024, 0, 0); + + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector+vY*fHeight; + + for( INDEX iSpark=0; iSparkELECTRICITY_SPARKS_TOTAL_TIME) + { + fFade=0; + } + else if(fT>ELECTRICITY_SPARKS_FADE_OUT_TIME) + { + fFade=-1.0f/(ELECTRICITY_SPARKS_TOTAL_TIME-ELECTRICITY_SPARKS_FADE_OUT_TIME)*(fT-ELECTRICITY_SPARKS_TOTAL_TIME); + } + else + { + fFade=1.0f; + } + + FLOAT fTold = fT-0.05f; + +#define SPARK_CURVE( time) \ + vCenter + \ + vX*(afStarsPositions[iSpark][0]*time*fSize*3) + \ + vY*(afStarsPositions[iSpark][1]*10.0f*time-(15.0f+afStarsPositions[iSpark*2][1]*15.0f)*time*time) + \ + vZ*(afStarsPositions[iSpark][2]*time*fSize*3); + + FLOAT3D vPosOld = SPARK_CURVE( fTold); + FLOAT3D vPosNew = SPARK_CURVE( fT); + + UBYTE ubR = 224+(afStarsPositions[iSpark][2]+0.5f)*32; + UBYTE ubG = 224+(afStarsPositions[iSpark][2]+0.5f)*32; + UBYTE ubB = 160; + UBYTE ubA = FloatToInt( 255 * fFade); + COLOR colStar = RGBToColor( ubR, ubG, ubB) | ubA; + Particle_RenderLine( vPosOld, vPosNew, 0.075f, colStar); + } + // all done + Particle_Flush(); +} + +void Particles_LavaErupting(CEntity *pen, FLOAT fStretchAll, FLOAT fSize, + FLOAT fStretchX, FLOAT fStretchY, FLOAT fStretchZ, + FLOAT fActivateTime) +{ + FLOAT fT = _pTimer->GetLerpedCurrentTick()-fActivateTime; + if( fT>10.0f) return; + + Particle_PrepareTexture( &_toLavaEruptingTexture, PBT_ADD); + INDEX iTexture = ((ULONG)fActivateTime)%3; + Particle_SetTexturePart( 512, 512, iTexture, 0); + FLOAT fGA = ((CMovableEntity *)pen)->en_fGravityA; + + INDEX iRnd1 = ((ULONG)fActivateTime)%CT_MAX_PARTICLES_TABLE; + INDEX iRnd2 = (~(ULONG)fActivateTime)%CT_MAX_PARTICLES_TABLE; + + FLOAT fRndAppearX = afStarsPositions[iRnd2][0]*fStretchAll; + FLOAT fRndAppearZ = afStarsPositions[iRnd2][1]*fStretchAll; + FLOAT fRndRotation = afStarsPositions[iRnd2][2]; + + FLOAT3D vPos = pen->GetLerpedPlacement().pl_PositionVector; + vPos(1) += fRndAppearX+afStarsPositions[iRnd1][0]*fT*fStretchX*10; + vPos(2) += (fStretchY+(fStretchY*0.25f*afStarsPositions[iRnd1][1]))*fT-fGA/2.0f*fT*fT; + vPos(3) += fRndAppearZ+afStarsPositions[iRnd1][2]*fT*fStretchZ*10; + + Particle_RenderSquare( vPos, fSize+afStarsPositions[iRnd2][3]*fSize*0.5f, fRndRotation*300*fT, C_WHITE|CT_OPAQUE); + + // all done + Particle_Flush(); +} + +#define CT_ATOMIC_TRAIL 32 +void Particles_Atomic( CEntity *pen, FLOAT fSize, FLOAT fHeight, + enum ParticleTexture ptTexture, INDEX ctEllipses) +{ + ASSERT( ctEllipses<=CT_MAX_PARTICLES_TABLE); + FLOAT fMipFactor = Particle_GetMipFactor(); + if( fMipFactor>7.0f) return; + fMipFactor = 2.5f-fMipFactor*0.3f; + fMipFactor = Clamp(fMipFactor, 0.0f ,1.0f); + INDEX ctAtomicTrail = fMipFactor*CT_ATOMIC_TRAIL; + if( ctAtomicTrail<=0) return; + FLOAT fTrailDelta = 0.075f/fMipFactor; + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + SetupParticleTexture( ptTexture); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector+vY*fHeight; + + for( INDEX iEllipse=0; iEllipse>3, ub>>3, ub>>2); + Particle_RenderSquare( vPos, 0.2f, 0, colStar|0xFF); + } + } + // all done + Particle_Flush(); +} + +#define CT_LIGHTNINGS 8 +void Particles_Ghostbuster(const FLOAT3D &vSrc, const FLOAT3D &vDst, INDEX ctRays, FLOAT fSize, FLOAT fPower, + FLOAT fKneeDivider/*=33.3333333f*/) +{ + Particle_PrepareTexture(&_toGhostbusterBeam, PBT_ADD); + Particle_SetTexturePart( 512, 512, 0, 0); + // get direction vector + FLOAT3D vZ = vDst-vSrc; + FLOAT fLen = vZ.Length(); + vZ.Normalize(); + + // get two normal vectors + FLOAT3D vX; + if (Abs(vZ(2))>0.5) { + vX = FLOAT3D(1.0f, 0.0f, 0.0f)*vZ; + } else { + vX = FLOAT3D(0.0f, 1.0f, 0.0f)*vZ; + } + FLOAT3D vY = vZ*vX; + const FLOAT fStep = fLen/fKneeDivider; + + for(INDEX iRay = 0; iRayGetLerpedCurrentTick()/1.5f; + FLOAT fDT = fT-INDEX(fT); + FLOAT fFade = 1-fDT*4.0f; + + if( fFade>1 || fFade<=0) continue; + UBYTE ubFade = NormFloatToByte(fFade*fPower); + COLOR colFade = RGBToColor( ubFade, ubFade, ubFade); + for(FLOAT fPos=fStep; fPosGetLerpedPlacement().pl_PositionVector; + + vPos(1) -= fGridSize*ctGrids/2; + vPos(3) -= fGridSize*ctGrids/2; + + SnapFloat( vPos(1), fGridSize); + SnapFloat( vPos(2), fGridSize); + SnapFloat( vPos(3), fGridSize); + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toRaindrop, PBT_BLEND); + Particle_SetTexturePart( 512, 4096, 0, 0); + + FLOAT fMinX = boxRainMap.Min()(1); + FLOAT fMinY = boxRainMap.Min()(2); + FLOAT fMinZ = boxRainMap.Min()(3); + FLOAT fSizeX = boxRainMap.Size()(1); + FLOAT fSizeY = boxRainMap.Size()(2); + FLOAT fSizeZ = boxRainMap.Size()(3); + PIX pixRainMapW = 1; + PIX pixRainMapH = 1; + + if( ptdRainMap != NULL) + { + pixRainMapW = ptdRainMap->GetPixWidth(); + pixRainMapH = ptdRainMap->GetPixHeight(); + } + + INDEX ctDiscarded=0; + for( INDEX iZ=0; iZ=0 && pixX=0 && pixZGetTexel( pixX, pixZ); + FLOAT fRainMapY = fMinY+((col>>8)&0xFF)/255.0f*fSizeY; + + FLOAT fRainY = vRender(2); + // if tested raindrop is below ceiling + if( fRainY<=fRainMapY) + { + // don't render it + continue; + } else if (fRainY-fSizeGetLerpedPlacement().pl_PositionVector; + + vPos(1) -= fGridSize*ctGrids/2; + vPos(3) -= fGridSize*ctGrids/2; + + SnapFloat( vPos(1), fGridSize); + SnapFloat( vPos(2), fGridSize); + SnapFloat( vPos(3), fGridSize); + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + Particle_PrepareTexture(&_toSnowdrop, PBT_BLEND); + Particle_SetTexturePart( 512, 512, 0, 0); + + for( INDEX iZ=0; iZ0.5) + { + vX = FLOAT3D(1.0f, 0.0f, 0.0f)*vZ; + } + else + { + vX = FLOAT3D(0.0f, 1.0f, 0.0f)*vZ; + } + // we found ortonormal vectors + FLOAT3D vY = vZ*vX; + + FLOAT fAllowRnd = 4.0f/fRandomDivider; + fRandomDivider+=1.0f; + vRenderDest = vSrc+ + vZ*fKneeLen + + vX*(fAllowRnd*afStarsPositions[iRnd][0]*fKneeLen) + + vY*(fAllowRnd*afStarsPositions[iRnd][1]*fKneeLen); + // get new rnd index + iRnd = (iRnd+1) % CT_MAX_PARTICLES_TABLE; + // see if we will spawn new branch of lightning + FLOAT fRnd = ((1-ctBranches/ctMaxBranches)*ctKnees)*afStarsPositions[iRnd][0]; + if( (fRnd < 2.0f) && (fPower>0.25f) ) + { + ctBranches++; + FLOAT3D vNewDirection = (vRenderDest-vSrc).Normalize(); + FLOAT3D vNewDst = vSrc + vNewDirection*fLen; + // recurse into new branch + RenderOneLightningBranch( vSrc, vNewDst, fPath, fTimeStart, fTimeNow, fPower/3.0f, iRnd); + } + } + + // calculate color + UBYTE ubA = UBYTE(fPower*255*fTimeKiller); + // render line + Particle_RenderLine( vSrc, vRenderDest, fPower*2, C_WHITE|ubA); + // add traveled path + fPath += (vRenderDest-vSrc).Length(); + if( fPath/LIGHTNING_SPEED > fPassedTime) + { + bRenderInProgress = FALSE; + } + vSrc = vRenderDest; + } +} + +void Particles_Lightning( FLOAT3D vSrc, FLOAT3D vDst, FLOAT fTimeStart) +{ + Particle_PrepareTexture(&_toLightning, PBT_ADDALPHA); + Particle_SetTexturePart( 512, 512, 0, 0); + + FLOAT fTimeNow = _pTimer->GetLerpedCurrentTick(); + // get rnd index + INDEX iRnd = (INDEX( fTimeStart*100))%CT_MAX_PARTICLES_TABLE; + RenderOneLightningBranch( vSrc, vDst, 0, fTimeStart, fTimeNow, 1.0f, iRnd); + + // all done + Particle_Flush(); +} + +#define CT_SANDFLOW_TRAIL 3 +#define SANDFLOW_FADE_OUT 0.25f +#define SANDFLOW_TOTAL_TIME 1.0f +void Particles_SandFlow( CEntity *pen, FLOAT fStretchAll, FLOAT fSize, FLOAT fHeight, FLOAT fStartTime, FLOAT fStopTime, + INDEX ctParticles) +{ + ASSERT( ctParticles<=CT_MAX_PARTICLES_TABLE); + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + SetupParticleTexture( PT_SANDFLOW); + CTextureData *pTD = (CTextureData *) _toSandFlowGradient.GetData(); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + FLOAT fPowerFactor = Clamp((fNow - fStartTime)/2.0f,0.0f,1.0f); + fPowerFactor *= Clamp(1+(fStopTime-fNow)/2.0f,0.0f,1.0f); + ctParticles = FLOAT(ctParticles) * fPowerFactor; + fHeight *= fPowerFactor; + for( INDEX iStar=0; iStarfStopTime+2.0f) ) continue; + FLOAT fFade; + if (fT>(1.0f-SANDFLOW_FADE_OUT)) fFade=(1-fT)*(1/SANDFLOW_FADE_OUT); + else fFade=1.0f; + fFade *= (CT_SANDFLOW_TRAIL-iTrail)*(1.0f/CT_SANDFLOW_TRAIL); + + FLOAT3D vPos = vCenter + + vX*(afStarsPositions[iStar][0]*fStretchAll*fPowerFactor+fHeight*fT) + + vY*(fT*fT*-5.0f+(afStarsPositions[iStar][1]*fPowerFactor*0.1)) + + vZ*(afStarsPositions[iStar][2]*fPowerFactor*fT*fStretchAll); + + COLOR colSand = pTD->GetTexel( FloatToInt(fT*2048), 0); + ULONG ulA = FloatToInt( ((colSand&CT_AMASK)>>CT_ASHIFT) * fFade); + colSand = (colSand&~CT_AMASK) | (ulA<GetLerpedCurrentTick(); + + SetupParticleTexture( PT_WATERFLOW); + CTextureData *pTD = (CTextureData *) _toWaterFlowGradient.GetData(); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + FLOAT fPowerFactor = Clamp((fNow - fStartTime)/2.0f,0.0f,1.0f); + fPowerFactor *= Clamp(1+(fStopTime-fNow)/2.0f,0.0f,1.0f); + ctParticles = FLOAT(ctParticles) * fPowerFactor; + fHeight *= fPowerFactor; + for( INDEX iStar=0; iStarfStopTime+2.0f) ) continue; + FLOAT fFade; + if (fT>(1.0f-WATER_FLOW_FADE_OUT)) fFade=(1-fT)*(1/WATER_FLOW_FADE_OUT); + else fFade=1.0f; + fFade *= (CT_WATER_FLOW_TRAIL-iTrail)*(1.0f/CT_WATER_FLOW_TRAIL); + + FLOAT3D vPos = vCenter + + vX*(afStarsPositions[iStar][0]*fStretchAll*fPowerFactor+fHeight*fT) + + vY*(fT*fT*-5.0f+(afStarsPositions[iStar][1]*fPowerFactor*0.1)) + + vZ*(afStarsPositions[iStar][2]*fPowerFactor*fT*fStretchAll); + + COLOR colWater = pTD->GetTexel( FloatToInt(fT*2048), 0); + ULONG ulA = FloatToInt( ((colWater&CT_AMASK)>>CT_ASHIFT) * fFade); + colWater = (colWater&~CT_AMASK) | (ulA<GetLerpedCurrentTick(); + + SetupParticleTexture( PT_LAVAFLOW); + CTextureData *pTD = (CTextureData *) _toLavaFlowGradient.GetData(); + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + FLOAT fPowerFactor = Clamp((fNow - fStartTime)/2.0f,0.0f,1.0f); + fPowerFactor *= Clamp(1+(fStopTime-fNow)/2.0f,0.0f,1.0f); + ctParticles = FLOAT(ctParticles) * fPowerFactor; + fHeight *= fPowerFactor; + for( INDEX iStar=0; iStarfStopTime+2.0f) ) continue; + FLOAT fFade; + if (fT>(1.0f-LAVA_FLOW_FADE_OUT)) fFade=(1-fT)*(1/LAVA_FLOW_FADE_OUT); + else fFade=1.0f; + fFade *= (CT_LAVA_FLOW_TRAIL-iTrail)*(1.0f/CT_LAVA_FLOW_TRAIL); + + FLOAT3D vPos = vCenter + + vX*(afStarsPositions[iStar][0]*fStretchAll*fPowerFactor+fHeight*fT) + + vY*(fT*fT*-4.0f+(afStarsPositions[iStar][1]*fPowerFactor*0.1)) + + vZ*(afStarsPositions[iStar][2]*fPowerFactor*fT*fStretchAll); + + COLOR colLava = pTD->GetTexel( FloatToInt(fT*2048), 0); + ULONG ulA = FloatToInt( ((colLava&CT_AMASK)>>CT_ASHIFT) * fFade); + colLava = (colLava&~CT_AMASK) | (ulA<GetLerpedPlacement().pl_PositionVector; + FLOAT fFadeStart = BULLET_SPRAY_FADEOUT_START; + FLOAT fLifeTotal = BULLET_SPRAY_TOTAL_TIME; + FLOAT fFadeLen = fLifeTotal-fFadeStart; + COLOR colStones = C_WHITE; + + FLOAT fMipFactor = Particle_GetMipFactor(); + FLOAT fDisappear = 1.0f; + if( fMipFactor>8.0f) return; + if( fMipFactor>6.0f) + { + fDisappear = 1.0f-(fMipFactor-6.0f)/2.0f; + } + + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fT=(fNow-tmSpawn); + if( fT>fLifeTotal) return; + INDEX iRnd = INDEX( (tmSpawn*1000.0f)+pen->en_ulID) &63; + FLOAT fSizeStart; + FLOAT fSpeedStart; + FLOAT fConeMultiplier = 1.0f; + COLOR colSmoke; + + switch( eptType) + { + case EPT_BULLET_WATER: + { + Particle_PrepareTexture(&_toBulletWater, PBT_BLEND); + fSizeStart = 0.08f; + fSpeedStart = 1.75f; + fConeMultiplier = 0.125f; + + FLOAT fFadeStart = BULLET_SPRAY_WATER_FADEOUT_START; + FLOAT fLifeTotal = BULLET_SPRAY_WATER_TOTAL_TIME; + FLOAT fFadeLen = fLifeTotal-fFadeStart; + + break; + } + case EPT_BULLET_SAND: + { + colSmoke = 0xFFE8C000; + Particle_PrepareTexture(&_toBulletSand, PBT_BLEND); + fSizeStart = 0.15f; + fSpeedStart = 0.75f; + break; + } + case EPT_BULLET_RED_SAND: + { + colSmoke = 0xA0402000; + colStones = 0x80503000; + Particle_PrepareTexture(&_toBulletSand, PBT_BLEND); + fSizeStart = 0.15f; + fSpeedStart = 0.75f; + break; + } + default: + { + colSmoke = C_WHITE; + Particle_PrepareTexture(&_toBulletStone, PBT_BLEND); + fSizeStart = 0.05f; + fSpeedStart = 1.5f; + } + } + + FLOAT fGA = 10.0f; + + // render particles + for( INDEX iSpray=0; iSpray<12*fDisappear; iSpray++) + { + Particle_SetTexturePart( 512, 512, iSpray&3, 0); + + FLOAT3D vRandomAngle = FLOAT3D( + afStarsPositions[ iSpray+iRnd][0]*3.0f* fConeMultiplier, + (afStarsPositions[ iSpray+iRnd][1]+1.0f)*3.0f, + afStarsPositions[ iSpray+iRnd][2]*3.0f* fConeMultiplier); + FLOAT fSpeedRnd = fSpeedStart+afStarsPositions[ iSpray+iRnd*2][3]; + FLOAT3D vPos = vEntity + (vDirection+vRandomAngle)*(fT*fSpeedRnd)+vGDir*(fT*fT*fGA); + + if( (eptType == EPT_BULLET_WATER) && (vPos(2) < vEntity(2)) ) + { + continue; + } + + FLOAT fSize = fSizeStart + afStarsPositions[ iSpray*2+iRnd*3][0]/20.0f; + FLOAT fRotation = fT*500.0f; + FLOAT fColorFactor = 1.0f; + if( fT>=fFadeStart) + { + fColorFactor = 1-fFadeLen*(fT-fFadeStart); + } + UBYTE ubColor = UBYTE(CT_OPAQUE*fColorFactor); + COLOR col = colStones|ubColor; + Particle_RenderSquare( vPos, fSize, fRotation, col); + } + Particle_Flush(); + + //--------------------------------------- + if( (fT=BULLET_SPARK_FADEOUT_START) + { + fColorFactor = 1-BULLET_SPARK_FADEOUT_LEN*(fT-BULLET_SPARK_FADEOUT_START); + } + UBYTE ubColor = UBYTE(CT_OPAQUE*fColorFactor); + COLOR col = RGBToColor(ubColor,ubColor,ubColor)|CT_OPAQUE; + Particle_RenderLine( vPos0, vPos1, 0.05f, col); + } + Particle_Flush(); + } + + //--------------------------------------- + if( (fT0.5) { + // use cross product of +x axis and plane normal as +s axis + vX = FLOAT3D(1.0f, 0.0f, 0.0f)*vY; + // if the plane is mostly vertical + } else { + // use cross product of +y axis and plane normal as +s axis + vX = FLOAT3D(0.0f, 1.0f, 0.0f)*vY; + } + // make +s axis normalized + vX.Normalize(); + + // use cross product of plane normal and +s axis as +t axis + vZ = vX*vY; + vZ.Normalize(); +} + +void Particles_EmptyShells( CEntity *pen, ShellLaunchData *asldData) +{ + FLOAT tmNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fGA = ((CMovableEntity *)pen)->en_fGravityA; + FLOAT3D vGDir = ((CMovableEntity *)pen)->en_vGravityDir; + INDEX iRow, iColumn; + + for( INDEX iShell=0; iShell (tmLaunch+fLife) ) continue; + FLOAT fTRatio = fT/fLife; + INDEX iFrame = INDEX( fTRatio*16*8)%16; + iRow = iFrame/4; + iColumn = iFrame%4; + Particle_SetTexturePart( 256, 256, iColumn, iRow); + FLOAT3D vPos = (sld.sld_vPos)+(sld.sld_vSpeed*fT)+(vGDir*(fT*fT*fGA/2.0f)); + Particle_RenderSquare( vPos, 0.05f, 0, C_WHITE|CT_OPAQUE); + break; + } + case ESL_SHOTGUN: + { + FLOAT fLife = 1.5f; + if( tmNow > (tmLaunch+fLife) ) continue; + FLOAT fTRatio = fT/fLife; + INDEX iFrame = INDEX( fTRatio*16*8)%16; + iRow = 4+iFrame/4; + iColumn = iFrame%4; + Particle_SetTexturePart( 256, 256, iColumn, iRow); + FLOAT3D vPos = (sld.sld_vPos)+(sld.sld_vSpeed*fT)+(vGDir*(fT*fT*fGA/2.0f)); + Particle_RenderSquare( vPos, 0.05f, 0, C_WHITE|CT_OPAQUE); + break; + } + case ESL_BUBBLE: + { + INDEX iRnd = (INDEX(tmLaunch*1234))%CT_MAX_PARTICLES_TABLE; + FLOAT fLife = 4.0f; + if( tmNow > (tmLaunch+fLife) ) continue; + Particle_SetTexturePart( 512, 512, 2, 0); + + FLOAT3D vX, vZ; + MakeBaseFromVector( sld.sld_vUp, vX, vZ); + + FLOAT fZF = sin( afStarsPositions[iRnd+2][0]*PI); + FLOAT fXF = cos( afStarsPositions[iRnd+2][0]*PI); + + FLOAT fAmpl = ClampUp( fT+afStarsPositions[iRnd+1][1]+0.5f, 2.0f)/64; + FLOAT fFormulae = fAmpl * sin(afStarsPositions[iRnd][2]+fT*afStarsPositions[iRnd][3]*2); + + FLOAT fColorFactor = 1.0f; + if( fT>fLife/2) + { + fColorFactor = -fT+fLife; + } + UBYTE ubAlpha = UBYTE(CT_OPAQUE*fColorFactor); + ubAlpha = CT_OPAQUE; + FLOAT3D vSpeedPower = sld.sld_vSpeed/(1.0f+fT*fT); + + FLOAT3D vPos = sld.sld_vPos + + vX*fFormulae*fXF+ + vZ*fFormulae*fZF+ + sld.sld_vUp*fT/4.0f*(0.8f+afStarsPositions[iRnd][1]/8.0f)+ + vSpeedPower*fT; + FLOAT fSize = 0.02f + afStarsPositions[iRnd+3][1]*0.01f; + Particle_RenderSquare( vPos, fSize, 0, C_WHITE|ubAlpha); + break; + } + case ESL_SHOTGUN_SMOKE: + { + FLOAT fLife = 1.0f; + if( fT0.0f) + { + // render smoke + INDEX iRnd = (INDEX(tmLaunch*1234))%CT_MAX_PARTICLES_TABLE; + FLOAT fTRatio = fT/fLife; + INDEX iColumn = 4+INDEX( iShell)%4; + Particle_SetTexturePart( 256, 256, iColumn, 2); + + FLOAT3D vPos = sld.sld_vPos + sld.sld_vUp*(afStarsPositions[iRnd][0]/2.0f+0.5f)*fT + sld.sld_vSpeed*fT/(1+fT*fT); + FLOAT fColorFactor = (fLife-fT)/fLife/(afStarsPositions[iRnd+1][0]*2+4.0f); + FLOAT fRotation = afStarsPositions[iShell][1]*200*fT; + FLOAT fSize = (0.0125f+fT/(5.0f+afStarsPositions[iRnd+1][0]*2.0f))*sld.sld_fSize; + UBYTE ubAlpha = UBYTE(CT_OPAQUE*ClampUp(fColorFactor*sld.sld_fSize, 1.0f)); + COLOR colSmoke = C_WHITE; + Particle_RenderSquare( vPos, fSize, fRotation, colSmoke|ubAlpha); + } + break; + } + case ESL_COLT_SMOKE: + { + FLOAT fLife = 1.0f; + if( fT0.0f) + { + CPlayer &plr = (CPlayer&)*pen; + CPlacement3D plPipe; + plr.GetLerpedWeaponPosition(sld.sld_vPos, plPipe); + FLOATmatrix3D m; + MakeRotationMatrixFast(m, plPipe.pl_OrientationAngle); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + + INDEX iRnd = (INDEX(tmLaunch*1234))%CT_MAX_PARTICLES_TABLE; + FLOAT fTRatio = fT/fLife; + INDEX iColumn = 4+INDEX( iShell)%4; + Particle_SetTexturePart( 256, 256, iColumn, 2); + + FLOAT3D vPos = plPipe.pl_PositionVector+vUp*(afStarsPositions[iRnd][0]/4.0f+0.3f)*fT; + FLOAT fColorFactor = (fLife-fT)/fLife/(afStarsPositions[iRnd+1][0]*2+4.0f); + FLOAT fRotation = afStarsPositions[iShell][1]*500*fT; + FLOAT fSize = 0.0025f+fT/(10.0f+(afStarsPositions[iRnd+1][0]+0.5f)*10.0f); + UBYTE ubAlpha = UBYTE(CT_OPAQUE*fColorFactor); + COLOR colSmoke = C_WHITE; + Particle_RenderSquare( vPos, fSize, fRotation, colSmoke|ubAlpha); + } + break; + } + } + } + Particle_Flush(); +} + +#define FADE_IN_LENGHT 1.0f +#define FADE_OUT_LENGHT 1.5f +#define FADE_IN_START 0.0f +#define SPIRIT_SPIRAL_START 1.0f +#define FADE_OUT_START 1.75f + +#define FADE_IN_END (FADE_IN_START+FADE_IN_LENGHT) +#define FADE_OUT_END (FADE_OUT_START+FADE_OUT_LENGHT) + +void Particles_Death(CEntity *pen, TIME tmStart) +{ + FLOAT fMipFactor = Particle_GetMipFactor(); + BOOL bVisible = pen->en_pmoModelObject->IsModelVisible( fMipFactor); + if( !bVisible) return; + + FLOAT fTime = _pTimer->GetLerpedCurrentTick()-tmStart; + // don't render particles before fade in and after fadeout + if( (fTimeFADE_OUT_END)) { + return; + } + FLOAT fPowerTime = pow(fTime-SPIRIT_SPIRAL_START, 2.5f); + + // fill array with absolute vertices of entity's model and its attached models + pen->GetModelVerticesAbsolute(avVertices, 0.05f, fMipFactor); + + // get entity position and orientation + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + SetupParticleTexture( PT_STAR07); + + // calculate color factor (for fade in/out) + FLOAT fColorFactor = 1.0f; + if( (fTime>=FADE_IN_START) && (fTime<=FADE_IN_END)) + { + fColorFactor = 1/FADE_IN_LENGHT*(fTime-FADE_IN_START); + } + else if( (fTime>=FADE_OUT_START) && (fTime<=FADE_OUT_END)) + { + fColorFactor = -1/FADE_OUT_LENGHT*(fTime-FADE_OUT_END); + } + + UBYTE ubColor = UBYTE(CT_OPAQUE*fColorFactor); + COLOR col = RGBToColor(ubColor,ubColor,ubColor)|CT_OPAQUE; + + INDEX ctVtx = avVertices.Count(); + FLOAT fSpeedFactor = 1.0f/ctVtx; + + // get corp size + FLOATaabbox3D box; + pen->en_pmoModelObject->GetCurrentFrameBBox(box); + FLOAT fHeightStretch = box.Size()(2); + + FLOAT fStep = ClampDn( fMipFactor, 1.0f); + for( FLOAT fVtx=0.0f; fVtxen_pmoModelObject->IsModelVisible( fMipFactor); + if( !bVisible) return; + + FLOAT fTime = _pTimer->GetLerpedCurrentTick()-tmStart; + // don't render particles before fade in and after fadeout + if( (fTimeAPPEAR_OUT_END)) { + return; + } + FLOAT fPowerTime = pow(fTime-SPIRIT_SPIRAL_START, 2.5f); + + // fill array with absolute vertices of entity's model and its attached models + pen->GetModelVerticesAbsolute(avVertices, 0.05f, fMipFactor); + + // get entity position and orientation + const FLOATmatrix3D &m = pen->GetRotationMatrix(); + FLOAT3D vX( m(1,1), m(2,1), m(3,1)); + FLOAT3D vY( m(1,2), m(2,2), m(3,2)); + FLOAT3D vZ( m(1,3), m(2,3), m(3,3)); + FLOAT3D vCenter = pen->GetLerpedPlacement().pl_PositionVector; + + SetupParticleTexture( PT_STAR07); + + // calculate color factor (for fade in/out) + FLOAT fColorFactor = 1.0f; + if( (fTime>=APPEAR_IN_START) && (fTime<=APPEAR_IN_END)) + { + fColorFactor = 1/APPEAR_IN_LENGHT*(fTime-APPEAR_IN_START); + } + else if( (fTime>=APPEAR_OUT_START) && (fTime<=APPEAR_OUT_END)) + { + fColorFactor = -1/APPEAR_OUT_LENGHT*(fTime-APPEAR_OUT_END); + } + + UBYTE ubColor = UBYTE(CT_OPAQUE*fColorFactor); + COLOR col = RGBToColor(ubColor,ubColor,ubColor)|CT_OPAQUE; + + INDEX ctVtx = avVertices.Count(); + FLOAT fSpeedFactor = 1.0f/ctVtx; + + // get corp size + FLOATaabbox3D box; + pen->en_pmoModelObject->GetCurrentFrameBBox(box); + FLOAT fHeightStretch = box.Size()(2); + + FLOAT fStep = ClampDn( fMipFactor, 1.0f); + for( FLOAT fVtx=0.0f; fVtxGetLerpedPlacement().pl_PositionVector; + FLOAT fBoxSize = boxOwner.Size().Length()*0.1f; + FLOAT fEnemySizeModifier = (fBoxSize-0.2)/1.0f+1.0f; + FLOAT fRotation = 0.0f; + + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + + // determine time difference + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + + // prepare texture + switch(sptType) { + case SPT_BLOOD: + case SPT_SLIME: + { + if( iBloodType<1) return; + if( iBloodType==3) Particle_PrepareTexture( &_toFlowerSprayTexture, PBT_BLEND); + else Particle_PrepareTexture( &_toBloodSprayTexture, PBT_BLEND); + break; + } + case SPT_BONES: + { + Particle_PrepareTexture( &_toBonesSprayTexture, PBT_BLEND); + break; + } + case SPT_FEATHER: + { + Particle_PrepareTexture( &_toFeatherSprayTexture, PBT_BLEND); + fDamagePower*=2.0f; + break; + } + case SPT_STONES: + { + Particle_PrepareTexture( &_toStonesSprayTexture, PBT_BLEND); + fDamagePower*=3.0f; + break; + } + case SPT_WOOD: + { + Particle_PrepareTexture( &_toWoodSprayTexture, PBT_BLEND); + fDamagePower*=5.0f; + break; + } + case SPT_SMALL_LAVA_STONES: + { + Particle_PrepareTexture( &_toLavaSprayTexture, PBT_BLEND); + fDamagePower *= 0.75f; + break; + } + case SPT_LAVA_STONES: + { + Particle_PrepareTexture( &_toLavaSprayTexture, PBT_BLEND); + fDamagePower *=3.0f; + break; + } + case SPT_BEAST_PROJECTILE_SPRAY: + { + Particle_PrepareTexture( &_toBeastProjectileSprayTexture, PBT_BLEND); + fDamagePower*=3.0f; + break; + } + case SPT_ELECTRICITY_SPARKS: + { + Particle_PrepareTexture( &_toMetalSprayTexture, PBT_BLEND); + break; + } + default: ASSERT(FALSE); + return; + } + + FLOAT fT=(fNow-tmStarted); + for( INDEX iSpray=0; iSprayBLOOD_SPRAY_FADE_OUT_START) + { + fSize=(-1/(BLOOD_SPRAY_TOTAL_TIME-BLOOD_SPRAY_FADE_OUT_START))*(fT-BLOOD_SPRAY_TOTAL_TIME); + fFade = fSize; + } + else if( fT>BLOOD_SPRAY_TOTAL_TIME) + { + fSize=0.0f; + fFade =0.0f; + } + else + { + fSize=1.0f; + fFade = fSize; + } + FLOAT fMipFactor = Particle_GetMipFactor(); + FLOAT fMipSizeAffector = Clamp( fMipFactor/4.0f, 0.05f, 1.0f); + fSize *= fMipSizeAffector*fDamagePower*fEnemySizeModifier; + + FLOAT3D vRandomAngle = FLOAT3D( + afStarsPositions[ iSpray][0]*1.75f, + (afStarsPositions[ iSpray][1]+1.0f)*1.0f, + afStarsPositions[ iSpray][2]*1.75f); + FLOAT fSpeedModifier = afStarsPositions[ iSpray+BLOOD_SPRAYS][0]*0.5f; + + FLOAT fSpeed = BLOOD_SPRAY_SPEED_MIN+(BLOOD_SPRAY_TOTAL_TIME-fT)/BLOOD_SPRAY_TOTAL_TIME; + FLOAT3D vPos = vWoundPos + (vSpilDirection+vRandomAngle)*(fT*(fSpeed+fSpeedModifier))+vGDir*(fT*fT*fGA/4.0f); + + UBYTE ubAlpha = UBYTE(CT_OPAQUE*fFade); + FLOAT fSizeModifier = afStarsPositions[ int(iSpray+tmStarted*50)%CT_MAX_PARTICLES_TABLE][1]*0.5+1.0f; + + COLOR col = C_WHITE|CT_OPAQUE; + // prepare texture + switch(sptType) { + case SPT_BLOOD: + { + UBYTE ubRndCol = UBYTE( 128+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*64); + if( iBloodType==2) col = RGBAToColor( ubRndCol, 0, 0, ubAlpha); + if( iBloodType==1) col = RGBAToColor( 0, ubRndCol, 0, ubAlpha); + break; + } + case SPT_SLIME: + { + UBYTE ubRndCol = UBYTE( 128+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*64); + if( iBloodType!=3) col = RGBAToColor(0, ubRndCol, 0, ubAlpha); + break; + } + case SPT_BONES: + { + UBYTE ubRndH = UBYTE( 8+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*16); + UBYTE ubRndS = UBYTE( 96+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*64); + UBYTE ubRndV = UBYTE( 64+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*64); + col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + fSize/=1.5f; + break; + } + case SPT_FEATHER: + { + if(iSpray>=BLOOD_SPRAYS/2) + { + UBYTE ubRndCol = UBYTE( 128+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*64); + if( iBloodType==2) col = RGBAToColor( ubRndCol, 0, 0, ubAlpha); + if( iBloodType==1) col = RGBAToColor( 0, ubRndCol, 0, ubAlpha); + } + else + { + UBYTE ubRndH = UBYTE( 32+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*16); + UBYTE ubRndS = UBYTE( 127+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*128); + UBYTE ubRndV = UBYTE( 159+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*192); + col = HSVToColor(ubRndH, 0, ubRndV)|ubAlpha; + fSize/=2.0f; + fRotation = fT*200.0f; + } + break; + } + case SPT_STONES: + { + UBYTE ubRndH = UBYTE( 24+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*16); + UBYTE ubRndS = UBYTE( 32+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*64); + UBYTE ubRndV = UBYTE( 196+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*128); + col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + fSize*=0.10f; + fRotation = fT*200.0f; + break; + } + case SPT_WOOD: + { + UBYTE ubRndH = UBYTE( 16+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*16); + UBYTE ubRndS = UBYTE( 96+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*32); + UBYTE ubRndV = UBYTE( 96+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*96); + col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + fSize*=0.15f; + fRotation = fT*300.0f; + break; + } + case SPT_LAVA_STONES: + case SPT_SMALL_LAVA_STONES: + { + col = C_WHITE|ubAlpha; + fSize/=12.0f; + fRotation = fT*200.0f; + break; + } + case SPT_BEAST_PROJECTILE_SPRAY: + { + col = C_WHITE|ubAlpha; + fSize/=12.0f; + fRotation = fT*200.0f; + break; + } + case SPT_ELECTRICITY_SPARKS: + { + UBYTE ubRndH = UBYTE( 180+afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*16); + UBYTE ubRndS = UBYTE( 32+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*16); + UBYTE ubRndV = UBYTE( 192+(afStarsPositions[ int(iSpray+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*64); + ubRndS = 0; + ubRndV = 255; + col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + fSize/=32.0f; + fRotation = fT*200.0f; + break; + } + } + Particle_RenderSquare( vPos, 0.25f*fSize*fSizeModifier, fRotation, col); + } + + // all done + Particle_Flush(); +} + +// spray some stones along obelisk +void Particles_DestroyingObelisk(CEntity *penSpray, FLOAT tmStarted) +{ + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fT=(fNow-tmStarted); + Particle_PrepareTexture( &_toStonesSprayTexture, PBT_BLEND); + + FLOAT fTotalTime = 10.0f; + FLOAT fFadeOutStart = 7.5f; + FLOAT fFadeInEnd = 1.0f; + FLOAT3D vG = FLOAT3D(0.0f,-20.0f,0.0f); + + for( INDEX iStone=0; iStone<128; iStone++) + { + INDEX idx = int(iStone+tmStarted*33)%CT_MAX_PARTICLES_TABLE; + FLOAT3D vSpeed = FLOAT3D( + afStarsPositions[ idx][0], + afStarsPositions[ idx][1], + afStarsPositions[ idx][2]); + vSpeed(2) += 0.25f; + vSpeed *= 50.0f; + + // calculate position + FLOAT3D vPos = penSpray->GetPlacement().pl_PositionVector + + vSpeed*fT + + vG*fT*fT; + vPos(2) += (afStarsPositions[ int(iStone+tmStarted*100)%CT_MAX_PARTICLES_TABLE][1]+0.5)*116.0f; + + FLOAT fFade; + // apply fade + if( fTfFadeOutStart) + { + fFade = (-1/(fTotalTime-fFadeOutStart))*(fT-fTotalTime); + } + else if( fT>fTotalTime) + { + fFade =0.0f; + } + else + { + fFade = 1.0f; + } + + UBYTE ubRndH = UBYTE( 16+afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*8); + UBYTE ubRndS = UBYTE( 96+(afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*64); + UBYTE ubRndV = UBYTE( 128+(afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*64); + UBYTE ubAlpha = UBYTE(CT_OPAQUE*fFade); + COLOR col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + + FLOAT fSize=(afStarsPositions[ int(iStone+tmStarted*100)%CT_MAX_PARTICLES_TABLE][2]+1.0f)*1.5f; + FLOAT fRotation = fT*200.0f; + + Particle_SetTexturePart( 256, 256, ((int(tmStarted*100.0f))%8+iStone)%8, 0); + Particle_RenderSquare( vPos, fSize, fRotation, col); + } + // all done + Particle_Flush(); +} + +// spray some stones along pylon +void Particles_DestroyingPylon(CEntity *penSpray, FLOAT3D vDamageDir, FLOAT tmStarted) +{ + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fT=(fNow-tmStarted); + Particle_PrepareTexture( &_toStonesSprayTexture, PBT_BLEND); + + FLOAT fTotalTime = 10.0f; + FLOAT fFadeOutStart = 7.5f; + FLOAT fFadeInEnd = 1.0f; + FLOAT3D vG = FLOAT3D(0.0f,-20.0f,0.0f); + const FLOATmatrix3D &m = penSpray->GetRotationMatrix(); + + for( INDEX iStone=0; iStone<128; iStone++) + { + INDEX idx = int(iStone+tmStarted*33)%CT_MAX_PARTICLES_TABLE; + FLOAT3D vSpeed = vDamageDir+FLOAT3D( + afStarsPositions[ idx][0], + afStarsPositions[ idx][1], + afStarsPositions[ idx][2]); + vSpeed *= 50.0f; + + // calculate position + FLOAT3D vPos = penSpray->GetPlacement().pl_PositionVector + + vSpeed*fT*m + + vG*fT*fT; + FLOAT3D vOffset = FLOAT3D(0.0f,0.0f,0.0f); + vOffset(1) = (afStarsPositions[ int(iStone+tmStarted*100)%CT_MAX_PARTICLES_TABLE][1])*32.0f; + vOffset(2) = (afStarsPositions[ int(iStone+tmStarted*100)%CT_MAX_PARTICLES_TABLE][2]+0.5)*56.0f; + vPos += vOffset*m; + + FLOAT fFade; + // apply fade + if( fTfFadeOutStart) + { + fFade = (-1/(fTotalTime-fFadeOutStart))*(fT-fTotalTime); + } + else if( fT>fTotalTime) + { + fFade =0.0f; + } + else + { + fFade = 1.0f; + } + + UBYTE ubRndH = UBYTE( 16+afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*8); + UBYTE ubRndS = UBYTE( 96+(afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*64); + UBYTE ubRndV = UBYTE( 128+(afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*64); + UBYTE ubAlpha = UBYTE(CT_OPAQUE*fFade); + COLOR col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + + FLOAT fSize=(afStarsPositions[ int(iStone+tmStarted*100)%CT_MAX_PARTICLES_TABLE][2]+1.0f)*1.5f; + FLOAT fRotation = fT*200.0f; + + Particle_SetTexturePart( 256, 256, ((int(tmStarted*100.0f))%8+iStone)%8, 0); + Particle_RenderSquare( vPos, fSize, fRotation, col); + } + // all done + Particle_Flush(); +} + +// spray some stones in the air +void Particles_HitGround(CEntity *penSpray, FLOAT tmStarted, FLOAT fSizeMultiplier) +{ + FLOAT fNow = _pTimer->GetLerpedCurrentTick(); + FLOAT fT=(fNow-tmStarted); + Particle_PrepareTexture( &_toStonesSprayTexture, PBT_BLEND); + + FLOAT fTotalTime = 10.0f; + FLOAT fFadeOutStart = 7.5f; + FLOAT fFadeInEnd = 1.0f; + FLOAT3D vG = FLOAT3D(0.0f,-30.0f,0.0f); + + for( INDEX iStone=0; iStone<64; iStone++) + { + INDEX idx = int(iStone+tmStarted*33)%CT_MAX_PARTICLES_TABLE; + FLOAT3D vSpeed = FLOAT3D( + afStarsPositions[ idx][0]*1.5f, + (afStarsPositions[ idx][1]+0.5f)*3, + afStarsPositions[ idx][2]*1.5f); + FLOAT fSpeedMultiplier = (fSizeMultiplier-1)*(0.5f-1.0f)/(0.025f-1.0f)+1.0f; + vSpeed *= 50.0f*fSpeedMultiplier; + + // calculate position + FLOAT3D vPos = penSpray->GetPlacement().pl_PositionVector + + vSpeed*fT + + vG*fT*fT; + + FLOAT fFade; + // apply fade + if( fTfFadeOutStart) + { + fFade = (-1/(fTotalTime-fFadeOutStart))*(fT-fTotalTime); + } + else if( fT>fTotalTime) + { + fFade =0.0f; + } + else + { + fFade = 1.0f; + } + + UBYTE ubRndH = UBYTE( 16+afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][0]*8); + UBYTE ubRndS = UBYTE( 96+(afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][1]+0.5)*64); + UBYTE ubRndV = UBYTE( 128+(afStarsPositions[ int(iStone+tmStarted*10)%CT_MAX_PARTICLES_TABLE][2])*64); + UBYTE ubAlpha = UBYTE(CT_OPAQUE*fFade); + COLOR col = HSVToColor(ubRndH, ubRndS, ubRndV)|ubAlpha; + + FLOAT fSize=(afStarsPositions[ int(iStone+tmStarted*100)%CT_MAX_PARTICLES_TABLE][2]+1.0f)*4.0f*fSizeMultiplier; + FLOAT fRotation = fT*200.0f; + + Particle_SetTexturePart( 256, 256, ((int(tmStarted*100.0f))%8+iStone)%8, 0); + Particle_RenderSquare( vPos, fSize, fRotation, col); + } + // all done + Particle_Flush(); +} diff --git a/Sources/Entities/Common/Particles.h b/Sources/Entities/Common/Particles.h new file mode 100644 index 0000000..f20ece6 --- /dev/null +++ b/Sources/Entities/Common/Particles.h @@ -0,0 +1,88 @@ + +// init particle effects +void DECL_DLL InitParticles(void); +// close particle effects +void DECL_DLL CloseParticles(void); +// function for rendering local viewer particles +void DECL_DLL Particles_ViewerLocal(CEntity *penView); +// different particle effects +void DECL_DLL Particles_RomboidTrail(CEntity *pen); +void DECL_DLL Particles_RomboidTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_BombTrail(CEntity *pen); +void DECL_DLL Particles_BombTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_FirecrackerTrail(CEntity *pen); +void DECL_DLL Particles_FirecrackerTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_SpiralTrail(CEntity *pen); +void DECL_DLL Particles_SpiralTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_ColoredStarsTrail(CEntity *pen); +void DECL_DLL Particles_ColoredStarsTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_WhiteLineTrail(CEntity *pen); +void DECL_DLL Particles_WhiteLineTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_Fireball01Trail(CEntity *pen); +void DECL_DLL Particles_Fireball01Trail_Prepare(CEntity *pen); +void DECL_DLL Particles_GrenadeTrail(CEntity *pen); +void DECL_DLL Particles_GrenadeTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_CannonBall(CEntity *pen, FLOAT fSpeedRatio); +void DECL_DLL Particles_CannonBall_Prepare(CEntity *pen); +void DECL_DLL Particles_LavaTrail(CEntity *pen); +void DECL_DLL Particles_LavaTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_LavaBombTrail(CEntity *pen, FLOAT fSizeMultiplier); +void DECL_DLL Particles_LavaBombTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_RocketTrail(CEntity *pen, FLOAT fStretch); +void DECL_DLL Particles_RocketTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_BloodTrail(CEntity *pen); +void DECL_DLL Particles_FlameThrower(const CPlacement3D &plThis, const CPlacement3D &plOther, + FLOAT fThisElapsed, FLOAT fOtherElapsed); +void DECL_DLL Particles_Ghostbuster(const FLOAT3D &vSrc, const FLOAT3D &vDst, INDEX ctRays, FLOAT fSize, FLOAT fPower = 1.0f, + FLOAT fKneeDivider = 33.3333333f); +void DECL_DLL Particles_FlameThrower(const CPlacement3D &plThis, const CPlacement3D &plOther, + FLOAT fThisElapsed, FLOAT fOtherElapsed); +INDEX DECL_DLL Particles_FireBreath(CEntity *pen, FLOAT3D vSource, FLOAT3D vTarget, FLOAT tmStart, FLOAT tmStop); +INDEX DECL_DLL Particles_Regeneration(CEntity *pen, FLOAT tmStart, FLOAT tmStop, FLOAT fYFactor, BOOL bDeath); + +void DECL_DLL Particles_Stardust(CEntity *pen, FLOAT fSize, FLOAT fHeight, enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_Rising(CEntity *pen, FLOAT m_fActivateTime, FLOAT m_fDeactivateTime, FLOAT fStretchAll, FLOAT fStretchX, FLOAT fStretchY, FLOAT fStretchZ, FLOAT fSize, + enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_Spiral(CEntity *pen, FLOAT fSize, FLOAT fHeight, enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_Emanate(CEntity *pen, FLOAT fSize, FLOAT fHeight, enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_Fountain(CEntity *pen, FLOAT fSize, FLOAT fHeight, enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_Atomic(CEntity *pen, FLOAT fSize, FLOAT fHeight, enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_BloodSpray( enum SprayParticlesType sptType, CEntity *penSpray, FLOAT3D vGDir, FLOAT fGA, FLOATaabbox3D boxOwner, FLOAT3D vSpilDirection, FLOAT tmStarted, FLOAT fDamagePower); +void DECL_DLL Particles_EmanatePlane(CEntity *pen, FLOAT fSizeX, FLOAT fSizeY, FLOAT fSizeZ, + FLOAT fParticleSize, FLOAT fAway, FLOAT fSpeed, + enum ParticleTexture ptTexture, INDEX ctParticles); +void DECL_DLL Particles_WaterfallFoam(CEntity *pen, FLOAT fSizeX, FLOAT fSizeY, FLOAT fSizeZ, + FLOAT fParticleSize, FLOAT fSpeed, FLOAT fSpeedY, FLOAT fLife, INDEX ctParticles); +void DECL_DLL Particles_SandFlow(CEntity *pen, FLOAT fStretchAll, FLOAT fSize, FLOAT fHeight, FLOAT fBirthTime, FLOAT fDeathTime, + INDEX ctParticles); +void DECL_DLL Particles_WaterFlow( CEntity *pen, FLOAT fStretchAll, FLOAT fSize, FLOAT fHeight, FLOAT fStartTime, FLOAT fStopTime, + INDEX ctParticles); +void DECL_DLL Particles_LavaFlow( CEntity *pen, FLOAT fStretchAll, FLOAT fSize, FLOAT fHeight, FLOAT fStartTime, FLOAT fStopTime, + INDEX ctParticles); +void DECL_DLL Particles_Death(CEntity *pen, TIME tmStart); +void DECL_DLL Particles_Appearing(CEntity *pen, TIME tmStart); +void DECL_DLL Particles_ElectricitySparks( CEntity *pen, FLOAT fTimeAppear, FLOAT fSize, FLOAT fHeight, INDEX ctParticles); +void DECL_DLL Particles_LavaErupting(CEntity *pen, FLOAT fStretchAll, FLOAT fSize, + FLOAT fStretchX, FLOAT fStretchY, FLOAT fStretchZ, + FLOAT fActivateTime); +void DECL_DLL Particles_BeastProjectileTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_BeastProjectileTrail( CEntity *pen, FLOAT fSize, FLOAT fHeight, INDEX ctParticles); +void DECL_DLL Particles_BeastBigProjectileTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_BeastBigProjectileTrail( CEntity *pen, FLOAT fSize, FLOAT fZOffset, FLOAT fYOffset, INDEX ctParticles); +void DECL_DLL Particles_BeastProjectileDebrisTrail_Prepare(CEntity *pen); +void DECL_DLL Particles_BeastProjectileDebrisTrail(CEntity *pen, FLOAT fSizeMultiplier); + +void DECL_DLL Particles_Rain( CEntity *pen, FLOAT fGridSize, INDEX ctGrids, FLOAT fFactor, + CTextureData *ptdRainMap, FLOATaabbox3D &boxRainMap); +void DECL_DLL Particles_Snow( CEntity *pen, FLOAT fGridSize, INDEX ctGrids); +void DECL_DLL Particles_Lightning( FLOAT3D vSrc, FLOAT3D vDst, FLOAT fTimeStart); +void DECL_DLL Particles_BulletSpray(CEntity *pen, FLOAT3D vGDir, enum EffectParticlesType eptType, FLOAT tmSpawn, FLOAT3D vDirection); +void DECL_DLL Particles_MachineBullets( CEntity *pen, TIME tmStart, TIME tmEnd, FLOAT fFrequency); +void DECL_DLL Particles_EmptyShells( CEntity *pen, ShellLaunchData *asldData); +void DECL_DLL Particles_DestroyingObelisk(CEntity *penSpray, FLOAT tmStarted); +void DECL_DLL Particles_DestroyingPylon(CEntity *penSpray, FLOAT3D vDamageDir, FLOAT tmStarted); +void DECL_DLL Particles_HitGround(CEntity *penSpray, FLOAT tmStarted, FLOAT fSizeMultiplier); +void DECL_DLL Particles_MetalParts( CEntity *pen, FLOAT tmStarted, FLOATaabbox3D boxOwner, FLOAT fDamage); +void DECL_DLL Particles_DamageSmoke( CEntity *pen, FLOAT tmStarted, FLOATaabbox3D boxOwner, FLOAT fDamage); +void DECL_DLL Particles_RunningDust_Prepare(CEntity *pen); +void DECL_DLL Particles_RunningDust(CEntity *pen); diff --git a/Sources/Entities/Common/PathFinding.cpp b/Sources/Entities/Common/PathFinding.cpp new file mode 100644 index 0000000..e4099b2 --- /dev/null +++ b/Sources/Entities/Common/PathFinding.cpp @@ -0,0 +1,280 @@ +#include "../StdH/StdH.h" +#include "Entities/Common/PathFinding.h" +#include "Entities/NavigationMarker.h" + +#define PRINTOUT(_dummy) +//#define PRINTOUT(something) something + +// open and closed lists of nodes +static CListHead _lhOpen; +static CListHead _lhClosed; + +FLOAT NodeDistance(CPathNode *ppn0, CPathNode *ppn1) +{ + return ( + ppn0->pn_pnmMarker->GetPlacement().pl_PositionVector - + ppn1->pn_pnmMarker->GetPlacement().pl_PositionVector).Length(); +} + +CPathNode::CPathNode(class CNavigationMarker *penMarker) +{ + pn_pnmMarker = penMarker; + pn_ppnParent = NULL; + pn_fG = 0.0f; + pn_fH = 0.0f; + pn_fF = 0.0f; +} + +CPathNode::~CPathNode(void) +{ + // detach from marker when deleting + ASSERT(pn_pnmMarker!=NULL); + pn_pnmMarker->m_ppnNode = NULL; +} + +// get name of this node +const CTString &CPathNode::GetName(void) +{ + static CTString strNone=""; + if (this==NULL || pn_pnmMarker==NULL) { + return strNone; + } else { + return pn_pnmMarker->GetName(); + } +} + +// get link with given index or null if no more (for iteration along the graph) +CPathNode *CPathNode::GetLink(INDEX i) +{ + if (this==NULL || pn_pnmMarker==NULL) { + ASSERT(FALSE); + return NULL; + } + CNavigationMarker *pnm = pn_pnmMarker->GetLink(i); + if (pnm==NULL) { + return NULL; + } + return pnm->GetPathNode(); +} + +// add given node to open list, sorting best first +static void SortIntoOpenList(CPathNode *ppnLink) +{ + // start at head of the open list + LISTITER(CPathNode, pn_lnInOpen) itpn(_lhOpen); + // while the given node is further than the one in list + while(ppnLink->pn_fF>itpn->pn_fF && !itpn.IsPastEnd()) { + // move to next node + itpn.MoveToNext(); + } + + // if past the end of list + if (itpn.IsPastEnd()) { + // add to the end of list + _lhOpen.AddTail(ppnLink->pn_lnInOpen); + // if not past end of list + } else { + // add before current node + itpn.InsertBeforeCurrent(ppnLink->pn_lnInOpen); + } +} + +// find shortest path from one marker to another +static BOOL FindPath(CNavigationMarker *pnmSrc, CNavigationMarker *pnmDst) +{ + + ASSERT(pnmSrc!=pnmDst); + CPathNode *ppnSrc = pnmSrc->GetPathNode(); + CPathNode *ppnDst = pnmDst->GetPathNode(); + + PRINTOUT(CPrintF("--------------------\n")); + PRINTOUT(CPrintF("FindPath(%s, %s)\n", ppnSrc->GetName(), ppnDst->GetName())); + + // start with empty open and closed lists + ASSERT(_lhOpen.IsEmpty()); + ASSERT(_lhClosed.IsEmpty()); + + // add the start node to open list + ppnSrc->pn_fG = 0.0f; + ppnSrc->pn_fH = NodeDistance(ppnSrc, ppnDst); + ppnSrc->pn_fF = ppnSrc->pn_fG +ppnSrc->pn_fH; + _lhOpen.AddTail(ppnSrc->pn_lnInOpen); + PRINTOUT(CPrintF("StartState: %s\n", ppnSrc->GetName())); + + // while the open list is not empty + while (!_lhOpen.IsEmpty()) { + // get the first node from open list (that is, the one with lowest F) + CPathNode *ppnNode = LIST_HEAD(_lhOpen, CPathNode, pn_lnInOpen); + ppnNode->pn_lnInOpen.Remove(); + _lhClosed.AddTail(ppnNode->pn_lnInClosed); + PRINTOUT(CPrintF("Node: %s - moved from OPEN to CLOSED\n", ppnNode->GetName())); + + // if this is the goal + if (ppnNode==ppnDst) { + PRINTOUT(CPrintF("PATH FOUND!\n")); + // the path is found + return TRUE; + } + + // for each link of current node + CPathNode *ppnLink = NULL; + for(INDEX i=0; (ppnLink=ppnNode->GetLink(i))!=NULL; i++) { + PRINTOUT(CPrintF(" Link %d: %s\n", i, ppnLink->GetName())); + // get cost to get to this node if coming from current node + FLOAT fNewG = ppnLink->pn_fG+NodeDistance(ppnNode, ppnLink); + // if a shorter path already exists + if ((ppnLink->pn_lnInOpen.IsLinked() || ppnLink->pn_lnInClosed.IsLinked()) && fNewG>=ppnLink->pn_fG) { + PRINTOUT(CPrintF(" shorter path exists through: %s\n", ppnLink->pn_ppnParent->GetName())); + // skip this link + continue; + } + // remember this path + ppnLink->pn_ppnParent = ppnNode; + ppnLink->pn_fG = fNewG; + ppnLink->pn_fH = NodeDistance(ppnLink, ppnDst); + ppnLink->pn_fF = ppnLink->pn_fG + ppnLink->pn_fH; + // remove from closed list, if in it + if (ppnLink->pn_lnInClosed.IsLinked()) { + ppnLink->pn_lnInClosed.Remove(); + PRINTOUT(CPrintF(" %s removed from CLOSED\n", ppnLink->GetName())); + } + // add to open if not in it + if (!ppnLink->pn_lnInOpen.IsLinked()) { + SortIntoOpenList(ppnLink); + PRINTOUT(CPrintF(" %s added to OPEN\n", ppnLink->GetName())); + } + } + } + + // if we get here, there is no path + PRINTOUT(CPrintF("PATH NOT FOUND!\n")); + return FALSE; +} + +// clear all temporary structures used for path finding +static void ClearPath(CEntity *penThis) +{ + {FORDELETELIST(CPathNode, pn_lnInOpen, _lhOpen, itpn) { + delete &itpn.Current(); + }} + {FORDELETELIST(CPathNode, pn_lnInClosed, _lhClosed, itpn) { + delete &itpn.Current(); + }} + +#ifndef NDEBUG + // for each navigation marker in the world + {FOREACHINDYNAMICCONTAINER(penThis->en_pwoWorld->wo_cenEntities, CEntity, iten) { + if (!IsOfClass(iten, "NavigationMarker")) { + continue; + } + CNavigationMarker &nm = (CNavigationMarker&)*iten; + ASSERT(nm.m_ppnNode==NULL); + }} +#endif +} + +// find marker closest to a given position +static void FindClosestMarker( + CEntity *penThis, const FLOAT3D &vSrc, CEntity *&penMarker, FLOAT3D &vPath) +{ + CNavigationMarker *pnmMin = NULL; + FLOAT fMinDist = UpperLimit(0.0f); + // for each sector this entity is in + {FOREACHSRCOFDST(penThis->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc) + // for each navigation marker in that sector + {FOREACHDSTOFSRC(pbsc->bsc_rsEntities, CEntity, en_rdSectors, pen) + if (!IsOfClass(pen, "NavigationMarker")) { + continue; + } + CNavigationMarker &nm = (CNavigationMarker&)*pen; + + // get distance from source + FLOAT fDist = (vSrc-nm.GetPlacement().pl_PositionVector).Length(); + // if closer than best found + if(fDistGetPlacement().pl_PositionVector; + penMarker = pnmMin; +} + +// find first marker for path navigation +void PATH_FindFirstMarker(CEntity *penThis, const FLOAT3D &vSrc, const FLOAT3D &vDst, CEntity *&penMarker, FLOAT3D &vPath) +{ + // find closest markers to source and destination positions + CNavigationMarker *pnmSrc; + FLOAT3D vSrcPath; + FindClosestMarker(penThis, vSrc, (CEntity*&)pnmSrc, vSrcPath); + CNavigationMarker *pnmDst; + FLOAT3D vDstPath; + FindClosestMarker(penThis, vDst, (CEntity*&)pnmDst, vDstPath); + + // if at least one is not found, or if they are same + if (pnmSrc==NULL || pnmDst==NULL || pnmSrc==pnmDst) { + // fail + penMarker = NULL; + vPath = vSrc; + return; + } + + // go to the source marker position + vPath = vSrcPath; + penMarker = pnmSrc; +} + +// find next marker for path navigation +void PATH_FindNextMarker(CEntity *penThis, const FLOAT3D &vSrc, const FLOAT3D &vDst, CEntity *&penMarker, FLOAT3D &vPath) +{ + // find closest marker to destination position + CNavigationMarker *pnmDst; + FLOAT3D vDstPath; + FindClosestMarker(penThis, vDst, (CEntity*&)pnmDst, vDstPath); + + // if at not found, or if same as current + if (pnmDst==NULL || penMarker==pnmDst) { + // fail + penMarker = NULL; + vPath = vSrc; + return; + } + + // try to find shortest path to the destination + BOOL bFound = FindPath((CNavigationMarker*)penMarker, pnmDst); + + // if not found + if (!bFound) { + // just clean up and fail + delete pnmDst->GetPathNode(); + ClearPath(penThis); + penMarker = NULL; + vPath = vSrc; + return; + } + + // find the first marker position after current + CPathNode *ppn = pnmDst->GetPathNode(); + while (ppn->pn_ppnParent!=NULL && ppn->pn_ppnParent->pn_pnmMarker!=penMarker) { + ppn = ppn->pn_ppnParent; + } + penMarker = ppn->pn_pnmMarker; + + // go there + vPath = penMarker->GetPlacement().pl_PositionVector; + + // clean up + ClearPath(penThis); +} \ No newline at end of file diff --git a/Sources/Entities/Common/PathFinding.h b/Sources/Entities/Common/PathFinding.h new file mode 100644 index 0000000..3791037 --- /dev/null +++ b/Sources/Entities/Common/PathFinding.h @@ -0,0 +1,40 @@ +#ifndef SE_INCL_PATHFINDING_H +#define SE_INCL_PATHFINDING_H +#ifdef PRAGMA_ONCE + #pragma once +#endif + +// temporary structure used for path finding +class DECL_DLL CPathNode { +public: + // cunstruction/destruction + CPathNode(class CNavigationMarker *penMarker); + ~CPathNode(void); + + // get name of this node + const CTString &GetName(void); + + // get link with given index or null if no more (for iteration along the graph) + CPathNode *GetLink(INDEX i); + + class CNavigationMarker *pn_pnmMarker; // the marker itself + + CListNode pn_lnInOpen; // for linking in open/closed lists + CListNode pn_lnInClosed; + + CPathNode *pn_ppnParent; // best found parent in path yet + FLOAT pn_fG; // total cost to get here through the best parent + FLOAT pn_fH; // estimate of distance to the goal + FLOAT pn_fF; // total quality of the path going through this node +}; + +// find first marker for path navigation +DECL_DLL void PATH_FindFirstMarker( + CEntity *penThis, const FLOAT3D &vSrc, const FLOAT3D &vDst, CEntity *&penMarker, FLOAT3D &vPath); +// find next marker for path navigation +DECL_DLL void PATH_FindNextMarker( + CEntity *penThis, const FLOAT3D &vSrc, const FLOAT3D &vDst, CEntity *&penMarker, FLOAT3D &vPath); + + +#endif /* include-once check. */ + diff --git a/Sources/Entities/Common/Stats.cpp b/Sources/Entities/Common/Stats.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Entities/Common/WeaponPositions.h b/Sources/Entities/Common/WeaponPositions.h new file mode 100644 index 0000000..7b439f6 --- /dev/null +++ b/Sources/Entities/Common/WeaponPositions.h @@ -0,0 +1,373 @@ + +#if 0 // use this part when manually setting weapon positions + + _pShell->DeclareSymbol("persistent user FLOAT wpn_fH[30+1];", &wpn_fH); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fP[30+1];", &wpn_fP); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fB[30+1];", &wpn_fB); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fX[30+1];", &wpn_fX); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fY[30+1];", &wpn_fY); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fZ[30+1];", &wpn_fZ); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fFOV[30+1];", &wpn_fFOV); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fClip[30+1];", &wpn_fClip); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fFX[30+1];", &wpn_fFX); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fFY[30+1];", &wpn_fFY); +// _pShell->DeclareSymbol("persistent user FLOAT wpn_fFZ[30+1];", &wpn_fFZ); +#else + /* + _pShell->DeclareSymbol("user FLOAT wpn_fFX[30+1];", &wpn_fFX); + _pShell->DeclareSymbol("user FLOAT wpn_fFY[30+1];", &wpn_fFY); + */ + +#pragma warning(disable: 4305) + +wpn_fH[0]=10; +wpn_fH[1]=-1; +wpn_fH[2]=-1; +wpn_fH[3]=-1; +wpn_fH[4]=2; +wpn_fH[5]=2; +wpn_fH[6]=(FLOAT)4; +wpn_fH[7]=(FLOAT)2; +wpn_fH[8]=(FLOAT)2; +wpn_fH[9]=(FLOAT)0.5; +wpn_fH[10]=(FLOAT)-12; +wpn_fH[11]=(FLOAT)4; +wpn_fH[12]=(FLOAT)4.6; +wpn_fH[13]=(FLOAT)0; +wpn_fH[14]=(FLOAT)1; +wpn_fH[15]=(FLOAT)2.2; +wpn_fH[16]=(FLOAT)2.5; +wpn_fH[17]=(FLOAT)0; +wpn_fH[18]=(FLOAT)0; +wpn_fH[19]=(FLOAT)0; +wpn_fH[20]=(FLOAT)0; +wpn_fH[21]=(FLOAT)0; +wpn_fH[22]=(FLOAT)0; +wpn_fH[23]=(FLOAT)0; +wpn_fH[24]=(FLOAT)0; +wpn_fH[25]=(FLOAT)0; +wpn_fH[26]=(FLOAT)0; +wpn_fH[27]=(FLOAT)0; +wpn_fH[28]=(FLOAT)0; +wpn_fH[29]=(FLOAT)0; +wpn_fH[30]=(FLOAT)0; +wpn_fP[0]=0; +wpn_fP[1]=10; +wpn_fP[2]=0; +wpn_fP[3]=0; +wpn_fP[4]=2; +wpn_fP[5]=1; +wpn_fP[6]=(FLOAT)3; +wpn_fP[7]=(FLOAT)0; +wpn_fP[8]=(FLOAT)1; +wpn_fP[9]=(FLOAT)2.5; +wpn_fP[10]=(FLOAT)0; +wpn_fP[11]=(FLOAT)0; +wpn_fP[12]=(FLOAT)2.8; +wpn_fP[13]=(FLOAT)0; +wpn_fP[14]=(FLOAT)3; +wpn_fP[15]=(FLOAT)4.7; +wpn_fP[16]=(FLOAT)6; +wpn_fP[17]=(FLOAT)0; +wpn_fP[18]=(FLOAT)0; +wpn_fP[19]=(FLOAT)0; +wpn_fP[20]=(FLOAT)0; +wpn_fP[21]=(FLOAT)0; +wpn_fP[22]=(FLOAT)0; +wpn_fP[23]=(FLOAT)0; +wpn_fP[24]=(FLOAT)0; +wpn_fP[25]=(FLOAT)0; +wpn_fP[26]=(FLOAT)0; +wpn_fP[27]=(FLOAT)0; +wpn_fP[28]=(FLOAT)0; +wpn_fP[29]=(FLOAT)0; +wpn_fP[30]=(FLOAT)0; +wpn_fB[0]=0; +wpn_fB[1]=6; +wpn_fB[2]=0; +wpn_fB[3]=0; +wpn_fB[4]=0; +wpn_fB[5]=0; +wpn_fB[6]=(FLOAT)0; +wpn_fB[7]=(FLOAT)0; +wpn_fB[8]=(FLOAT)0; +wpn_fB[9]=(FLOAT)0; +wpn_fB[10]=(FLOAT)0; +wpn_fB[11]=(FLOAT)0; +wpn_fB[12]=(FLOAT)0; +wpn_fB[13]=(FLOAT)0; +wpn_fB[14]=(FLOAT)0; +wpn_fB[15]=(FLOAT)0; +wpn_fB[16]=(FLOAT)0; +wpn_fB[17]=(FLOAT)0; +wpn_fB[18]=(FLOAT)0; +wpn_fB[19]=(FLOAT)0; +wpn_fB[20]=(FLOAT)0; +wpn_fB[21]=(FLOAT)0; +wpn_fB[22]=(FLOAT)0; +wpn_fB[23]=(FLOAT)0; +wpn_fB[24]=(FLOAT)0; +wpn_fB[25]=(FLOAT)0; +wpn_fB[26]=(FLOAT)0; +wpn_fB[27]=(FLOAT)0; +wpn_fB[28]=(FLOAT)0; +wpn_fB[29]=(FLOAT)0; +wpn_fB[30]=(FLOAT)0; +wpn_fX[0]=0.08; +wpn_fX[1]=0.23; +wpn_fX[2]=0.19; +wpn_fX[3]=0.19; +wpn_fX[4]=0.12; +wpn_fX[5]=0.13; +wpn_fX[6]=(FLOAT)0.121; +wpn_fX[7]=(FLOAT)0.137; +wpn_fX[8]=(FLOAT)0.17; +wpn_fX[9]=(FLOAT)0.155; +wpn_fX[10]=(FLOAT)0.16; +wpn_fX[11]=(FLOAT)0.204; +wpn_fX[12]=(FLOAT)0.204; +wpn_fX[13]=(FLOAT)0; +wpn_fX[14]=(FLOAT)0.141; +wpn_fX[15]=(FLOAT)0.169; +wpn_fX[16]=(FLOAT)0.17; +wpn_fX[17]=(FLOAT)0; +wpn_fX[18]=(FLOAT)0; +wpn_fX[19]=(FLOAT)0; +wpn_fX[20]=(FLOAT)0; +wpn_fX[21]=(FLOAT)0; +wpn_fX[22]=(FLOAT)0; +wpn_fX[23]=(FLOAT)0; +wpn_fX[24]=(FLOAT)0; +wpn_fX[25]=(FLOAT)0; +wpn_fX[26]=(FLOAT)0; +wpn_fX[27]=(FLOAT)0; +wpn_fX[28]=(FLOAT)0; +wpn_fX[29]=(FLOAT)0; +wpn_fX[30]=(FLOAT)0; +wpn_fY[0]=0; +wpn_fY[1]=-0.28; +wpn_fY[2]=-0.21; +wpn_fY[3]=-0.21; +wpn_fY[4]=-0.22; +wpn_fY[5]=-0.21; +wpn_fY[6]=(FLOAT)-0.213; +wpn_fY[7]=(FLOAT)-0.24; +wpn_fY[8]=(FLOAT)-0.325; +wpn_fY[9]=(FLOAT)-0.515; +wpn_fY[10]=(FLOAT)-0.2; +wpn_fY[11]=(FLOAT)-0.102; +wpn_fY[12]=(FLOAT)-0.306; +wpn_fY[13]=(FLOAT)0; +wpn_fY[14]=(FLOAT)-0.174; +wpn_fY[15]=(FLOAT)-0.232; +wpn_fY[16]=(FLOAT)-0.3; +wpn_fY[17]=(FLOAT)0; +wpn_fY[18]=(FLOAT)0; +wpn_fY[19]=(FLOAT)0; +wpn_fY[20]=(FLOAT)0; +wpn_fY[21]=(FLOAT)0; +wpn_fY[22]=(FLOAT)0; +wpn_fY[23]=(FLOAT)0; +wpn_fY[24]=(FLOAT)0; +wpn_fY[25]=(FLOAT)0; +wpn_fY[26]=(FLOAT)0; +wpn_fY[27]=(FLOAT)0; +wpn_fY[28]=(FLOAT)0; +wpn_fY[29]=(FLOAT)0; +wpn_fY[30]=(FLOAT)0; +wpn_fZ[0]=0; +wpn_fZ[1]=-0.44; +wpn_fZ[2]=-0.1; +wpn_fZ[3]=-0.1; +wpn_fZ[4]=-0.34; +wpn_fZ[5]=-0.364; +wpn_fZ[6]=(FLOAT)-0.285; +wpn_fZ[7]=(FLOAT)-0.328; +wpn_fZ[8]=(FLOAT)-0.24; +wpn_fZ[9]=(FLOAT)-0.130001; +wpn_fZ[10]=(FLOAT)-0.1; +wpn_fZ[11]=(FLOAT)0; +wpn_fZ[12]=(FLOAT)-0.57; +wpn_fZ[13]=(FLOAT)0; +wpn_fZ[14]=(FLOAT)-0.175; +wpn_fZ[15]=(FLOAT)-0.308; +wpn_fZ[16]=(FLOAT)-0.625; +wpn_fZ[17]=(FLOAT)0; +wpn_fZ[18]=(FLOAT)0; +wpn_fZ[19]=(FLOAT)0; +wpn_fZ[20]=(FLOAT)0; +wpn_fZ[21]=(FLOAT)0; +wpn_fZ[22]=(FLOAT)0; +wpn_fZ[23]=(FLOAT)0; +wpn_fZ[24]=(FLOAT)0; +wpn_fZ[25]=(FLOAT)0; +wpn_fZ[26]=(FLOAT)0; +wpn_fZ[27]=(FLOAT)0; +wpn_fZ[28]=(FLOAT)0; +wpn_fZ[29]=(FLOAT)0; +wpn_fZ[30]=(FLOAT)0; +wpn_fFOV[0]=2; +wpn_fFOV[1]=41.5; +wpn_fFOV[2]=57; +wpn_fFOV[3]=57; +wpn_fFOV[4]=41; +wpn_fFOV[5]=52.5; +wpn_fFOV[6]=(FLOAT)49; +wpn_fFOV[7]=(FLOAT)66.9; +wpn_fFOV[8]=(FLOAT)66; +wpn_fFOV[9]=(FLOAT)85.5; +wpn_fFOV[10]=(FLOAT)72; +wpn_fFOV[11]=(FLOAT)80; +wpn_fFOV[12]=(FLOAT)50; +wpn_fFOV[13]=(FLOAT)80; +wpn_fFOV[14]=(FLOAT)70.5; +wpn_fFOV[15]=(FLOAT)52.5; +wpn_fFOV[16]=(FLOAT)50; +wpn_fFOV[17]=(FLOAT)0; +wpn_fFOV[18]=(FLOAT)0; +wpn_fFOV[19]=(FLOAT)0; +wpn_fFOV[20]=(FLOAT)0; +wpn_fFOV[21]=(FLOAT)0; +wpn_fFOV[22]=(FLOAT)0; +wpn_fFOV[23]=(FLOAT)0; +wpn_fFOV[24]=(FLOAT)0; +wpn_fFOV[25]=(FLOAT)0; +wpn_fFOV[26]=(FLOAT)0; +wpn_fFOV[27]=(FLOAT)0; +wpn_fFOV[28]=(FLOAT)0; +wpn_fFOV[29]=(FLOAT)0; +wpn_fFOV[30]=(FLOAT)0; +wpn_fClip[0]=0; +wpn_fClip[1]=0.1; +wpn_fClip[2]=0.1; +wpn_fClip[3]=0.1; +wpn_fClip[4]=0.1; +wpn_fClip[5]=0.1; +wpn_fClip[6]=0.1; +wpn_fClip[7]=0.1; +wpn_fClip[8]=0.1; +wpn_fClip[9]=0.1; +wpn_fClip[10]=0.1; +wpn_fClip[11]=0.1; +wpn_fClip[12]=0.1; +wpn_fClip[13]=0.1; +wpn_fClip[14]=0.1; +wpn_fClip[15]=0.1; +wpn_fClip[16]=0.1; +wpn_fClip[17]=0; +wpn_fClip[18]=0; +wpn_fClip[19]=0; +wpn_fClip[20]=0; +wpn_fClip[21]=0; +wpn_fClip[22]=0; +wpn_fClip[23]=0; +wpn_fClip[24]=0; +wpn_fClip[25]=0; +wpn_fClip[26]=0; +wpn_fClip[27]=0; +wpn_fClip[28]=0; +wpn_fClip[29]=0; +wpn_fClip[30]=0; +wpn_fFX[0]=(FLOAT)0; +wpn_fFX[1]=(FLOAT)0; +wpn_fFX[2]=(FLOAT)0; +wpn_fFX[3]=(FLOAT)0; +wpn_fFX[4]=(FLOAT)0; +wpn_fFX[5]=(FLOAT)0; +wpn_fFX[6]=(FLOAT)0; +wpn_fFX[7]=(FLOAT)0; +wpn_fFX[8]=(FLOAT)-0.1; +wpn_fFX[9]=(FLOAT)0; +wpn_fFX[10]=(FLOAT)0; +wpn_fFX[11]=(FLOAT)0; +wpn_fFX[12]=(FLOAT)0; +wpn_fFX[13]=(FLOAT)0; +wpn_fFX[14]=(FLOAT)-0.1; +wpn_fFX[15]=(FLOAT)0; +wpn_fFX[16]=(FLOAT)0.25; +wpn_fFX[17]=(FLOAT)0; +wpn_fFX[18]=(FLOAT)0; +wpn_fFX[19]=(FLOAT)0; +wpn_fFX[20]=(FLOAT)0; +wpn_fFX[21]=(FLOAT)0; +wpn_fFX[22]=(FLOAT)0; +wpn_fFX[23]=(FLOAT)0; +wpn_fFX[24]=(FLOAT)0; +wpn_fFX[25]=(FLOAT)0; +wpn_fFX[26]=(FLOAT)0; +wpn_fFX[27]=(FLOAT)0; +wpn_fFX[28]=(FLOAT)0; +wpn_fFX[29]=(FLOAT)0; +wpn_fFX[30]=(FLOAT)0; +wpn_fFY[0]=(FLOAT)0; +wpn_fFY[1]=(FLOAT)0; +wpn_fFY[2]=(FLOAT)0; +wpn_fFY[3]=(FLOAT)0; +wpn_fFY[4]=(FLOAT)0; +wpn_fFY[5]=(FLOAT)0; +wpn_fFY[6]=(FLOAT)0; +wpn_fFY[7]=(FLOAT)0; +wpn_fFY[8]=(FLOAT)0.11; +wpn_fFY[9]=(FLOAT)0; +wpn_fFY[10]=(FLOAT)0; +wpn_fFY[11]=(FLOAT)0; +wpn_fFY[12]=(FLOAT)0; +wpn_fFY[13]=(FLOAT)0; +wpn_fFY[14]=(FLOAT)-0.4; +wpn_fFY[15]=(FLOAT)0; +wpn_fFY[16]=(FLOAT)-0.5; +wpn_fFY[17]=(FLOAT)0; +wpn_fFY[18]=(FLOAT)0; +wpn_fFY[19]=(FLOAT)0; +wpn_fFY[20]=(FLOAT)0; +wpn_fFY[21]=(FLOAT)0; +wpn_fFY[22]=(FLOAT)0; +wpn_fFY[23]=(FLOAT)0; +wpn_fFY[24]=(FLOAT)0; +wpn_fFY[25]=(FLOAT)0; +wpn_fFY[26]=(FLOAT)0; +wpn_fFY[27]=(FLOAT)0; +wpn_fFY[28]=(FLOAT)0; +wpn_fFY[29]=(FLOAT)0; +wpn_fFY[30]=(FLOAT)0; + +// tommygun +wpn_fH[6]=(FLOAT)4; +wpn_fP[6]=(FLOAT)3; +wpn_fB[6]=(FLOAT)0; +wpn_fX[6]=(FLOAT)0.121; +wpn_fY[6]=(FLOAT)-0.213; +wpn_fZ[6]=(FLOAT)-0.285; +wpn_fFOV[6]=(FLOAT)49; +wpn_fClip[6]=0.1; +wpn_fFX[6]=(FLOAT)0; +wpn_fFY[6]=(FLOAT)0; + +// grenade launcher +wpn_fH[9]=(FLOAT)2; +wpn_fP[9]=(FLOAT)6; +wpn_fB[9]=(FLOAT)0; +wpn_fX[9]=(FLOAT)0.14; +wpn_fY[9]=(FLOAT)-0.41; +wpn_fZ[9]=(FLOAT)-0.335001; +wpn_fFOV[9]=(FLOAT)44.5; +wpn_fClip[9]=(FLOAT)0.1; +wpn_fFX[9]=(FLOAT)0; +wpn_fFY[9]=(FLOAT)0; + +// iron cannon +wpn_fH[16]=(FLOAT)2.5; +wpn_fP[16]=(FLOAT)6; +wpn_fB[16]=(FLOAT)0; +wpn_fX[16]=(FLOAT)0.225; +wpn_fY[16]=(FLOAT)-0.345; +wpn_fZ[16]=(FLOAT)-0.57; +wpn_fFOV[16]=(FLOAT)57; +wpn_fClip[16]=(FLOAT)0.1; +wpn_fFX[16]=(FLOAT)0.25; +wpn_fFY[16]=(FLOAT)-0.5; + +#pragma warning(default: 4305) + +#endif + diff --git a/Sources/Entities/Copier.es b/Sources/Entities/Copier.es new file mode 100644 index 0000000..7de96fa --- /dev/null +++ b/Sources/Entities/Copier.es @@ -0,0 +1,94 @@ +225 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/BasicEffects"; + +class CCopier : CRationalEntity { +name "Copier"; +thumbnail "Thumbnails\\Copier.tbn"; +features "HasName", "HasTarget", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Copier", + 3 CTString m_strDescription = "", + 2 CEntityPointer m_penTarget "Target" 'T' COLOR(C_BROWN|0xFF), + 4 BOOL m_bSpawnEffect "Spawn Effect" 'X' = TRUE, + +components: + 1 model MODEL_TELEPORT "Models\\Editor\\Copier.mdl", + 2 texture TEXTURE_TELEPORT "Models\\Editor\\Copier.tex", + 3 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +functions: + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s",(const char*) m_penTarget->GetName()); + } + return m_strDescription; + } + + void TeleportEntity() + { + // if the target doesn't exist, or is destroyed + if (m_penTarget==NULL || (m_penTarget->GetFlags()&ENF_DELETED)) { + // do nothing + return; + } + + CEntity *pen = GetWorld()->CopyEntityInWorld( *m_penTarget, + CPlacement3D(FLOAT3D(-32000.0f+FRnd()*200.0f, -32000.0f+FRnd()*200.0f, 0), ANGLE3D(0, 0, 0)) ); + + // teleport back + CPlacement3D pl = GetPlacement(); + pl.pl_PositionVector += GetRotationMatrix().GetColumn(2)*0.05f; + pen->Teleport(pl); + + // spawn teleport effect + if (m_bSpawnEffect) { + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_TELEPORT; + ese.vNormal = FLOAT3D(0,1,0); + FLOATaabbox3D box; + pen->GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm()*2; + ese.vStretch = FLOAT3D(fEntitySize, fEntitySize, fEntitySize); + CEntityPointer penEffect = CreateEntity(GetPlacement(), CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_TOUCHMODEL); + + // set appearance + SetModel(MODEL_TELEPORT); + SetModelMainTexture(TEXTURE_TELEPORT); + + while (TRUE) { + // wait to someone enter and teleport it + wait() { + on (ETrigger eTrigger) : { + if (m_penTarget!=NULL) { + TeleportEntity(); + } + stop; + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } +}; + diff --git a/Sources/Entities/Counter.es b/Sources/Entities/Counter.es new file mode 100644 index 0000000..5b8744c --- /dev/null +++ b/Sources/Entities/Counter.es @@ -0,0 +1,124 @@ +232 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelHolder2"; + +class CCounter : CRationalEntity { +name "Counter"; +thumbnail "Thumbnails\\Counter.tbn"; +features "HasName", "IsTargetable", "IsImportant"; + +properties: + 1 FLOAT m_fCountdownSpeed "Countdown speed" 'S' = 12.0f, + 2 CEntityPointer m_penTarget "Zero target" 'T' COLOR(C_WHITE|0x80), + 3 FLOAT m_fNumber = 0.0f, + 4 FLOAT m_tmStart = -1.0f, + 5 CTString m_strName "Name" 'N' ="", + 6 CSoundObject m_soSound, + 7 INDEX m_iCountFrom "Count start" 'A' = 1023, + 10 CEntityPointer m_pen0 "Bit 0" COLOR(C_RED|0x30), + 11 CEntityPointer m_pen1 "Bit 1" COLOR(C_RED|0x30), + 12 CEntityPointer m_pen2 "Bit 2" COLOR(C_RED|0x30), + 13 CEntityPointer m_pen3 "Bit 3" COLOR(C_RED|0x30), + 14 CEntityPointer m_pen4 "Bit 4" COLOR(C_RED|0x30), + 15 CEntityPointer m_pen5 "Bit 5" COLOR(C_RED|0x30), + 16 CEntityPointer m_pen6 "Bit 6" COLOR(C_RED|0x30), + 17 CEntityPointer m_pen7 "Bit 7" COLOR(C_RED|0x30), + 18 CEntityPointer m_pen8 "Bit 8" COLOR(C_RED|0x30), + 19 CEntityPointer m_pen9 "Bit 9" COLOR(C_RED|0x30), + +components: + 0 sound SOUND_TICK "Sounds\\Menu\\Select.wav", + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + +functions: + void Precache(void) + { + PrecacheSound( SOUND_TICK); + CRationalEntity::Precache(); + } + + void DisplayNumber(void) + { + for( INDEX iDigit=0; iDigit<10; iDigit++) + { + CModelHolder2 *pmh = (CModelHolder2 *)&*(&m_pen0)[iDigit]; + if( pmh!=NULL && pmh->GetModelObject()!=NULL && + pmh->GetModelObject()->mo_toTexture.GetData()!=NULL) + { + // set texture animation + INDEX iOldAnim = pmh->GetModelObject()->mo_toTexture.GetAnim(); + INDEX iAnim=(INDEX(m_fNumber)&(1<>iDigit; + pmh->GetModelObject()->mo_toTexture.PlayAnim(iAnim, 0); + + // play sound + m_soSound.Set3DParameters(200.0f, 100.0f, 1.0f, + Clamp(1.0f+(m_iCountFrom-m_fNumber)/m_iCountFrom*2.0f, 1.0f, 3.0f) ); + if( iDigit==0 && iOldAnim!=iAnim /*iOldAnim==1 && iAnim==0 */&& !m_soSound.IsPlaying()) + { + PlaySound(m_soSound, SOUND_TICK, SOF_3D|SOF_VOLUMETRIC); + } + } + } + } + +procedures: + CountDown() + { + while( TRUE) + { + autowait(_pTimer->TickQuantum); + FLOAT tmNow = _pTimer->CurrentTick(); + FLOAT tmDelta = tmNow-m_tmStart; + FLOAT fSub = Clamp( tmDelta/m_fCountdownSpeed, 0.01f, 1.0f); + m_fNumber = Clamp( m_fNumber-fSub, 0.0f, FLOAT(m_iCountFrom)); + DisplayNumber(); + if( m_fNumber==0) + { + return EReturn(); + } + } + } + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + autowait(0.1f); + m_fNumber = m_iCountFrom; + DisplayNumber(); + + wait() { + on(EBegin): { + resume; + } + on (ETrigger eTrigger): { + m_fNumber = m_iCountFrom; + DisplayNumber(); + m_tmStart = _pTimer->CurrentTick(); + call CountDown(); + } + on(EReturn): { + if( m_penTarget!= NULL) + { + SendToTarget(m_penTarget, EET_TRIGGER); + } + stop; + } + } + + return; + } +}; diff --git a/Sources/Entities/CrateRider.es b/Sources/Entities/CrateRider.es new file mode 100644 index 0000000..19680b4 --- /dev/null +++ b/Sources/Entities/CrateRider.es @@ -0,0 +1,214 @@ +341 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Mental/Mental.h" +#include "Models/CutSequences/CrateRider/Crate.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/BasicEffects"; + +%{ +// info structure +static EntityInfo eiCrate = { + EIBT_FLESH, 500.0f, + 0.0f, 1.5f, 0.0f, // source (eyes) + 0.0f, 1.0f, 0.0f, // target (body) +}; + +#define GREET_SENSE_RANGE 10.0f +#define GREET_SENSE_DELAY 10.0f + +%} + +class CCrateRider: CEnemyBase { +name "CrateRider"; +thumbnail "Thumbnails\\Mental.tbn"; + +properties: + // class internal + 1 CTFileName m_fnmHeadTex1 "Head texture1" 'H' = CTString(""), + 2 CTFileName m_fnmHeadTex2 "Head texture2" = CTString(""), + 3 CTFileName m_fnmDriveSnd "Drive sound" 'S' = CTString(""), + + { + CAutoPrecacheSound m_aps; + CAutoPrecacheTexture m_apt1; + CAutoPrecacheTexture m_apt2; + } + +components: + 1 class CLASS_BASE "Classes\\EnemyBase.ecl", + 2 class CLASS_DEBRIS "Classes\\Debris.ecl", + 3 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +// ************** DATA ************** + 10 model MODEL_MENTAL "Models\\Enemies\\Mental\\Mental.mdl", + 11 texture TEXTURE_MENTAL "Models\\Enemies\\Mental\\Mental.tex", + 12 model MODEL_HEAD "Models\\Enemies\\Mental\\Head.mdl", + 13 model MODEL_CRATE "Models\\CutSequences\\CrateRider\\Crate.mdl", + 14 texture TEXTURE_CRATE "Models\\CutSequences\\CrateRider\\Crate.tex", + 15 texture TEXTURE_BUMP "Models\\CutSequences\\Bridge\\BridgeBump.tex", + +functions: + /* Entity info */ + void *GetEntityInfo(void) + { + return &eiCrate; + }; + + void Precache(void) + { + CEnemyBase::Precache(); + + PrecacheClass(CLASS_DEBRIS); + + m_apt1.Precache(m_fnmHeadTex1); + m_apt2.Precache(m_fnmHeadTex2); + m_aps.Precache(m_fnmDriveSnd); + }; + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + iAnim = 0; + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + iAnim = 0; + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { +// ChangeCollisionBoxIndexWhenPossible(HEADMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(CRATE_ANIM_DEFAULT, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); + + CModelObject *pmo0 = &(GetModelObject()->GetAttachmentModel(0)->amo_moModelObject); + pmo0->PlayAnim(MENTAL_ANIM_CRATEANIMLEFTSEATING, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); + CModelObject *pmo1 = &(GetModelObject()->GetAttachmentModel(1)->amo_moModelObject); + pmo1->PlayAnim(MENTAL_ANIM_CRATEANIMRIGHTSEATING, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); + + m_soSound.Stop(); + }; + void WalkingAnim(void) { + RunningAnim(); + StartModelAnim(CRATE_ANIM_DRIVE, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) + { + if (m_fnmDriveSnd!="") { + PlaySound(m_soSound, m_fnmDriveSnd, SOF_3D); + } + CModelObject *pmo0 = &(GetModelObject()->GetAttachmentModel(0)->amo_moModelObject); + pmo0->PlayAnim(MENTAL_ANIM_CRATEANIMLEFT, AOF_LOOPING|AOF_NORESTART); + CModelObject *pmo1 = &(GetModelObject()->GetAttachmentModel(1)->amo_moModelObject); + pmo1->PlayAnim(MENTAL_ANIM_CRATEANIMRIGHT, AOF_LOOPING|AOF_NORESTART); + + StartModelAnim(CRATE_ANIM_DRIVE, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + RunningAnim(); + }; + + // virtual sound functions + void IdleSound(void) { +// PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + + void SightSound(void) { +// PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { +// PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { +// PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + void AddRider(INDEX i, const CTFileName &fnmHead) + { + AddAttachment(i, MODEL_MENTAL, TEXTURE_MENTAL); + CModelObject *pmoMain = &(GetModelObject()->GetAttachmentModel(i)->amo_moModelObject); +// pmoMain->PlayAnim(i==0 ? MENTAL_ANIM_CRATEANIMLEFTSEATING : MENTAL_ANIM_CRATEANIMRIGHTSEATING, AOF_LOOPING); + pmoMain->PlayAnim(i==0 ? MENTAL_ANIM_CRATEANIMLEFT: MENTAL_ANIM_CRATEANIMRIGHT, AOF_LOOPING); + AddAttachmentToModel(this, *pmoMain, 0, MODEL_HEAD, TEXTURE_MENTAL, 0, 0, 0); + CModelObject *pmoHead = &(pmoMain->GetAttachmentModel(0)->amo_moModelObject); + if (fnmHead!="") { + // try to + try { + pmoHead->mo_toTexture.SetData_t(fnmHead); + // if anything failed + } catch (char *strError) { + // report error + CPrintF("%s\n", strError); + } + } + } + +procedures: + + /************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(1.0f); + m_fMaxHealth = 1.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 2000.0f; + m_fBlowUpSize = 2.0f; + + // set your appearance + SetModel(MODEL_CRATE); + SetModelMainTexture(TEXTURE_CRATE); + AddRider(0, m_fnmHeadTex1); + AddRider(1, m_fnmHeadTex2); + + // setup moving speed + m_fWalkSpeed = + m_fAttackRunSpeed = + m_fCloseRunSpeed = 1.0f; + m_aWalkRotateSpeed = AngleDeg(30.0f); + m_aAttackRotateSpeed = AngleDeg(30); + m_aCloseRotateSpeed = AngleDeg(30); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 5.0f; // greeting distance + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 0.0f; + m_fBodyParts = 4; + m_fDamageWounded = 1.0f; + m_iScore = 0; + m_bBlind = TRUE; + m_bRobotBlowup = TRUE; +// m_fSenseRange = GREET_SENSE_RANGE; + + // set stretch factors for height and width + const FLOAT fSize = 0.6f; + GetModelObject()->StretchModel(FLOAT3D(fSize, fSize, fSize)); + ModelChangeNotify(); + StandingAnim(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Cyborg.es b/Sources/Entities/Cyborg.es new file mode 100644 index 0000000..f1c61b8 --- /dev/null +++ b/Sources/Entities/Cyborg.es @@ -0,0 +1,743 @@ +330 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Cyborg/Cyborg.h" +%} + + +uses "Entities/EnemyFly"; +uses "Entities/Projectile"; +uses "Entities/CyborgBike"; + + +enum CyborgType { + 0 CBT_GROUND "Ground", + 1 CBT_FLY "Fly", + 2 CBT_FLYGROUND "Fly-Ground", +}; + + +%{ +// info structure +static EntityInfo eiCyborgStand = { + EIBT_ROBOT, 200.0f, + 0.0f, 1.55f, 0.0f, + 0.0f, 1.0f, 0.0f, +}; +static EntityInfo eiCyborgFly = { + EIBT_ROBOT, 1500.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; + +#define FIRE_BIKE FLOAT3D(-0.35f, 0.1f, -1.2f) +#define FIRE_LASER FLOAT3D(-0.5f, 1.7f, -0.75f) + +#define IGNORE_RANGE 400.0f + +#define BIKE_ATTACHMENT FLOAT3D(0, 0, -0.271f) +%} + + +class CCyborg : CEnemyBase { +name "Cyborg"; +thumbnail "Thumbnails\\Cyborg.tbn"; + +properties: + 1 enum CyborgType m_EctType "Type" 'T' = CBT_GROUND, // type + 2 INDEX m_iCloseHit = 0, // close hit hand (left or right) + 3 INDEX m_iFireLaserCount = 0, // fire laser binary divider + 4 INDEX m_ctBombsToDrop = 0, // counter of bombs to drop in fly-over + 10 FLOAT m_tmLastBombDropped = -1.0f, // when last bomb was dropped + 5 FLOAT m_fFlyAboveEnemy = 0.0f, // fly above enemy height + 6 FLOAT m_fFlySpeed = 0.0f, + 7 FLOAT m_aFlyRotateSpeed = 0.0f, + 8 FLOAT m_fFallStartTime = 0.0f, + 9 BOOL m_bBombing "Bombing" 'B' = FALSE, // enable bombing + +{ + CEntity *penBullet; // bullet +} + +components: + 0 class CLASS_BASE "Classes\\EnemyFly.ecl", + 1 class CLASS_BULLET "Classes\\Bullet.ecl", + 2 class CLASS_CYBORG_BIKE "Classes\\CyborgBike.ecl", + 3 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + + 10 model MODEL_CYBORG "Models\\Enemies\\Cyborg\\Cyborg.mdl", + 11 model MODEL_ASS "Models\\Enemies\\Cyborg\\AssHole.mdl", + 12 model MODEL_TORSO "Models\\Enemies\\Cyborg\\Torso.mdl", + 13 model MODEL_HEAD "Models\\Enemies\\Cyborg\\Head.mdl", + 14 model MODEL_RIGHT_UPPER_ARM "Models\\Enemies\\Cyborg\\RightUpperArm.mdl", + 15 model MODEL_RIGHT_LOWER_ARM "Models\\Enemies\\Cyborg\\RightLowerArm.mdl", + 16 model MODEL_LEFT_UPPER_ARM "Models\\Enemies\\Cyborg\\LeftUpperArm.mdl", + 17 model MODEL_LEFT_LOWER_ARM "Models\\Enemies\\Cyborg\\LeftLowerArm.mdl", + 18 model MODEL_RIGHT_UPPER_LEG "Models\\Enemies\\Cyborg\\RightUpperLeg.mdl", + 19 model MODEL_RIGHT_LOWER_LEG "Models\\Enemies\\Cyborg\\RightLowerLeg.mdl", + 20 model MODEL_LEFT_UPPER_LEG "Models\\Enemies\\Cyborg\\LeftUpperLeg.mdl", + 21 model MODEL_LEFT_LOWER_LEG "Models\\Enemies\\Cyborg\\LeftLowerLeg.mdl", + 22 model MODEL_FOOT "Models\\Enemies\\Cyborg\\Foot.mdl", + 23 model MODEL_BIKE "Models\\Enemies\\Cyborg\\Bike.mdl", + 30 texture TEXTURE_CYBORG "Models\\Enemies\\Cyborg\\Cyborg.tex", + 31 texture TEXTURE_BIKE "Models\\Enemies\\Cyborg\\Bike.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Cyborg\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Cyborg\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Cyborg\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Cyborg\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Cyborg\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Cyborg\\Sounds\\Death.wav", + +// ************** REFLECTIONS ************** +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", + +// ************** SPECULAR ************** +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + if (m_EctType!=CBT_GROUND) { + return &eiCyborgFly; + } else { + return &eiCyborgStand; + } + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // cyborg can't harm cyborg + if (!IsOfClass(penInflictor, "Cyborg")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + switch (IRnd()%4) { + case 0: iAnim = CYBORG_ANIM_WOUND01; break; + case 1: iAnim = CYBORG_ANIM_WOUND02; break; + case 2: iAnim = CYBORG_ANIM_WOUND03; break; + case 3: iAnim = CYBORG_ANIM_WOUND04; break; + default: ASSERTALWAYS("Cyborg unknown damage"); + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = CYBORG_ANIM_DEATH01; break; + case 1: iAnim = CYBORG_ANIM_DEATH02; break; + default: ASSERTALWAYS("Cyborg unknown death"); + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + + // virtual anim functions + void StandingAnim(void) { + if (m_EctType!=CBT_GROUND) { + StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(CYBORG_ANIM_WAIT01, AOF_LOOPING|AOF_NORESTART); + } + }; + void WalkingAnim(void) { + if (m_EctType!=CBT_GROUND) { + StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(CYBORG_ANIM_WALK01, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) { + if (m_EctType!=CBT_GROUND) { + StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(CYBORG_ANIM_WALK01, AOF_LOOPING|AOF_NORESTART); + } + }; + void RotatingAnim(void) { + if (m_EctType!=CBT_GROUND) { + StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(CYBORG_ANIM_WALK01, AOF_LOOPING|AOF_NORESTART); + } + }; + void ChangeCollisionToAir() { + ChangeCollisionBoxIndexWhenPossible(CYBORG_COLLISION_BOX_BIKE); + }; + void ChangeCollisionToGround() { + ChangeCollisionBoxIndexWhenPossible(CYBORG_COLLISION_BOX_GROUND); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + // spawn body parts + void BlowUp(void) { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + + // spawn debris + Debris_Begin(EIBT_ROBOT, DPR_SMOKETRAIL, BET_EXPLOSIONSTAIN, fEntitySize, m_vDamage*0.3f, + en_vCurrentTranslationAbsolute, 1.0f, 0.0f); + + Debris_Spawn(this, this, MODEL_ASS, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_TORSO, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_STRONG, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_HEAD, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_RIGHT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_RIGHT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_LEFT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_LEFT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_RIGHT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_RIGHT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_LEFT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_LEFT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0, + 0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + + // spawn explosion + CPlacement3D plExplosion = GetPlacement(); + CEntityPointer penExplosion = CreateEntity(plExplosion, CLASS_BASIC_EFFECT); + ESpawnEffect eSpawnEffect; + eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; + eSpawnEffect.betType = BET_BOMB; + FLOAT fSize = fEntitySize*0.3f; + eSpawnEffect.vStretch = FLOAT3D(fSize,fSize,fSize); + penExplosion->Initialize(eSpawnEffect); + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + }; + + + +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + // fly desired position for attack + virtual void FlyDesiredPosition(FLOAT3D &vPos) { + FLOAT fDist = (m_penEnemy->GetPlacement().pl_PositionVector - + GetPlacement().pl_PositionVector).Length(); + vPos = m_penEnemy->GetPlacement().pl_PositionVector; + vPos += FLOAT3D(m_penEnemy->en_mRotation(1, 2), + m_penEnemy->en_mRotation(2, 2), + m_penEnemy->en_mRotation(3, 2)) * m_fFlyAboveEnemy; + }; + + // fly move in direction + void FlyInDirection() { + /* !!!! + RotateToAngle(); + + // determine translation speed + FLOAT3D vTranslation = (m_vDesiredPosition - GetPlacement().pl_PositionVector) * !en_mRotation; + vTranslation(1) = 0.0f; + vTranslation.Normalize(); + vTranslation *= m_fMoveSpeed; + + // start moving + SetDesiredTranslation(vTranslation); + */ + }; + + // fly entity to desired position + void FlyToPosition() { + +/* !!!! + CalcAngleFromPosition(); + FlyInDirection(); + */ + }; + + + +procedures: +/************************************************************ + * CLASS INTERNAL * + ************************************************************/ + // fall to floor + FallToFloor(EVoid) { + // spawn bike + CPlacement3D plBike = GetPlacement(); + FLOATmatrix3D mRotation; + MakeRotationMatrixFast(mRotation, GetPlacement().pl_OrientationAngle); + plBike.pl_PositionVector += BIKE_ATTACHMENT*mRotation; + + ECyborgBike ecb; + ecb.fSpeed = m_fFlySpeed*2.0f; + CEntityPointer penBike = CreateEntity(plBike, CLASS_CYBORG_BIKE); + penBike->Initialize(ecb); + + // drop to floor + m_EctType = CBT_GROUND; + SetPhysicsFlags(EPF_MODEL_WALKING); + ChangeCollisionToGround(); + + // remove bike + RemoveAttachmentFromModel(*GetModelObject(), CYBORG_ATTACHMENT_BIKE); + + // anim + if (IRnd()&1) { + StartModelAnim(CYBORG_ANIM_FALL01, 0); + } else { + StartModelAnim(CYBORG_ANIM_FALL02, 0); + } + + // wait to touch brush or time limit + m_fFallStartTime = _pTimer->CurrentTick(); + wait (10.0f) { + on (EBegin) : { resume; } + // brush touched + on (ETouch et) : { + if (et.penOther->GetRenderType()&RT_BRUSH) { + StopMoving(); + stop; + } + resume; + } + on (EDamage) : { resume; } + on (EWatch) : { resume; } + on (ETimer) : { stop; } + } + + // wait fall anim + if (_pTimer->CurrentTick() < m_fFallStartTime+1.5f) { + wait(m_fFallStartTime+1.5f - _pTimer->CurrentTick()) { + on (EBegin) : { resume; } + on (EDamage) : { resume; } + on (EWatch) : { resume; } + on (ETimer) : { stop; } + } + } + return EReturn(); + }; + + // get up + GetUp(EVoid) { + // get up + StartModelAnim(CYBORG_ANIM_GETUP, 0); + wait(GetModelObject()->GetAnimLength(CYBORG_ANIM_GETUP)) { + on (EBegin) : { resume; } + on (EDamage) : { resume; } + on (EWatch) : { resume; } + on (ETimer) : { stop; } + } + return EReturn(); + }; + + + +/************************************************************ + * PROCEDURES WHEN NO ANY SPECIAL ACTION * + ************************************************************/ + // Move to destination +/* !!!! + MoveToDestination(EVoid) : CEnemyBase::MoveToDestination { + // animation + if (m_bRunToMarker) { + RunningAnim(); + } else { + WalkingAnim(); + } + // fly to position + if (m_EctType!=CBT_GROUND) { + m_fMoveFrequency = 0.25f; + m_fMovePrecision = m_fMoveSpeed*m_fMoveFrequency*2.0f; + while ((m_vDesiredPosition-GetPlacement().pl_PositionVector).Length()>m_fMovePrecision) { + wait (0.25f) { + on (EBegin) : { FlyToPosition(); } + on (ETimer) : { stop; } + } + } + return EReturn(); + // move to position + } else { + jump CEnemyBase::MoveToDestination(); + } + }; + */ + + + +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + // Play wound animation and falling body part + BeWounded(EDamage eDamage) : CEnemyBase::BeWounded { + // damage only on ground + if (m_EctType==CBT_GROUND) { + jump CEnemyBase::BeWounded(eDamage); + // fall on ground + } else if (m_EctType==CBT_FLYGROUND && GetHealth()<=60.0f) { + SetHealth(60.0f); + m_fMaxHealth = 60.0f; + autocall FallToFloor() EReturn; + autocall GetUp() EReturn; + SendEvent(ERestartAttack()); + } + return EReturn(); + }; + + + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + AttackEnemy(EVoid) : CEnemyBase::AttackEnemy { + // air attack + if (m_EctType!=CBT_GROUND) { + jump FlyAttackEnemy(); + // ground attack + } else if (TRUE) { + jump CEnemyBase::AttackEnemy(); + } + }; + + // fly attack enemy + FlyAttackEnemy(EVoid) { + // initial preparation + autocall CEnemyBase::InitializeAttack() EReturn; + + // while you have some enemy + while (m_penEnemy != NULL) { + // to far cease attack + if (CalcDist(m_penEnemy) > IGNORE_RANGE) { + SetTargetNone(); + } + + if (m_penEnemy != NULL) { + // attack run + if (SeeEntity(m_penEnemy, CosFast(90.0f))) { + autocall FlyAttackRun() EReturn; + // go away and rotate + } else if (TRUE) { + autocall GoAwayAndRotate() EReturn; + } + } + } + + // stop attack + autocall CEnemyBase::StopAttack() EReturn; + + // return to Move() procedure + return EBegin(); + }; + + // fly attack run + FlyAttackRun(EVoid) { + m_iFireLaserCount = 0; + if (m_bBombing) { + m_ctBombsToDrop = 3; + } + while (SeeEntity(m_penEnemy, CosFast(90.0f))) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + on (EBegin) : { + if (IsInFrustum(m_penEnemy, CosFast(55.0f))) { + // fire laser + if (m_iFireLaserCount==0) { + ShootProjectile(PRT_CYBORG_LASER, FIRE_BIKE, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + } + if (m_iFireLaserCount++ == 2) { + m_iFireLaserCount = 0; + } + } + + // if a bomb may be dropped + if (m_ctBombsToDrop>0 && _pTimer->CurrentTick()>=m_tmLastBombDropped+0.3f) { + // calculate where it would hit + FLOAT fV = en_vCurrentTranslationAbsolute.Length(); + FLOAT fD = CalcDist(m_penEnemy); + FLOAT fDP = CalcPlaneDist(m_penEnemy); + FLOAT fH = Sqrt(fD*fD-fDP*fDP); + FLOAT fHitD = fDP-fV*Sqrt(2*fH/en_fGravityA); + + // if close enough + if( Abs(fHitD)<10.0f) { + // drop it + CPlacement3D pl(FLOAT3D(FRnd()*2.0f-1.0f, -1.0f, 0.0f), ANGLE3D(0, 0, 0)); ; + pl.RelativeToAbsoluteSmooth(GetPlacement()); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_CYBORG_BOMB; + eLaunch.fSpeed = fV; + penProjectile->Initialize(eLaunch); + m_ctBombsToDrop--; + m_tmLastBombDropped = _pTimer->CurrentTick(); + } + } + + // inside attack radius + if (MayMoveToAttack()) { + m_fMoveSpeed = m_fFlySpeed; + m_aRotateSpeed = m_aFlyRotateSpeed; + FlyDesiredPosition(m_vDesiredPosition); + FlyToPosition(); + RunningAnim(); + // outside attack radius + } else { + StopMoving(); + StandingAnim(); + } + } + on (ETimer) : { stop; } + } + } + + return EReturn(); + }; + + GoAwayAndRotate(EVoid) { + // go away + SetDesiredTranslation(FLOAT3D(0, 1.25f, -m_fFlySpeed)); + StopRotating(); + autowait(1.0f); + + // rotate side + if (IRnd()&1) { + SetDesiredRotation(ANGLE3D( 100.0f, 0, 0)); + } else { + SetDesiredRotation(ANGLE3D(-100.0f, 0, 0)); + } + + // rotate to enemy + SetDesiredTranslation(FLOAT3D(0, 0, -m_fFlySpeed)); + while (!SeeEntityInPlane(m_penEnemy, CosFast(5.0f))) { + autowait(_pTimer->TickQuantum); + } + + return EReturn(); + }; + + Fire(EVoid) : CEnemyBase::Fire { + // to fire + StartModelAnim(CYBORG_ANIM_TOFIRE, 0); + m_fLockOnEnemyTime = GetModelObject()->GetAnimLength(CYBORG_ANIM_TOFIRE) + FRnd()/3; + autocall CEnemyBase::LockOnEnemy() EReturn; + + StartModelAnim(CYBORG_ANIM_FIRE02, 0); + ShootProjectile(PRT_CYBORG_LASER, FIRE_LASER, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + + m_fLockOnEnemyTime = 0.5f; + autocall CEnemyBase::LockOnEnemy() EReturn; + StartModelAnim(CYBORG_ANIM_FIRE02, 0); + ShootProjectile(PRT_CYBORG_LASER, FIRE_LASER, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + + m_fLockOnEnemyTime = 0.5f; + autocall CEnemyBase::LockOnEnemy() EReturn; + StartModelAnim(CYBORG_ANIM_FIRE02, 0); + ShootProjectile(PRT_CYBORG_LASER, FIRE_LASER, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.1f + FRnd()/3); + + m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/3.0f); + + // from fire + StartModelAnim(CYBORG_ANIM_FROMFIRE, 0); + autowait(GetModelObject()->GetAnimLength(CYBORG_ANIM_FROMFIRE)); + + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + // animation + m_iCloseHit = IRnd()&1; + if (m_iCloseHit==0) { + StartModelAnim(CYBORG_ANIM_ATTACKCLOSE01, 0); + } else { + StartModelAnim(CYBORG_ANIM_ATTACKCLOSE02, 0); + } + + autowait(0.9f); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 15.0f, FLOAT3D(0, 0, 0), vDirection); + // push target left/right + FLOAT3D vSpeed; + if (m_iCloseHit==0) { + GetHeadingDirection(AngleDeg(90.0f), vSpeed); + } else { + GetHeadingDirection(AngleDeg(-90.0f), vSpeed); + } + vSpeed = vSpeed * 5.0f; + KickEntity(m_penEnemy, vSpeed); + } + + return EReturn(); + }; + + + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + StopMoving(); // stop moving + DeathSound(); // death sound + + // death notify (usually change collision box and change body density) + ChangeCollisionBoxIndexWhenPossible(CYBORG_COLLISION_BOX_DEATH); + + // set physic flags + SetPhysicsFlags(EPF_MODEL_CORPSE); + SetCollisionFlags(ECF_CORPSE); + + if (m_EctType==CBT_FLY || m_EctType==CBT_FLYGROUND) { + autocall FallToFloor() EReturn; + } else if (TRUE) { + // start death anim + INDEX iAnim = AnimForDeath(); + autowait(GetModelObject()->GetAnimLength(iAnim)); + } + + // death twist + StartModelAnim(CYBORG_ANIM_DEATHTWIST, AOF_LOOPING); + autowait(FRnd()*5.0f + 1.0f); + StartModelAnim(CYBORG_ANIM_DEATHREST, 0); + + // explode + SetHealth(-45.0f); + ReceiveDamage(NULL, DMT_EXPLOSION, 10.0f, FLOAT3D(0,0,0), FLOAT3D(0,1,0)); + + return EEnd(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + en_fDensity = 5000.0f; + + // set your appearance + SetModel(MODEL_CYBORG); + SetModelMainTexture(TEXTURE_CYBORG); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_ASS, + MODEL_ASS, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_TORSO, + MODEL_TORSO, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_STRONG, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_HEAD, + MODEL_HEAD, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTUPPERARM, + MODEL_RIGHT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTLOWERARM, + MODEL_RIGHT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTUPPERARM, + MODEL_LEFT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTLOWERARM, + MODEL_LEFT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTUPPERLEG, + MODEL_RIGHT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTLOWERLEG, + MODEL_RIGHT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTUPPERLEG, + MODEL_LEFT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTLOWERLEG, + MODEL_LEFT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_FOOTRIGHT, + MODEL_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_FOOTLEFT, + MODEL_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + if (m_EctType!=CBT_GROUND) { + AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_BIKE, + MODEL_BIKE, TEXTURE_BIKE, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + // fly in air + SetHealth(90.0f); + m_fMaxHealth = 90.0f; + ChangeCollisionToAir(); + SetPhysicsFlags(EPF_MODEL_FLYING); + m_iScore = 1000; + } else { + // walk on ground + SetHealth(60.0f); + m_fMaxHealth = 60.0f; + ChangeCollisionToGround(); + SetPhysicsFlags(EPF_MODEL_WALKING); + m_iScore = 500; + } + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd()*3.0f + 6.0f; + m_aWalkRotateSpeed = FRnd()*20.0f + 700.0f; + m_fAttackRunSpeed = m_fWalkSpeed; + m_aAttackRotateSpeed = m_aWalkRotateSpeed; + m_fCloseRunSpeed = m_fWalkSpeed; + m_aCloseRotateSpeed = m_aWalkRotateSpeed; + m_fWalkSpeed/=3; + + // setup attack distances + m_fAttackDistance = 100.0f; + m_fCloseDistance = 2.5f; + m_fStopDistance = 1.5; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 2.0f; + m_fIgnoreRange = 200.0f; + // fly moving properties + m_fFlyAboveEnemy = 10.0f+FRnd()*1.0f; + m_fFlySpeed = FRnd()*5.0f + 20.0f; + m_aFlyRotateSpeed = FRnd()*25.0f + 100.0f; + // damage/explode properties + m_fBlowUpAmount = 90.0f; + m_fDamageWounded = 50.0f; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/CyborgBike.es b/Sources/Entities/CyborgBike.es new file mode 100644 index 0000000..1930ebc --- /dev/null +++ b/Sources/Entities/CyborgBike.es @@ -0,0 +1,132 @@ +331 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Cyborg/Bike.h" +%} + + +uses "Entities/BasicEffects"; +uses "Entities/Debris"; + +event ECyborgBike { + FLOAT fSpeed, +}; + + +%{ +static EntityInfo eiCyborgBike = { + EIBT_FLESH, 1300.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; +%} + + +class CCyborgBike : CMovableModelEntity { +name "Cyborg Bike"; +thumbnail ""; + +properties: + 1 FLOAT m_fSpeed = 0.0f, + 2 INDEX m_iIndex = 0, + +components: + 1 class CLASS_DEBRIS "Classes\\Debris.ecl", + 2 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +// ************** BIKE ************** + 10 model MODEL_BIKE "Models\\Enemies\\Cyborg\\Bike.mdl", + 11 texture TEXTURE_BIKE "Models\\Enemies\\Cyborg\\Bike.tex", + +// ************** REFLECTIONS ************** +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", + +// ************** SPECULAR ************** +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", + + +functions: + +procedures: +/************************************************************ + * M A I N L O O P * + ************************************************************/ + // main loop + MainLoop(EVoid) { + SetDesiredTranslation(FLOAT3D(0, -(2.0f+FRnd()*2.0f), -m_fSpeed)); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + + // wait to touch brush or time limit or death + wait (10.0f) { + on (EBegin) : { resume; } + // brush touched + on (ETouch et) : { + if (et.penOther->GetRenderType()&RT_BRUSH) { + SetDesiredTranslation(FLOAT3D(0, 0, 0)); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + stop; + } + resume; + } + on (EDamage) : { resume; } + on (EDeath) : { stop; } + on (ETimer) : { stop; } + } + + // hide yourself + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // explode + m_iIndex=0; + while (m_iIndex<4) { + // spawn effect + CPlacement3D plExplosion; + plExplosion.pl_PositionVector = FLOAT3D(FRnd()*4.0f-2.0f, FRnd()*4.0f-2.0f, FRnd()*2.0f); + plExplosion.RelativeToAbsolute(GetPlacement()); + ESpawnEffect eSpawnEffect; + eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; + eSpawnEffect.betType = BET_GRENADE; + eSpawnEffect.vStretch = FLOAT3D(1,1,1); + CEntityPointer penExplosion = CreateEntity(plExplosion, CLASS_BASIC_EFFECT); + penExplosion->Initialize(eSpawnEffect); + + // damage + FLOAT3D vSource; + GetEntityInfoPosition(this, eiCyborgBike.vTargetCenter, vSource); + InflictRangeDamage(this, DMT_EXPLOSION, 15.0f, vSource, 4.0f, 8.0f); + + // next explosion + autowait(0.1f + FRnd()/5); + m_iIndex++; + } + + // cease to exist + Destroy(); + + return; + }; + + + // dummy main + Main(ECyborgBike ecb) { + m_fSpeed = ecb.fSpeed; + + // declare yourself as a model + InitAsModel(); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetPhysicsFlags(EPF_MODEL_FLYING); + en_fDensity = 5000.0f; + SetHealth(50.0f); + + // set your appearance + SetComponents(this, *GetModelObject(), MODEL_BIKE, TEXTURE_BIKE, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + ModelChangeNotify(); + + jump MainLoop(); + + return; + }; +}; diff --git a/Sources/Entities/Damager.es b/Sources/Entities/Damager.es new file mode 100644 index 0000000..6eb0674 --- /dev/null +++ b/Sources/Entities/Damager.es @@ -0,0 +1,73 @@ +229 +%{ +#include "Entities/StdH/StdH.h" +%} + +class CDamager: CRationalEntity { +name "Damager"; +thumbnail "Thumbnails\\Damager.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Damager", + 2 CTString m_strDescription = "", + 3 enum DamageType m_dmtType "Type" 'Y' = DMT_ABYSS, // type of damage + 4 FLOAT m_fAmmount "Ammount" 'A' = 1000.0f, // ammount of damage + 5 CEntityPointer m_penToDamage "Entity to Damage" 'E', // entity to damage, NULL to damage the triggerer + 6 BOOL m_bDamageFromTriggerer "DamageFromTriggerer" 'S' = FALSE, // make the triggerer inflictor of the damage + +components: + 1 model MODEL_TELEPORT "Models\\Editor\\Copier.mdl", + 2 texture TEXTURE_TELEPORT "Models\\Editor\\Copier.tex", + +functions: + const CTString &GetDescription(void) const { + return m_strDescription; + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_TELEPORT); + SetModelMainTexture(TEXTURE_TELEPORT); + + ((CTString&)m_strDescription).PrintF("%s:%g", + DamageType_enum.NameForValue(INDEX(m_dmtType)), m_fAmmount); + + while (TRUE) { + // wait to someone trigger you and then damage it + wait() { + on (ETrigger eTrigger) : { + + CEntity *penInflictor = this; + if (m_bDamageFromTriggerer) { + penInflictor = eTrigger.penCaused; + } + + if (m_penToDamage!=NULL) { + InflictDirectDamage(m_penToDamage, penInflictor, + m_dmtType, m_fAmmount, + m_penToDamage->GetPlacement().pl_PositionVector, FLOAT3D(0,1,0)); + } else if (eTrigger.penCaused!=NULL) { + InflictDirectDamage(eTrigger.penCaused, penInflictor, + m_dmtType, m_fAmmount, + eTrigger.penCaused->GetPlacement().pl_PositionVector, FLOAT3D(0,1,0)); + } + stop; + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } +}; + diff --git a/Sources/Entities/Debris.es b/Sources/Entities/Debris.es new file mode 100644 index 0000000..0cf8055 --- /dev/null +++ b/Sources/Entities/Debris.es @@ -0,0 +1,276 @@ +602 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/BasicEffects"; + +enum DebrisParticlesType { + 0 DPT_NONE "", // no particles + 1 DPT_BLOODTRAIL "", // blood + 2 DPR_SMOKETRAIL "", // smoke + 3 DPR_SPARKS "", // sparks (for robots) + 4 DPR_FLYINGTRAIL "", // just flying object +}; + +// input parameter for spawning a debris +event ESpawnDebris { + EntityInfoBodyType Eeibt, // body type + CModelData *pmd, // model for this debris + FLOAT fSize, // stretch factor + CTextureData *ptd, // texture for this debris + CTextureData *ptdRefl, // reflection texture + CTextureData *ptdSpec, // specular texture + CTextureData *ptdBump, // bump texture + INDEX iModelAnim, // animation for debris model + enum DebrisParticlesType dptParticles, // particles type + enum BasicEffectType betStain, // stain left when touching brushes + COLOR colDebris, // multiply color for debris +}; + +%{ +%} + +class CDebris: CMovableModelEntity { +name "Debris"; +thumbnail ""; + +properties: + + 1 enum DebrisParticlesType m_dptParticles = DPT_NONE, // type of particles + 2 INDEX m_iBodyType = 0, // body type of this debris + 3 BOOL m_bFade = FALSE, // fade debris + 4 FLOAT m_fFadeStartTime = 0.0f, // fade start time + 5 FLOAT m_fFadeTime = 0.0f, // fade time + 6 FLOAT3D m_fLastStainHitPoint = FLOAT3D(0,0,0), // last stain hit point + 7 enum BasicEffectType m_betStain = BET_NONE, // type of stain left + 8 INDEX m_ctLeftStains = 0, // count of stains already left + 9 FLOAT m_tmStarted = 0.0f, // time when spawned + + +components: + + 1 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + + +functions: + + /* Entity info */ + void *GetEntityInfo(void) { + return GetStdEntityInfo((EntityInfoBodyType)m_iBodyType); + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // cannot be damaged immediately after spawning + if ((_pTimer->CurrentTick()-m_tmStarted<1.0f) + ||(dmtType==DMT_CANNONBALL_EXPLOSION) && (_pTimer->CurrentTick()-m_tmStarted<5.0f)) { + return; + } + CMovableModelEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + }; + +/************************************************************ + * FADE OUT * + ************************************************************/ + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + if (m_bFade) { + FLOAT fTimeRemain = m_fFadeStartTime + m_fFadeTime - _pTimer->CurrentTick(); + if (fTimeRemain < 0.0f) { fTimeRemain = 0.0f; } + COLOR colAlpha = GetModelObject()->mo_colBlendColor; + colAlpha = (colAlpha&0xffffff00) + (COLOR(fTimeRemain/m_fFadeTime*0xff)&0xff); + GetModelObject()->mo_colBlendColor = colAlpha; + } + + return FALSE; + }; + + + +/************************************************************ + * EFFECTS * + ************************************************************/ + + // leave a stain where hit + void LeaveStain(void) + { + // if no stains + if (m_betStain==BET_NONE) { + // do nothing + return; + } + + // don't allow too many stains to be left + if (m_ctLeftStains>5) { + return; + } + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D plPlaneNormal; + FLOAT fDistanceToEdge; + + // on plane + if (GetNearestPolygon(vPoint, plPlaneNormal, fDistanceToEdge)) { + // away from last hit point and near to polygon + if ((m_fLastStainHitPoint-vPoint).Length()>3.0f && + (vPoint-GetPlacement().pl_PositionVector).Length()<3.5f) { + m_fLastStainHitPoint = vPoint; + // stain + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = m_betStain; + ese.vNormal = FLOAT3D(plPlaneNormal); + GetNormalComponent( en_vCurrentTranslationAbsolute, plPlaneNormal, ese.vDirection); + FLOAT fLength = ese.vDirection.Length() / 7.5f; + fLength = Clamp( fLength, 1.0f, 15.0f); + ese.vStretch = FLOAT3D( 1.0f, fLength*1.0f, 1.0f); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f*(FRnd()+0.5f), ANGLE3D(0, 0, 0)), ese); + m_ctLeftStains++; + } + } + }; + + // spawn effect + void SpawnEffect(const CPlacement3D &plEffect, const class ESpawnEffect &eSpawnEffect) + { + CEntityPointer penEffect = CreateEntity(plEffect, CLASS_BASIC_EFFECT); + penEffect->Initialize(eSpawnEffect); + }; + + // particles + void RenderParticles(void) + { + // if going too slow + if (en_vCurrentTranslationAbsolute.Length()<0.1f) { + // don't render particles + return; + } + switch(m_dptParticles) { + case DPT_BLOODTRAIL: { + Particles_BloodTrail( this); + } break; + case DPR_SMOKETRAIL: { + Particles_GrenadeTrail( this); + } break; + case DPR_SPARKS: { + Particles_ColoredStarsTrail( this); + } break; + case DPR_FLYINGTRAIL:{ + //Particles_WhiteLineTrail( this); + Particles_BombTrail( this); + } break; + default: ASSERT(FALSE); + case DPT_NONE: + return; + } + }; + + // explode + void Explode(void) + { + // spawn explosion + CPlacement3D plExplosion = GetPlacement(); + CEntityPointer penExplosion = CreateEntity(plExplosion, CLASS_BASIC_EFFECT); + ESpawnEffect eSpawnEffect; + eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; + eSpawnEffect.betType = BET_BOMB; + eSpawnEffect.vStretch = FLOAT3D(0.3f,0.3f,0.3f); + penExplosion->Initialize(eSpawnEffect); + } + +/************************************************************ + * MAIN * + ************************************************************/ + +procedures: + + Main(ESpawnDebris eSpawn) + { + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING|EPF_CANFADESPINNING); + SetCollisionFlags(ECF_DEBRIS); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetHealth(25.0f); + en_fBounceDampNormal = 0.15f; + en_fBounceDampParallel = 0.5f; + en_fJumpControlMultiplier = 0.0f; + + // set density + if (eSpawn.Eeibt==EIBT_ICE) { + en_fDensity = 500.0f; + } else if (eSpawn.Eeibt==EIBT_WOOD) { + en_fDensity = 500.0f; + } else if (eSpawn.Eeibt==EIBT_FLESH) { + en_fDensity = 5000.0f; + en_fBounceDampNormal = 0.25f; + en_fBounceDampParallel = 0.75f; + } else if (TRUE) { + en_fDensity = 5000.0f; + } + + // set appearance + m_dptParticles = eSpawn.dptParticles, + m_betStain = eSpawn.betStain; + m_iBodyType = (INDEX)eSpawn.Eeibt; + GetModelObject()->SetData(eSpawn.pmd); + GetModelObject()->mo_toTexture.SetData(eSpawn.ptd); + GetModelObject()->mo_toReflection.SetData(eSpawn.ptdRefl); + GetModelObject()->mo_toSpecular.SetData(eSpawn.ptdSpec); + GetModelObject()->mo_toBump.SetData(eSpawn.ptdBump); + GetModelObject()->PlayAnim(eSpawn.iModelAnim, AOF_LOOPING); + GetModelObject()->mo_Stretch = FLOAT3D( eSpawn.fSize, eSpawn.fSize, eSpawn.fSize); + // adjust color + GetModelObject()->mo_colBlendColor = eSpawn.colDebris|CT_OPAQUE; + + ModelChangeNotify(); + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + if (fEntitySize>0.5f) { + SetCollisionFlags(ECF_MODEL); + } + en_fCollisionSpeedLimit+=ClampDn(0.0f, fEntitySize*10.0f); + m_bFade = FALSE; + m_fLastStainHitPoint = FLOAT3D(32000.0f, 32000.0f, 32000.0f); + m_ctLeftStains = 0; + m_tmStarted = _pTimer->CurrentTick(); + + // wait some time + wait(FRnd()*2.0f + 3.0f) { + on (EBegin) : { resume; } + // if touched something + on (ETouch etouch) : { + // if it is brush + if (etouch.penOther->GetRenderType()==RT_BRUSH) { + // maybe leave stain + LeaveStain(); + // if robot + if (m_iBodyType==EIBT_ROBOT) { + // explode + Explode(); + SendEvent(EDeath()); + resume; + } + } + resume; + } + on (EDeath) : { Destroy(); return; } + on (ETimer) : { stop; } + } + + // fade away + SetCollisionFlags(ECF_DEBRIS); + m_fFadeStartTime = _pTimer->CurrentTick(); + m_fFadeTime = 5.0f; + m_bFade = TRUE; + autowait(m_fFadeTime); + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/DestroyableArchitecture.es b/Sources/Entities/DestroyableArchitecture.es new file mode 100644 index 0000000..7d1b4bc --- /dev/null +++ b/Sources/Entities/DestroyableArchitecture.es @@ -0,0 +1,415 @@ +107 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/Effector.h" +#include "Entities/MovingBrush.h" +%} +uses "Entities/Devil"; +uses "Entities/Debris"; +uses "Entities/GradientMarker"; +uses "Entities/Effector"; + +%{ +struct DebrisInfo { + ULONG ulModelID; + ULONG ulTextureID; + FLOAT vOffset[3]; +}; + +static struct DebrisInfo _ObeliskDebrisInfo[] = +{ + { MODEL_OBELISK01, TEXTURE_OBELISK, 0.0f, 114.4989f, 0.0f}, + { MODEL_OBELISK02, TEXTURE_OBELISK, 0.035f, 106.8628f, 0.0f}, + { MODEL_OBELISK03, TEXTURE_OBELISK, 0.0f, 98.628f, 0.0f}, + { MODEL_OBELISK04, TEXTURE_OBELISK, 0.0f, 90.4996f, 0.0f}, + { MODEL_OBELISK05, TEXTURE_OBELISK, 0.0f, 82.174f, 0.0f}, + { MODEL_OBELISK06, TEXTURE_OBELISK, 0.0f, 71.0425f, 0.0f}, + { MODEL_OBELISK07, TEXTURE_OBELISK, 0.0f, 59.2f, 0.0f}, + { MODEL_OBELISK08, TEXTURE_OBELISK, 0.0f, 46.65f, 0.0f}, + { MODEL_OBELISK09, TEXTURE_OBELISK, 0.0f, 36.6f, 0.0f}, +}; + +static struct DebrisInfo _PylonDebrisInfo[] = +{ + { MODEL_PYLON01, TEXTURE_PYLON, -17.3379f, 55.92f, 0}, + { MODEL_PYLON02, TEXTURE_PYLON, -10.525f, 58.045f, 0}, + { MODEL_PYLON03, TEXTURE_PYLON, -17.66f, 42.32f, 0}, + { MODEL_PYLON04, TEXTURE_PYLON, -0.815000f, 54.69f, 0 }, + { MODEL_PYLON05, TEXTURE_PYLON, 14.795f, 51.65f, 0}, + { MODEL_PYLON06, TEXTURE_PYLON, 0.02f, 36.18f, 0}, + { MODEL_PYLON07, TEXTURE_PYLON, -10.289f, 33.982f, 0}, + { MODEL_PYLON08, TEXTURE_PYLON, -22.9152f, 28.6205f, 0}, + { MODEL_PYLON09, TEXTURE_PYLON, 21.932f, 47.2453f, 0}, +}; +%} + +class CDestroyableArchitecture: CMovableBrushEntity { +name "DestroyableArchitecture"; +thumbnail "Thumbnails\\DestroyableArchitecture.tbn"; +features "HasName", "IsTargetable"; +properties: + 1 CTString m_strName "Name" 'N' = "DestroyableArchitecture", // name + 2 FLOAT m_fHealth "Health" 'H' = -1.0f, // health + 3 enum EffectorEffectType m_etType "Type" 'Y' = ET_DESTROY_OBELISK, // name + 4 FLOAT3D m_vDamageDir = FLOAT3D(0,0,0), // direction of damage + 5 FLOAT m_fStretch "Stretch" 'S' = 1.0f, // debris stretch + 6 CEntityPointer m_penGradient "Gradient" 'R', + + 10 COLOR m_colDebrises "Color of debrises" = C_WHITE, + 11 INDEX m_ctDebrises "Debris count" = 12, + 12 FLOAT m_fCandyEffect "Debris blow power" = 0.0f, + 13 FLOAT m_fCubeFactor "Cube factor" = 1.0f, + 14 BOOL m_bBlowupByDamager "Blowup by Damager" = FALSE, // if only damager can destroy brush + +components: +// ************** DEBRIS PARTS ************** + 10 texture TEXTURE_OBELISK "Models\\CutSequences\\Obelisk\\Obelisk.tex", + 11 model MODEL_OBELISK01 "Models\\CutSequences\\Obelisk\\Part01.mdl", + 12 model MODEL_OBELISK02 "Models\\CutSequences\\Obelisk\\Part02.mdl", + 13 model MODEL_OBELISK03 "Models\\CutSequences\\Obelisk\\Part03.mdl", + 14 model MODEL_OBELISK04 "Models\\CutSequences\\Obelisk\\Part04.mdl", + 15 model MODEL_OBELISK05 "Models\\CutSequences\\Obelisk\\Part05.mdl", + 16 model MODEL_OBELISK06 "Models\\CutSequences\\Obelisk\\Part06.mdl", + 17 model MODEL_OBELISK07 "Models\\CutSequences\\Obelisk\\Part07.mdl", + 18 model MODEL_OBELISK08 "Models\\CutSequences\\Obelisk\\Part08.mdl", + 19 model MODEL_OBELISK09 "Models\\CutSequences\\Obelisk\\Part09.mdl", + + 20 texture TEXTURE_PYLON "Models\\CutSequences\\Pylon\\Pylon.tex", + 21 model MODEL_PYLON01 "Models\\CutSequences\\Pylon\\Part01.mdl", + 22 model MODEL_PYLON02 "Models\\CutSequences\\Pylon\\Part02.mdl", + 23 model MODEL_PYLON03 "Models\\CutSequences\\Pylon\\Part03.mdl", + 24 model MODEL_PYLON04 "Models\\CutSequences\\Pylon\\Part04.mdl", + 25 model MODEL_PYLON05 "Models\\CutSequences\\Pylon\\Part05.mdl", + 26 model MODEL_PYLON06 "Models\\CutSequences\\Pylon\\Part06.mdl", + 27 model MODEL_PYLON07 "Models\\CutSequences\\Pylon\\Part07.mdl", + 28 model MODEL_PYLON08 "Models\\CutSequences\\Pylon\\Part08.mdl", + 29 model MODEL_PYLON09 "Models\\CutSequences\\Pylon\\Part09.mdl", + +// ************** NEEDED CLASSES ************** + 30 class CLASS_DEBRIS "Classes\\Debris.ecl", + 31 class CLASS_EFFECTOR "Classes\\Effector.ecl", + +// ************** STONE PARTS ************** + 32 model MODEL_STONE "Models\\Effects\\Debris\\Stone\\Stone.mdl", + 33 texture TEXTURE_STONE "Models\\Effects\\Debris\\Stone\\Stone.tex", + +functions: + + void Precache(void) + { + PrecacheClass (CLASS_DEBRIS); + PrecacheModel (MODEL_STONE); + PrecacheTexture (TEXTURE_STONE); + + // precache acording to destroying architecture + switch( m_etType) + { + case ET_DESTROY_OBELISK: + PrecacheClass (CLASS_EFFECTOR,ET_DESTROY_OBELISK); + PrecacheTexture (TEXTURE_OBELISK); + PrecacheModel (MODEL_OBELISK01); + PrecacheModel (MODEL_OBELISK02); + PrecacheModel (MODEL_OBELISK03); + PrecacheModel (MODEL_OBELISK04); + PrecacheModel (MODEL_OBELISK05); + PrecacheModel (MODEL_OBELISK06); + PrecacheModel (MODEL_OBELISK07); + PrecacheModel (MODEL_OBELISK08); + PrecacheModel (MODEL_OBELISK09); + break; + case ET_DESTROY_PYLON: + PrecacheClass (CLASS_EFFECTOR,ET_DESTROY_PYLON); + PrecacheTexture (TEXTURE_PYLON); + PrecacheModel (MODEL_PYLON01); + PrecacheModel (MODEL_PYLON02); + PrecacheModel (MODEL_PYLON03); + PrecacheModel (MODEL_PYLON04); + PrecacheModel (MODEL_PYLON05); + PrecacheModel (MODEL_PYLON06); + PrecacheModel (MODEL_PYLON07); + PrecacheModel (MODEL_PYLON08); + PrecacheModel (MODEL_PYLON09); + break; + } + } + + // Validate offered target for one property + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if(penTarget==NULL) + { + return FALSE; + } + + // if gradient marker + if( slPropertyOffset==offsetof(CDestroyableArchitecture, m_penGradient) ) + { + return (IsDerivedFromClass(penTarget, "Gradient Marker")); + } + return CEntity::IsTargetValid(slPropertyOffset, penTarget); + } + + /* Get gradient type name, return empty string if not used. */ + const CTString &GetGradientName(INDEX iGradient) + { + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + if (iGradient==1) + { + CGradientMarker *pgm = (CGradientMarker *)&*m_penGradient; + if (pgm != NULL) { + return pgm->GetGradientName(); + } else { + return strMarkerUnused; + } + } + return strDummyName; + } + /* Uncache shadows for given gradient */ + void UncacheShadowsForGradient(class CGradientMarker *penDiscard) + { + CGradientMarker *pgm = (CGradientMarker *)&*m_penGradient; + if(pgm == penDiscard) + { + CEntity::UncacheShadowsForGradient(1); + } + } + + /* Get gradient, return FALSE for none. */ + BOOL GetGradient(INDEX iGradient, class CGradientParameters &fpGradient) + { + if ( iGradient==1) + { + CGradientMarker *pgm = (CGradientMarker *)&*m_penGradient; + if (pgm != NULL) { + return pgm->GetGradient(0, fpGradient); + } + } + return FALSE; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // if not destroyable + if(m_fHealth<0) { + // ignore damages + return; + } + + if(m_bBlowupByDamager) + { + if( dmtType == DMT_DAMAGER) + { + CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + } + else + { + // react only on explosions + if( (dmtType == DMT_EXPLOSION) || + (dmtType == DMT_PROJECTILE) || + (dmtType == DMT_CANNONBALL) ) + { + CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + } + } + + void DestroyObelisk() + { + for( INDEX iDebris=0; iDebrisCreateEntity_t( + CPlacement3D(vPos, ANGLE3D(0,0,0)), CTFILENAME("Classes\\Debris.ecl")); + // prepare parameters + ESpawnDebris eSpawn; + eSpawn.colDebris = C_WHITE|CT_OPAQUE; + eSpawn.Eeibt = EIBT_ROCK; + eSpawn.dptParticles = DPT_NONE; + eSpawn.betStain = BET_NONE; + eSpawn.pmd = GetModelDataForComponent(di.ulModelID); + eSpawn.ptd = GetTextureDataForComponent(di.ulTextureID); + eSpawn.ptdRefl = NULL; + eSpawn.ptdSpec = NULL; + eSpawn.ptdBump = NULL; + eSpawn.iModelAnim = 0; + eSpawn.fSize = m_fStretch; + // initialize it + penDebris->Initialize(eSpawn); + + // speed it up + FLOAT fHeightRatio = di.vOffset[1]*m_fStretch/120.0f; + FLOAT3D vSpeed = FLOAT3D( FRnd()-0.5f, 0.0f, FRnd()-0.5f)*(1.0f-fHeightRatio)*160.0f; + FLOAT3D vRot = FLOAT3D( FRnd()-0.5f, (FRnd()-0.5f)*(1.0f-fHeightRatio), FRnd()-0.5f)*200.0f; + /* + vSpeed = FLOAT3D( 0,0,0); + vRot = FLOAT3D( 0,0,0);*/ + ((CMovableEntity&)*penDebris).LaunchAsFreeProjectile( vSpeed, NULL); + ((CMovableEntity&)*penDebris).SetDesiredRotation( vRot); + } + + // notify children + FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) { + iten->SendEvent( EBrushDestroyed()); + } + m_fHealth = -1; + ForceFullStop(); + SetDefaultProperties(); + + CPlacement3D plObelisk = GetPlacement(); + + // notify engine to kickstart entities that are cached in stationary position, + // before we turn off, so they can fall + NotifyCollisionChanged(); + SetFlags( GetFlags()|ENF_HIDDEN); + SetCollisionFlags(ECF_IMMATERIAL); + + // spawn spray spray + CEntity *penEffector = CreateEntity( plObelisk, CLASS_EFFECTOR); + // set spawn parameters + ESpawnEffector eSpawnEffector; + eSpawnEffector.tmLifeTime = 6.0f; + eSpawnEffector.eetType = ET_DESTROY_OBELISK; + // initialize spray + penEffector->Initialize( eSpawnEffector); + } + + void DestroyPylon() + { + for( INDEX iDebris=0; iDebrisCreateEntity_t( + CPlacement3D(vPos, ANGLE3D(0,0,0)), CTFILENAME("Classes\\Debris.ecl")); + // prepare parameters + ESpawnDebris eSpawn; + eSpawn.colDebris = C_WHITE|CT_OPAQUE; + eSpawn.Eeibt = EIBT_ROCK; + eSpawn.dptParticles = DPT_NONE; + eSpawn.betStain = BET_NONE; + eSpawn.pmd = GetModelDataForComponent(di.ulModelID); + eSpawn.ptd = GetTextureDataForComponent(di.ulTextureID); + eSpawn.ptdRefl = NULL; + eSpawn.ptdSpec = NULL; + eSpawn.ptdBump = NULL; + eSpawn.iModelAnim = 0; + eSpawn.fSize = m_fStretch; + // initialize it + penDebris->Initialize(eSpawn); + + // speed it up + FLOAT fHeightRatio = di.vOffset[1]*m_fStretch/120.0f; + FLOAT3D vSpeed = (m_vDamageDir*2.0f+FLOAT3D( FRnd()-0.5f, 0.0f, FRnd()))*fHeightRatio*160.0f; + FLOAT3D vRot = FLOAT3D( FRnd()-0.5f, (FRnd()-0.5f)*fHeightRatio, FRnd()-0.5f)*300.0f; + ((CMovableEntity&)*penDebris).LaunchAsFreeProjectile( vSpeed, NULL); + ((CMovableEntity&)*penDebris).SetDesiredRotation( vRot); + } + + // notify children + FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) { + iten->SendEvent( EBrushDestroyed()); + } + m_fHealth = -1; + CPlacement3D plObelisk = GetPlacement(); + // spawn spray spray + CEntity *penEffector = CreateEntity( plObelisk, CLASS_EFFECTOR); + // set spawn parameters + ESpawnEffector eSpawnEffector; + eSpawnEffector.eetType = ET_DESTROY_PYLON; + eSpawnEffector.tmLifeTime = 6.0f; + eSpawnEffector.vDamageDir = m_vDamageDir; + // initialize spray + penEffector->Initialize( eSpawnEffector); + + ForceFullStop(); + SetDefaultProperties(); + // notify engine to kickstart entities that are cached in stationary position, + // before we turn off, so they can fall + NotifyCollisionChanged(); + SetFlags( GetFlags()|ENF_HIDDEN); + SetCollisionFlags(ECF_IMMATERIAL); + } +procedures: + + Main() { + // declare yourself as a brush + InitAsBrush(); + SetPhysicsFlags(EPF_BRUSH_MOVING); + SetCollisionFlags(ECF_BRUSH); + // non-zoning brush + SetFlags(GetFlags()&~ENF_ZONING); + SetHealth(m_fHealth); + + // start moving + wait() { + on (EBegin) : { + resume; + } + on (EBrushDestroyedByDevil ebdbd) : + { + m_vDamageDir = ebdbd.vDamageDir; + switch( m_etType) + { + case ET_DESTROY_OBELISK: + DestroyObelisk(); + break; + case ET_DESTROY_PYLON: + DestroyPylon(); + break; + } + stop; + } + on (EDeath eDeath) : { + // get your size + FLOATaabbox3D box; + GetSize(box); + if( m_ctDebrises<=0) + { + m_ctDebrises=1; + } + FLOAT fEntitySize = pow(box.Size()(1)*box.Size()(2)*box.Size()(3)/m_ctDebrises, 1.0f/3.0f)*m_fCubeFactor; + + Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(1.0f,2.0f,3.0f), + FLOAT3D(0,0,0), 1.0f+m_fCandyEffect/2.0f, m_fCandyEffect, m_colDebrises); + for(INDEX iDebris = 0; iDebrisSendEvent( EBrushDestroyed()); + } + + m_fHealth = -1; + ForceFullStop(); + SetDefaultProperties(); + // notify engine to kickstart entities that are cached in stationary position, + // before we turn off, so they can fall + NotifyCollisionChanged(); + SetFlags( GetFlags()|ENF_HIDDEN); + SetCollisionFlags(ECF_IMMATERIAL); + + // for each child of this entity + {FOREACHINLIST(CEntity, en_lnInParent, en_lhChildren, itenChild) { + // send it destruction event + itenChild->SendEvent(ERangeModelDestruction()); + }} + + stop; + } + on (EReturn) : + { + stop; + } + } + return; + } +}; diff --git a/Sources/Entities/Devil.es b/Sources/Entities/Devil.es new file mode 100644 index 0000000..90ce666 --- /dev/null +++ b/Sources/Entities/Devil.es @@ -0,0 +1,2415 @@ +332 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Devil/Devil.h" +#include "Models/Enemies/Devil/Weapons/Laser.h" +#include "Models/Weapons/RocketLauncher/RocketLauncherItem.h" +#include "Entities/Effector.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/PyramidSpaceShip.h" +#include "Entities/BackgroundViewer.h" + +#define DEVIL_LASER_SPEED 100.0f +#define DEVIL_ROCKET_SPEED 60.0f +%} + +uses "Entities/DevilMarker"; +uses "Entities/EnemyBase"; +uses "Entities/Projectile"; +uses "Entities/Bullet"; + +event EBrushDestroyedByDevil { + FLOAT3D vDamageDir, +}; + +event ERegenerationImpuls { +}; + +enum DevilCommandType { + 0 DC_GRAB_LOWER_WEAPONS "Grab lower weapons", + 1 DC_FORCE_ACTION "Force next action", + 2 DC_STOP_MOVING "Stop moving", + 3 DC_STOP_ATTACK "Stop attacking", + 4 DC_JUMP_INTO_PYRAMID "Jump into pyramid", + 5 DC_FORCE_ATTACK_RADIUS "Force attack radius", + 6 DC_DECREASE_ATTACK_RADIUS "Decrease attack radius", + 7 DC_TELEPORT_INTO_PYRAMID "Teleport into pyramid", +}; + +event EDevilCommand { + enum DevilCommandType dctType, + CEntityPointer penForcedAction, + FLOAT fAttackRadius, + FLOAT3D vCenterOfAttack, +}; + +enum DevilState { + 0 DS_NOT_EXISTING "Not existing", // idle + 1 DS_DESTROYING_CITY "Destroying city", // process of destroying city + 2 DS_ENEMY "Enemy", // behave as normal enemy + 3 DS_JUMPING_INTO_PYRAMID "Jumping into pyramid", // jumping into pyramid + 4 DS_PYRAMID_FIGHT "Pyramid fight", // pyramid fight + 5 DS_REGENERATION_IMPULSE "Regenerating with impulse", // drinking power +}; + +enum DevilAttackPower { + 1 DAP_PLAYER_HUNT "Player hunt", // process of hunting player + 2 DAP_LOW_POWER_ATTACK "Low power attack", // low power attack + 3 DAP_MEDIUM_POWER_ATTACK "Medium power attack", // medium power attack + 4 DAP_FULL_POWER_ATTACK "Full power attack", // full power attack + 5 DAP_NOT_ATTACKING "Not attacking", // not attacking +}; + +%{ +static FLOAT3D vLastStartPosition; +static FLOAT vLastAttackRadius; + +extern INDEX cht_bKillFinalBoss; +extern INDEX cht_bDebugFinalBoss; +extern INDEX cht_bDumpFinalBossData; +extern INDEX cht_bDebugFinalBossAnimations; + +#define LIGHT_ANIM_FIRE 3 +#define LIGHT_ANIM_NONE 5 + +// parameters defining boss +#define SIZE 50.0f +#define DEVIL_HOOF_RADIUS 0.25f*SIZE +#define DEVIL_HIT_HOOF_OFFSET FLOAT3D(-0.149021f, 0.084463f, -0.294425f)*SIZE +#define DEVIL_WALK_HOOF_RIGHT_OFFSET FLOAT3D(0.374725f, 0.0776713f, 0.0754253f)*SIZE +#define DEVIL_WALK_HOOF_LEFT_OFFSET FLOAT3D(-0.402306f, 0.0864595f, 0.292397f)*SIZE + +#define ATT_PROJECTILE_GUN (FLOAT3D(-0.703544f, 1.12582f, -0.329834f)*SIZE) +#define ATT_LASER (FLOAT3D(0.63626f, 1.13841f, -0.033062f)*SIZE) +#define ATT_ELECTRICITYGUN (FLOAT3D(-0.764868f, 1.27992f, -0.311084f)*SIZE) +#define ATT_ROCKETLAUNCHER (FLOAT3D(0.654788f, 1.30318f, -0.259358f)*SIZE) +#define MAGIC_PROJECTILE_EXIT (FLOAT3D(0.035866f, 1.400f, -0.792264f)*SIZE) + +#define ELECTROGUN_PIPE (FLOAT3D(-0.00423616f, -0.0216781f, -0.506613f)*SIZE) +#define LASER_PIPE (FLOAT3D(0.0172566f, -0.123152f, -0.232228f)*SIZE) + +#define PROJECTILEGUN_PIPE (FLOAT3D(0.0359023f, -0.000490744f, -0.394403f)*SIZE) +#define ROCKETLAUNCHER_PIPE (FLOAT3D(4.68194e-005f, 0.0483391f, -0.475134f)*SIZE) + +#define HEALTH_MULTIPLIER 1.0f +#define BOSS_HEALTH (40000.0f*HEALTH_MULTIPLIER) +#define HEALTH_IMPULSE (10000.0f*HEALTH_MULTIPLIER) +#define HEALTH_CLASS_1 (5000*HEALTH_MULTIPLIER) +#define HEALTH_CLASS_2 (7500*HEALTH_MULTIPLIER) +#define HEALTH_CLASS_3 (10000*HEALTH_MULTIPLIER) +#define HEALTH_CLASS_4 (15000*HEALTH_MULTIPLIER) +#define CLASS_2_CANNON_FACTOR 0.75f +#define CLASS_3_ROCKETLAUNCHER_FACTOR 0.75f +#define CLASS_4_ROCKETLAUNCHER_FACTOR 0.25f +#define TM_HEALTH_IMPULSE 4.0f + +// info structure +static EntityInfo eiDevil = { + EIBT_FLESH, 50000.0f, + 0.0f, 2.0f*SIZE, 0.0f, + 0.0f, 1.4f*SIZE, 0.0f, +}; + +%} + +class CDevil : CEnemyBase { +name "Devil"; +thumbnail "Thumbnails\\Devil.tbn"; + +properties: + 1 INDEX m_iAttID = 0, // internal temp var + 2 FLOAT m_fDeltaWeaponPitch = 0.0f, // for adjusting weapon pitch + 3 FLOAT m_fDeltaWeaponHdg = 0.0f, // for adjusting weapon hdg + 4 FLOAT m_fFireTime = 0.0f, // time to fire bullets + 5 CAnimObject m_aoLightAnimation, // light animation object + 6 CEntityPointer m_penAction "Action" 'O', // ptr to action marker entity + 8 INDEX m_iFiredProjectiles = 0, // internal counter of fired projectiles + 9 INDEX m_iToFireProjectiles = 0, // internal counter of projectiles that should be fired + 10 FLOAT m_fPauseStretcher = 0, // stretch factor for pauses between fireing + 11 FLOAT m_tmLastPause = 0.0f, // last pause between two fireings + 12 enum DevilState m_dsDevilState = DS_NOT_EXISTING,// current devil state + 13 FLOAT m_tmLastAngry = -1.0f, // last angry state + 14 CPlacement3D m_plTeleport = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)), + 16 FLOAT m_tmTemp = 0, + 17 enum DevilState m_dsLastDevilState = DS_REGENERATION_IMPULSE,// last devil state + 18 enum DevilAttackPower m_dapAttackPower = DAP_PLAYER_HUNT,// current devil state + 19 enum DevilAttackPower m_dapLastAttackPower = DAP_NOT_ATTACKING, + 20 BOOL m_bHasUpperWeapons = FALSE, + 21 FLOAT3D m_vElectricitySource = FLOAT3D( 0,0,0), // position of electricity ray target + 22 FLOAT3D m_vElectricityTarget = FLOAT3D( 0,0,0), // position of electricity ray target + 23 BOOL m_bRenderElectricity = FALSE, // if electricity particles are rendered + 24 FLOAT m_fAdjustWeaponTime = 0.0f, // time for weapon to lock enemy + 25 BOOL m_bWasOnceInMainLoop = FALSE, // if MainLoop was called at least once + 26 FLOAT m_tmHitBySpaceShipBeam = -1, // last time when was hit by space ship beam + 27 CSoundObject m_soLeft, // left foot sound + 28 CSoundObject m_soRight, // right foot sound + 29 FLOAT m_fLastWalkTime = -1.0f, // last walk time + 30 FLOAT m_tmFireBreathStart = UpperLimit(0.0f), // time when fire breath started + 31 FLOAT m_tmFireBreathStop = 0.0f, // time when fire breath stopped + 32 FLOAT3D m_vFireBreathSource = FLOAT3D( 0,0,0), // position of fire breath source + 33 FLOAT3D m_vFireBreathTarget = FLOAT3D( 0,0,0), // position of fire breath target + 34 FLOAT m_tmRegenerationStart = UpperLimit(0.0f), // time when regeneration started + 35 FLOAT m_tmRegenerationStop = 0.0f, // time when regeneration stopped + 36 FLOAT m_tmNextFXTime = 0.0f, // next effect time + + 37 INDEX m_iNextChannel = 0, // next channel to play sound on + // weapon sound channels + 38 CSoundObject m_soWeapon0, + 39 CSoundObject m_soWeapon1, + 40 CSoundObject m_soWeapon2, + 41 CSoundObject m_soWeapon3, + 42 CSoundObject m_soWeapon4, + + 43 INDEX m_iAngryAnim=0, // random angry animation + 44 INDEX m_iAngrySound=0, // random angry animation + 45 FLOAT m_tmDeathTime = -1.0f, // time of death + + 50 INDEX m_iLastCurrentAnim = -1, + 51 INDEX m_iLastScheduledAnim = -1, + + 52 enum DevilState m_dsPreRegenerationDevilState = DS_ENEMY, + 60 CSoundObject m_soClimb, // sound of climbing + 61 CSoundObject m_soGrabLowerWeapons, + 62 CSoundObject m_soGrabUpperWeapons, + 63 CSoundObject m_soJumpIntoPyramid, + +{ + CEntity *penBullet; // bullet + CLightSource m_lsLightSource; +} + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + 2 class CLASS_EFFECTOR "Classes\\Effector.ecl", + +// ************** DEVIL ************** + 10 model MODEL_DEVIL "Models\\Enemies\\Devil\\Devil.mdl", + 11 texture TEXTURE_DEVIL "Models\\Enemies\\Devil\\Devil.tex", + +// ************** LASER ************** + 20 model MODEL_LASER "Models\\Enemies\\Devil\\Weapons\\Laser.mdl", + 21 texture TEXTURE_LASER "Models\\Enemies\\Devil\\Weapons\\Laser.tex", + +// ************** ROCKET LAUNCHER ************** + 22 model MODEL_ROCKETLAUNCHER "Models\\Enemies\\Devil\\Weapons\\RocketLauncher.mdl", + 23 texture TEXTURE_ROCKETLAUNCHER "Models\\Enemies\\Devil\\Weapons\\RocketLauncher.tex", + +// ************** PROJECTILE GUN ************** + 24 model MODEL_PROJECTILEGUN "Models\\Enemies\\Devil\\Weapons\\ProjectileGun.mdl", + 25 texture TEXTURE_PROJECTILEGUN "Models\\Enemies\\Devil\\Weapons\\ProjectileGun.tex", + +// ************** ELECTRICITY GUN ************* + 26 model MODEL_ELECTRICITYGUN "Models\\Enemies\\Devil\\Weapons\\ElectricityGun.mdl", + 27 texture TEXTURE_ELECTRICITYGUN "Models\\Enemies\\Devil\\Weapons\\ElectricityGun.tex", + +// ************** SOUNDS ************** + 60 sound SOUND_ANGER01 "Models\\Enemies\\Devil\\Sounds\\Anger01.wav", + 61 sound SOUND_ANGER02 "Models\\Enemies\\Devil\\Sounds\\Anger02.wav", + 62 sound SOUND_ATTACKCLOSE "Models\\Enemies\\Devil\\Sounds\\AttackClose.wav", + 63 sound SOUND_CELEBRATE01 "Models\\Enemies\\Devil\\Sounds\\Celebrate01.wav", + 65 sound SOUND_DEATH "Models\\Enemies\\Devil\\Sounds\\Death.wav", + 66 sound SOUND_DRAW_LOWER_WEAPONS "Models\\Enemies\\Devil\\Sounds\\GrabWeaponsLower.wav", + 67 sound SOUND_DRAW_UPPER_WEAPONS "Models\\Enemies\\Devil\\Sounds\\GrabWeaponsUpper.wav", + 68 sound SOUND_GETUP "Models\\Enemies\\Devil\\Sounds\\Getup.wav", + 69 sound SOUND_IDLE "Models\\Enemies\\Devil\\Sounds\\Idle.wav", + 70 sound SOUND_PUNCH "Models\\Enemies\\Devil\\Sounds\\Punch.wav", + 71 sound SOUND_SMASH "Models\\Enemies\\Devil\\Sounds\\Smash.wav", + 72 sound SOUND_WALK_LEFT "Models\\Enemies\\Devil\\Sounds\\WalkL.wav", + 73 sound SOUND_WALK_RIGHT "Models\\Enemies\\Devil\\Sounds\\WalkR.wav", + 74 sound SOUND_WOUND "Models\\Enemies\\Devil\\Sounds\\Wound.wav", + 75 sound SOUND_ATTACK_BREATH_START "Models\\Enemies\\Devil\\Sounds\\AttackBreathStart.wav", + 76 sound SOUND_ATTACK_BREATH_FIRE "Models\\Enemies\\Devil\\Sounds\\BreathProjectile.wav", + 77 sound SOUND_ATTACK_BREATH_END "Models\\Enemies\\Devil\\Sounds\\AttackBreathEnd.wav", + 78 sound SOUND_HEAL "Models\\Enemies\\Devil\\Sounds\\Heal.wav", + 79 sound SOUND_ROCKETLAUNCHER "Models\\Enemies\\Devil\\Sounds\\RocketLauncher.wav", + 80 sound SOUND_LASER "Models\\Enemies\\Devil\\Sounds\\Laser.wav", + 81 sound SOUND_LAVABOMB "Models\\Enemies\\Devil\\Sounds\\LavaBomb.wav", + 82 sound SOUND_GHOSTBUSTER "Models\\Enemies\\Devil\\Sounds\\Ghostbuster.wav", + 83 sound SOUND_ATTACK_BREATH_LOOP "Models\\Enemies\\Devil\\Sounds\\AttackBreath.wav", + 84 sound SOUND_CLIMB "Models\\Enemies\\Devil\\Sounds\\Enter.wav", + 85 sound SOUND_DEATHPARTICLES "Models\\Enemies\\Devil\\Sounds\\DeathParticles.wav", + 86 sound SOUND_DISAPPEAR "Models\\Enemies\\Devil\\Sounds\\Disappear.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("Ugh Zan killed %s"),(const char*) strPlayerName); + return str; + } + + void Precache(void) { + CEnemyBase::Precache(); +// ************** DEVIL ************** + PrecacheModel (MODEL_DEVIL ); + PrecacheTexture (TEXTURE_DEVIL ); + +// ************** LASER ************** + PrecacheModel (MODEL_LASER ); + PrecacheTexture (TEXTURE_LASER ); + +// ************** ROCKET LAUNCHER ************** + PrecacheModel (MODEL_ROCKETLAUNCHER ); + PrecacheTexture (TEXTURE_ROCKETLAUNCHER ); + +// ************** ELECTRICITY GUN ************** + PrecacheModel (MODEL_ELECTRICITYGUN); + PrecacheTexture (TEXTURE_ELECTRICITYGUN); + +// ************** PROJECTILE GUN ************** + PrecacheModel (MODEL_PROJECTILEGUN); + PrecacheTexture (TEXTURE_PROJECTILEGUN); + +// ************** PREDICTED PROJECTILE ************** + PrecacheClass(CLASS_PROJECTILE, PRT_LAVAMAN_BIG_BOMB); + PrecacheClass(CLASS_PROJECTILE, PRT_DEVIL_GUIDED_PROJECTILE); + PrecacheClass(CLASS_PROJECTILE, PRT_DEVIL_LASER); + PrecacheClass(CLASS_PROJECTILE, PRT_DEVIL_ROCKET); + +// ************** SOUNDS ************** + PrecacheSound (SOUND_ANGER01 ); + PrecacheSound (SOUND_ANGER02 ); + PrecacheSound (SOUND_ATTACKCLOSE ); + PrecacheSound (SOUND_CELEBRATE01 ); + PrecacheSound (SOUND_DEATH ); + PrecacheSound (SOUND_DRAW_LOWER_WEAPONS ); + PrecacheSound (SOUND_DRAW_UPPER_WEAPONS ); + PrecacheSound (SOUND_GETUP ); + PrecacheSound (SOUND_IDLE ); + PrecacheSound (SOUND_PUNCH ); + PrecacheSound (SOUND_SMASH ); + PrecacheSound (SOUND_WALK_LEFT ); + PrecacheSound (SOUND_WALK_RIGHT ); + PrecacheSound (SOUND_WOUND ); + PrecacheSound (SOUND_ATTACK_BREATH_START ); + PrecacheSound (SOUND_ATTACK_BREATH_FIRE ); + PrecacheSound (SOUND_ATTACK_BREATH_END ); + PrecacheSound (SOUND_HEAL ); + PrecacheSound (SOUND_ROCKETLAUNCHER ); + PrecacheSound (SOUND_LASER ); + PrecacheSound (SOUND_LAVABOMB ); + PrecacheSound (SOUND_GHOSTBUSTER ); + PrecacheSound (SOUND_ATTACK_BREATH_LOOP ); + PrecacheSound (SOUND_CLIMB ); + PrecacheSound (SOUND_DEATHPARTICLES ); + PrecacheSound (SOUND_DISAPPEAR ); + } + + // Validate offered target for one property + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if(penTarget==NULL) + { + return FALSE; + } + return (IsDerivedFromClass(penTarget, "Devil Marker")); + } + + /* Read from stream. */ + void Read_t( CTStream *istr) { // throw char * + CEnemyBase::Read_t(istr); + + // setup light source + SetupLightSource(); + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + // Setup light source + void SetupLightSource(void) { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 2.0f; + lsNew.ls_rFallOff = 8.0f; + lsNew.ls_colColor = RGBToColor(128, 128, 128); + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = &m_aoLightAnimation; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + // play light animation + void PlayLightAnim(INDEX iAnim, ULONG ulFlags) { + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(iAnim, ulFlags); + } + }; + + + /* Entity info */ + void *GetEntityInfo(void) { + return &eiDevil; + }; + + BOOL ForcesCannonballToExplode(void) + { + return TRUE; + } + + void SetSpeedsToDesiredPosition(const FLOAT3D &vPosDelta, FLOAT fPosDist, BOOL bGoingToPlayer) + { + if(m_penEnemy!=NULL) + { + FLOAT fEnemyDistance = CalcDist(m_penEnemy); + FLOAT fRadius1 = 75.0f; + FLOAT fRadius2 = 200.0f; + FLOAT fSpeedRadius1 = 6.0f; + FLOAT fSpeedRadius2 = 14.0f; + + FLOAT fDistanceRatio = CalculateRatio( fEnemyDistance, fRadius1, fRadius2, 1, 0); + if( fEnemyDistance>=fRadius2) + { + fDistanceRatio = 1.0f; + } + m_fAttackRunSpeed = fSpeedRadius1+fDistanceRatio*(fSpeedRadius2-fSpeedRadius1); + m_fCloseRunSpeed = m_fAttackRunSpeed; + if( cht_bDebugFinalBoss) + { + CPrintF( "Enm dist:%g, Speed=%g\n", fEnemyDistance, m_fAttackRunSpeed); + } + } + CEnemyBase::SetSpeedsToDesiredPosition(vPosDelta, fPosDist, bGoingToPlayer); + } + + FLOAT GetCrushHealth(void) + { + return 1000.0f; + } + + void SelectRandomAnger(void) + { + if( IRnd()%2) { + m_iAngryAnim = DEVIL_ANIM_ANGER01; + m_iAngrySound = SOUND_ANGER01; + } else { + m_iAngryAnim = DEVIL_ANIM_ANGER02; + m_iAngrySound = SOUND_ANGER02; + } + } + + virtual FLOAT GetLockRotationSpeed(void) + { + return m_aAttackRotateSpeed*4; + }; + + class CWorldSettingsController *GetWSC(void) + { + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + return pwsc; + } + + void ShakeItBaby(FLOAT tmShaketime, FLOAT fPower) + { + CWorldSettingsController *pwsc = GetWSC(); + if (pwsc!=NULL) { + pwsc->m_tmShakeStarted = tmShaketime; + pwsc->m_vShakePos = GetPlacement().pl_PositionVector; + pwsc->m_fShakeFalloff = 400.0f; + pwsc->m_fShakeFade = 3.0f; + + pwsc->m_fShakeIntensityZ = 0.0f; + pwsc->m_tmShakeFrequencyZ = 5.0f; + pwsc->m_fShakeIntensityY = 0.1f*fPower; + pwsc->m_tmShakeFrequencyY = 5.0f; + pwsc->m_fShakeIntensityB = 2.5f*fPower; + pwsc->m_tmShakeFrequencyB = 7.2f; + } + } + + void ShakeItFarBaby(FLOAT tmShaketime, FLOAT fPower) + { + CWorldSettingsController *pwsc = GetWSC(); + if (pwsc!=NULL) { + pwsc->m_tmShakeStarted = tmShaketime; + pwsc->m_vShakePos = GetPlacement().pl_PositionVector; + pwsc->m_fShakeFalloff = 2048.0f; + pwsc->m_fShakeFade = 2.0f; + + pwsc->m_fShakeIntensityZ = 0.0f; + pwsc->m_tmShakeFrequencyZ = 5.0f; + pwsc->m_fShakeIntensityY = 0.1f*fPower; + pwsc->m_tmShakeFrequencyY = 5.0f; + pwsc->m_fShakeIntensityB = 2.5f*fPower; + pwsc->m_tmShakeFrequencyB = 7.2f; + } + } + + void InflictHoofDamage( FLOAT3D vOffset) + { + // apply range damage for right foot + FLOAT3D vFootRel = vOffset; + FLOAT3D vFootAbs = vFootRel*GetRotationMatrix()+GetPlacement().pl_PositionVector; + InflictRangeDamage(this, DMT_IMPACT, 1000.0f, vFootAbs, DEVIL_HOOF_RADIUS, DEVIL_HOOF_RADIUS); + } + + void ApplyFootQuake(void) + { + CModelObject &mo = *GetModelObject(); + TIME tmNow = _pTimer->CurrentTick(); + FLOAT tmAnim = -1; + FLOAT tmWalkLen = mo.GetAnimLength(DEVIL_ANIM_WALK); + FLOAT tmLeftFootOffset = 0.4f; + FLOAT tmRightFootOffset = 2.05f; + + // if we are now playing walk anim, but another anim is scheduled to happen after walk + if (mo.ao_iLastAnim==DEVIL_ANIM_WALK && mo.ao_tmAnimStart>tmNow) + { + // we started one anim time back from anim start time + tmAnim = mo.ao_tmAnimStart-tmWalkLen; + } + else if (mo.ao_iCurrentAnim==DEVIL_ANIM_WALK && mo.ao_tmAnimStart<=tmNow) + { + tmAnim = mo.ao_tmAnimStart; + } + // if we are now playing walk wo idle anim, but another anim is scheduled to happen after walk to idle + else if (mo.ao_iLastAnim==DEVIL_ANIM_FROMWALKTOIDLE && mo.ao_tmAnimStart>tmNow) + { + // we started one anim time back from anim start time + tmAnim = mo.ao_tmAnimStart-tmWalkLen; + tmLeftFootOffset = 0.6f; + tmRightFootOffset = 1.7f; + } + else if (mo.ao_iCurrentAnim==DEVIL_ANIM_FROMWALKTOIDLE && mo.ao_tmAnimStart<=tmNow) + { + tmAnim = mo.ao_tmAnimStart; + tmLeftFootOffset = 0.6f; + tmRightFootOffset = 1.7f; + } + + // WARNING !!! foot variable names are switched + if( tmAnim!=-1) + { + FLOAT tmAnimLast = tmAnim+INDEX((tmNow-tmAnim)/tmWalkLen)*tmWalkLen; + FLOAT tmLeftFootDown = tmAnimLast+tmLeftFootOffset; + FLOAT tmRightFootDown = tmAnimLast+tmRightFootOffset; + CWorldSettingsController *pwsc = GetWSC(); + if( pwsc!=NULL) + { + if( tmNow>=tmRightFootDown && pwsc->m_tmShakeStarted=tmLeftFootDown && pwsc->m_tmShakeStartedCurrentTick(); + } + + void StopRegenerationParticles(void) + { + m_tmRegenerationStop = _pTimer->CurrentTick(); + } + + void TurnOnPhysics(void) + { + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + } + + void TurnOffPhysics(void) + { + SetPhysicsFlags(EPF_MODEL_WALKING&~EPF_TRANSLATEDBYGRAVITY); + SetCollisionFlags(((ECBI_MODEL)<CurrentTick()>m_tmFireBreathStart) + { + // render fire breath particles + INDEX ctRendered = Particles_FireBreath(this, m_vFireBreathSource, m_vFireBreathTarget, + m_tmFireBreathStart, m_tmFireBreathStop); + // if should stop rendering fire breath particles + if( _pTimer->CurrentTick()>m_tmFireBreathStop && ctRendered==0) + { + m_tmFireBreathStart = UpperLimit(0.0f); + } + } + + // regeneration particles + if( _pTimer->CurrentTick()>m_tmRegenerationStart) + { + // render fire breath particles + INDEX ctRendered = Particles_Regeneration(this, m_tmRegenerationStart, m_tmRegenerationStop, 1.0f, FALSE); + // if should stop rendering regeneration particles + if( _pTimer->CurrentTick()>m_tmRegenerationStop && ctRendered==0) + { + m_tmRegenerationStart = UpperLimit(0.0f); + } + } + + // if is dead + if( m_tmDeathTime != -1.0f && _pTimer->CurrentTick()>m_tmDeathTime && _pTimer->CurrentTick()GetAttachmentModel(m_iAttID); + FLOAT3D vAttachment = FLOAT3D(0,0,0); + switch(m_iAttID) + { + case DEVIL_ATTACHMENT_LASER: + vAttachment = ATT_LASER; + break; + case DEVIL_ATTACHMENT_PROJECTILEGUN: + vAttachment = ATT_PROJECTILE_GUN; + break; + case DEVIL_ATTACHMENT_ELETRICITYGUN: + vAttachment = ATT_ELECTRICITYGUN; + break; + case DEVIL_ATTACHMENT_ROCKETLAUNCHER: + vAttachment = ATT_ROCKETLAUNCHER; + break; + default: + ASSERTALWAYS("Invalid attachment ID"); + } + return(vAttachment); + } + + FLOAT3D GetWeaponPositionAbsolute(void) + { + return GetPlacement().pl_PositionVector + GetWeaponPositionRelative()*GetRotationMatrix(); + } + + FLOAT3D GetFireingPositionRelative(void) + { + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(m_iAttID); + FLOAT3D vWeaponPipe = FLOAT3D(0,0,0); + FLOAT3D vAttachment = FLOAT3D(0,0,0); + switch(m_iAttID) + { + case DEVIL_ATTACHMENT_LASER: + vWeaponPipe = LASER_PIPE; + vAttachment = ATT_LASER; + break; + case DEVIL_ATTACHMENT_PROJECTILEGUN: + vWeaponPipe = PROJECTILEGUN_PIPE; + vAttachment = ATT_PROJECTILE_GUN; + break; + case DEVIL_ATTACHMENT_ELETRICITYGUN: + vWeaponPipe = ELECTROGUN_PIPE; + vAttachment = ATT_ELECTRICITYGUN; + break; + case DEVIL_ATTACHMENT_ROCKETLAUNCHER: + vWeaponPipe = ROCKETLAUNCHER_PIPE; + vAttachment = ATT_ROCKETLAUNCHER; + break; + default: + ASSERTALWAYS("Invalid attachment ID"); + } + + // create matrix + FLOATmatrix3D mWpn; + MakeRotationMatrixFast(mWpn, amo.amo_plRelative.pl_OrientationAngle); + return (vAttachment+vWeaponPipe*mWpn); + } + + FLOAT3D GetFireingPositionAbsolute(void) + { + return GetPlacement().pl_PositionVector + GetFireingPositionRelative()*GetRotationMatrix(); + } + + /* + Regeneration legend: + -------------------- + - if less than 0 -> no generation + - class 1 -> invoke impulse regeneration +HEALTH_IMPULSE + - class 2 -> drops when constantly hitted with cannonballs + - class 3 -> drops when constantly hitted with rockets + - class 4 -> drops when constantly hitted with rockets + - if greater than class 5 -> no regeneration + */ + void ApplyTickRegeneration(void) + { + if( cht_bKillFinalBoss && GetSP()->sp_bSinglePlayer) + { + cht_bKillFinalBoss=FALSE; + SetHealth(-1); + return; + } + // if currently regenerating or died or out of healing range or recently hit by space ship beam + if(m_dsDevilState == DS_REGENERATION_IMPULSE || + GetHealth()<=0 || GetHealth()>=HEALTH_CLASS_4 || + _pTimer->CurrentTick()TickQuantum; + FLOAT fDmgCannonsPerTick = 2959.0f/10.0f*_pTimer->TickQuantum; + FLOAT fRegeneration = 0.0f; + + if(GetHealth()CurrentTick(); + CModelObject &mo = *GetModelObject(); + // obtain current and scheduled animation + INDEX iCurrentAnim, iScheduledAnim; + if (mo.ao_tmAnimStart>tmNow) + { + iCurrentAnim = mo.ao_iLastAnim; + iScheduledAnim = mo.ao_iCurrentAnim; + } + else + { + iCurrentAnim = mo.ao_iCurrentAnim; + iScheduledAnim = -1; + } + + if( iCurrentAnim!=m_iLastCurrentAnim || iScheduledAnim!=m_iLastScheduledAnim) + { + CAnimData *pad = mo.GetData(); + CAnimInfo aiCurrent; + mo.GetAnimInfo(iCurrentAnim, aiCurrent); + CTString strCurrentAnimName = aiCurrent.ai_AnimName; + + CTString strScheduledAnimName = "....."; + if(iScheduledAnim != -1) + { + CAnimInfo aiScheduled; + mo.GetAnimInfo(iScheduledAnim, aiScheduled); + strScheduledAnimName = aiScheduled.ai_AnimName; + } + CPrintF("Time: %-10g %20s, %s\n", + _pTimer->GetLerpedCurrentTick(),(const char*) strCurrentAnimName,(const char*) strScheduledAnimName); + } + m_iLastCurrentAnim = iCurrentAnim; + m_iLastScheduledAnim = iScheduledAnim; + } + + if( cht_bDumpFinalBossData) + { + cht_bDumpFinalBossData=FALSE; + // dump devil data to console + CPrintF("\n\n\n\n\n\n\n"); + CPrintF("Devil class data ...................\n"); + CPrintF("\n\n"); + + CTString strAttackPower = DevilAttackPower_enum.NameForValue(INDEX(m_dapAttackPower)); + CPrintF( "Attack power: %s\n",(const char*) strAttackPower); + CTString strDevilState = DevilState_enum.NameForValue(INDEX(m_dsDevilState)); + CPrintF( "Devil state: %s\n",(const char*) strDevilState); + + CPrintF("m_fFireTime = %g\n", m_fFireTime); + CPrintF("m_iFiredProjectiles = %d\n", m_iFiredProjectiles); + CPrintF("m_iToFireProjectiles = %d\n", m_iToFireProjectiles); + CPrintF("m_tmLastPause = %g\n", m_tmLastPause); + CPrintF("m_fPauseStretcher = %g\n", m_fPauseStretcher); + CPrintF("m_tmLastAngry = %g\n", m_tmLastAngry); + CPrintF("m_bHasUpperWeapons = %d\n", m_bHasUpperWeapons); + CPrintF("m_fAdjustWeaponTime = %g\n", m_fAdjustWeaponTime); + CPrintF("m_bWasOnceInMainLoop = %d\n", m_bWasOnceInMainLoop); + CPrintF("m_tmHitBySpaceShipBeam = %g\n", m_tmHitBySpaceShipBeam); + CPrintF("m_fLastWalkTime = %g\n", m_fLastWalkTime); + CPrintF("m_tmFireBreathStart = %g\n", m_tmFireBreathStart); + CPrintF("m_tmFireBreathStop = %g\n", m_tmFireBreathStop); + CPrintF("m_tmRegenerationStart = %g\n", m_tmRegenerationStart); + CPrintF("m_tmRegenerationStop = %g\n", m_tmRegenerationStop); + CPrintF("m_tmNextFXTime = %g\n", m_tmNextFXTime); + CPrintF("m_tmDeathTime = %g\n", m_tmDeathTime); + CPrintF("Health = %g\n", GetHealth()); + + CPrintF("\n\n\n\n\n\n\n"); + CPrintF("Enemy base data ...................\n"); + CPrintF("\n\n"); + + CPrintF( "m_ttTarget (type): %d\n", INDEX(m_ttTarget)); + + CPrintF( "m_penWatcher %x\n",(const char*) m_penWatcher->GetName()); + CTString strEnemyName = "Null ptr, no name"; + if( m_penEnemy != NULL) + { + strEnemyName = m_penEnemy->GetName(); + } + CPrintF( "m_penEnemy %x, enemy name: %s\n",(const char*) (m_penEnemy->GetName()),(const char*) strEnemyName); + + CPrintF( "m_vStartPosition (%g, %g, %g)\n", m_vStartPosition(1), m_vStartPosition(2), m_vStartPosition(3)); + CPrintF( "m_vStartDirection (%g, %g, %g)\n", m_vStartDirection(1), m_vStartDirection(2), m_vStartDirection(3)); + CPrintF( "m_bOnStartPosition = %d\n", m_bOnStartPosition); + CPrintF( "m_fFallHeight = %g\n", m_fFallHeight); + CPrintF( "m_fStepHeight = %g\n", m_fStepHeight); + CPrintF( "m_fSenseRange = %g\n", m_fSenseRange); + CPrintF( "m_fViewAngle = %g\n", m_fViewAngle); + + CPrintF( "m_fWalkSpeed = %g\n", m_fWalkSpeed); + CPrintF( "m_aWalkRotateSpeed = %g\n", m_aWalkRotateSpeed); + CPrintF( "m_fAttackRunSpeed = %g\n", m_fAttackRunSpeed); + CPrintF( "m_aAttackRotateSpeed = %g\n", m_aAttackRotateSpeed); + CPrintF( "m_fCloseRunSpeed = %g\n", m_fCloseRunSpeed); + CPrintF( "m_aCloseRotateSpeed = %g\n", m_aCloseRotateSpeed); + CPrintF( "m_fAttackDistance = %g\n", m_fAttackDistance); + CPrintF( "m_fCloseDistance = %g\n", m_fCloseDistance); + CPrintF( "m_fAttackFireTime = %g\n", m_fAttackFireTime); + CPrintF( "m_fCloseFireTime = %g\n", m_fCloseFireTime); + CPrintF( "m_fStopDistance = %g\n", m_fStopDistance); + CPrintF( "m_fIgnoreRange = %g\n", m_fIgnoreRange); + CPrintF( "m_fLockOnEnemyTime = %g\n", m_fLockOnEnemyTime); + + CPrintF( "m_fMoveTime = %g\n", m_fMoveTime); + CPrintF( "m_vDesiredPosition (%g, %g, %g)\n", m_vDesiredPosition(1), m_vDesiredPosition(2), m_vDesiredPosition(3)); + + CTString strDestinationType = DestinationType_enum.NameForValue(INDEX(m_dtDestination)); + CPrintF( "m_dtDestination: %s\n",(const char*) strDestinationType); + CPrintF( "m_penPathMarker %x\n",(const char*) (m_penPathMarker->GetName())); + + CPrintF( "m_vPlayerSpotted (%g, %g, %g)\n", m_vPlayerSpotted(1), m_vPlayerSpotted(2), m_vPlayerSpotted(3)); + CPrintF( "m_fMoveFrequency = %g\n", m_fMoveFrequency); + CPrintF( "m_fMoveSpeed = %g\n", m_fMoveSpeed); + CPrintF( "m_aRotateSpeed = %g\n", m_aRotateSpeed); + CPrintF( "m_fLockStartTime = %g\n", m_fLockStartTime); + CPrintF( "m_fRangeLast = %g\n", m_fRangeLast); + CPrintF( "m_fShootTime = %g\n", m_fShootTime); + CPrintF( "m_fAttackRadius = %g\n", m_fAttackRadius); + CPrintF( "m_tmGiveUp = %g\n", m_tmGiveUp); + CPrintF( "m_fActivityRange = %g\n", m_fActivityRange); + + CTString strMarkerName = "Null ptr, no name"; + if( m_penMarker != NULL) + { + strMarkerName = m_penMarker->GetName(); + } + CPrintF( "m_penMarker %x, marker name: %s\n",(const char*) (m_penMarker->GetName()),(const char*) strMarkerName); + + CTString strMainMusicHolderName = "Null ptr, no name"; + if( m_penMainMusicHolder != NULL) + { + strMainMusicHolderName = m_penMainMusicHolder->GetName(); + } + CPrintF( "m_penMainMusicHolder %x, MainMusicHolder name: %s\n",(const char*) (m_penMainMusicHolder->GetName()),(const char*) strMainMusicHolderName); + CPrintF( "m_tmLastFussTime = %g\n", m_tmLastFussTime); + CPrintF( "m_iScore = %d\n", m_iScore); + CPrintF( "m_fMaxHealth = %g\n", m_fMaxHealth); + CPrintF( "m_bBoss = %d\n", m_bBoss); + CPrintF( "m_fSpiritStartTime = %g\n", m_fSpiritStartTime); + CPrintF( "m_tmSpraySpawned = %g\n", m_tmSpraySpawned); + CPrintF( "m_fSprayDamage = %g\n", m_fSprayDamage); + CPrintF( "m_fMaxDamageAmmount = %g\n", m_fMaxDamageAmmount ); + } + + vLightDirection = FLOAT3D(0.0f, 270.0f, 0.0f); + colAmbient = RGBToColor(32,32,32); + colLight = RGBToColor(255,235,145); + + return CMovableModelEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + //return CEnemyBase::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + }; + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + StartModelAnim(DEVIL_ANIM_WOUNDLOOP, 0); + return DEVIL_ANIM_WOUNDLOOP; + }; + + // death + INDEX AnimForDeath(void) { + StartModelAnim(DEVIL_ANIM_DEATH, 0); + return DEVIL_ANIM_DEATH; + }; + + void DeathNotify(void) { + StopFireBreathParticles(); + StopRegenerationParticles(); + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(DEVIL_ANIM_IDLE, AOF_SMOOTHCHANGE|AOF_LOOPING|AOF_NORESTART); + }; + + void WalkingAnim(void) { + CModelObject &mo = *GetModelObject(); + INDEX iAnim = mo.GetAnim(); + if (iAnim==DEVIL_ANIM_WALK) + { + // do nothing + } else if (iAnim==DEVIL_ANIM_FROMIDLETOWALK) { + StartModelAnim(DEVIL_ANIM_WALK, AOF_LOOPING|AOF_SMOOTHCHANGE); + } else { + StartModelAnim(DEVIL_ANIM_FROMIDLETOWALK, AOF_SMOOTHCHANGE); + } + }; + void RunningAnim(void) { + WalkingAnim(); + }; + void RotatingAnim(void) { + WalkingAnim(); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + //PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D|SOF_VOLUMETRIC); + }; + + + // start fire laser + void StartFireLaser(void) { + //PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING|SOF_3D); + }; + + // fire one laser + void FireOneLaser(FLOAT fRatio, FLOAT fDeltaPitch) + { + PlayWeaponSound( SOUND_LASER); + FLOAT3D vWpnPipeRel = GetFireingPositionRelative(); + FLOAT3D vWpnPipeAbs = GetFireingPositionAbsolute(); + // calculate predicted position + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vSpeedDst = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute*fRatio; + FLOAT fSpeedSrc = DEVIL_LASER_SPEED; + m_vDesiredPosition = CalculatePredictedPosition(vWpnPipeAbs, vTarget, fSpeedSrc, + vSpeedDst, GetPlacement().pl_PositionVector(2) ); + // shoot predicted propelled projectile + ShootPredictedProjectile(PRT_DEVIL_LASER, m_vDesiredPosition, vWpnPipeRel, ANGLE3D(0, fDeltaPitch, 0)); + //PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING); + }; + + // stop fire laser + void StopFireLaser(void) { + m_soSound.Stop(); + PlayLightAnim(LIGHT_ANIM_NONE, 0); + }; + + // start fire rocket + void StartFireRocket(void) { + //PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING); + }; + + void PlayWeaponSound( ULONG idSound) + { + CSoundObject &so = (&m_soWeapon0)[m_iNextChannel]; + m_iNextChannel = (m_iNextChannel+1)%5; + PlaySound(so, idSound, SOF_3D); + } + + // fire one rocket + void FireOneRocket(FLOAT fRatio) + { + PlayWeaponSound( SOUND_ROCKETLAUNCHER); + FLOAT3D vWpnPipeRel = GetFireingPositionRelative(); + FLOAT3D vWpnPipeAbs = GetFireingPositionAbsolute(); + // calculate predicted position + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vSpeedDst = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute*fRatio; + FLOAT fSpeedSrc = DEVIL_ROCKET_SPEED; + m_vDesiredPosition = CalculatePredictedPosition(vWpnPipeAbs, vTarget, fSpeedSrc, + vSpeedDst, GetPlacement().pl_PositionVector(2) ); + // shoot predicted propelled projectile + ShootPredictedProjectile(PRT_DEVIL_ROCKET, m_vDesiredPosition, vWpnPipeRel, ANGLE3D(0, 0, 0)); + //PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING); + + //PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING); + }; + + // stop fire rocket + void StopFireRocket(void) { + m_soSound.Stop(); + PlayLightAnim(LIGHT_ANIM_NONE, 0); + }; + + void AddLowerWeapons(void) + { + // laser + AddAttachmentToModel(this, *GetModelObject(), DEVIL_ATTACHMENT_LASER, MODEL_LASER, TEXTURE_LASER, 0, 0, 0); + // projectile gun + AddAttachmentToModel(this, *GetModelObject(), DEVIL_ATTACHMENT_PROJECTILEGUN, MODEL_PROJECTILEGUN, TEXTURE_PROJECTILEGUN, 0, 0, 0); + GetModelObject()->StretchModel(FLOAT3D(SIZE, SIZE, SIZE)); + }; + + void AddUpperWeapons(void) + { + // rocket launcher + AddAttachmentToModel(this, *GetModelObject(), DEVIL_ATTACHMENT_ROCKETLAUNCHER, MODEL_ROCKETLAUNCHER, TEXTURE_ROCKETLAUNCHER, 0, 0, 0); + // electro gun + AddAttachmentToModel(this, *GetModelObject(), DEVIL_ATTACHMENT_ELETRICITYGUN, MODEL_ELECTRICITYGUN, TEXTURE_ELECTRICITYGUN, 0, 0, 0); + GetModelObject()->StretchModel(FLOAT3D(SIZE, SIZE, SIZE)); + }; + + void RemoveWeapons(void) + { + // remove all weapons + RemoveAttachmentFromModel(*GetModelObject(), DEVIL_ATTACHMENT_LASER); + RemoveAttachmentFromModel(*GetModelObject(), DEVIL_ATTACHMENT_PROJECTILEGUN); + RemoveAttachmentFromModel(*GetModelObject(), DEVIL_ATTACHMENT_ELETRICITYGUN); + RemoveAttachmentFromModel(*GetModelObject(), DEVIL_ATTACHMENT_ROCKETLAUNCHER); + } + + class CDevilMarker *GetAction(void) + { + CDevilMarker *penAction = (CDevilMarker *) (CEntity*) m_penAction; + ASSERT( penAction != NULL); + return penAction; + }; + +/************************************************************ + * PREDICTED PROJECTILE * + ************************************************************/ + void F_FirePredictedProjectile(void) + { + PlayWeaponSound( SOUND_LAVABOMB); + FLOAT3D vFireingRel = GetFireingPositionRelative(); + FLOAT3D vFireingAbs = GetFireingPositionAbsolute(); + + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vSpeedDest = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute; + FLOAT fLaunchSpeed; + FLOAT fRelativeHdg; + + // obtain current gun orientation + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(m_iAttID); + FLOAT fPitch = amo.amo_plRelative.pl_OrientationAngle(2); + + // calculate parameters for predicted angular launch curve + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + CalculateAngularLaunchParams( vFireingAbs, 0, vTarget, vSpeedDest, fPitch, fLaunchSpeed, fRelativeHdg); + + // target enemy body + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + // launch + CPlacement3D pl; + PrepareFreeFlyingProjectile(pl, vShootTarget, vFireingRel, ANGLE3D( fRelativeHdg, fPitch, 0)); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_LAVAMAN_BIG_BOMB; + eLaunch.fSpeed = fLaunchSpeed; + penProjectile->Initialize(eLaunch); + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if (ee.ee_slEvent==EVENTCODE_EDevilCommand) + { + EDevilCommand eDevilCommand = ((EDevilCommand &) ee); + if( eDevilCommand.dctType == DC_FORCE_ATTACK_RADIUS) + { + m_fAttackRadius = eDevilCommand.fAttackRadius; + m_vStartPosition = eDevilCommand.vCenterOfAttack; + } + if( eDevilCommand.dctType == DC_DECREASE_ATTACK_RADIUS) + { + if( m_fAttackRadius>21.0f) + { + m_fAttackRadius -= 20.0f; + } + } + } + + return CEnemyBase::HandleEvent(ee); + } + +procedures: +/************************************************************ + * TRY TO REACH DESTINATION * + ************************************************************/ + // move to given destination position + WalkTo(EVoid) + { + autocall WaitCurrentAnimEnd() EReturn; + WalkingAnim(); + m_vDesiredPosition = GetAction()->GetPlacement().pl_PositionVector; + // setup parameters + m_fMoveFrequency = 0.25f; + m_fMoveSpeed = 15.0f; + m_aRotateSpeed = 60.0f; + m_fMoveTime = _pTimer->CurrentTick() + CalcDistanceInPlaneToDestination()/m_fMoveSpeed + 5.0f; + // while not there and time not expired + while (CalcDistanceInPlaneToDestination()>m_fMoveSpeed*m_fMoveFrequency*4.0f && + m_fMoveTime>_pTimer->CurrentTick()) { + // every once in a while + wait (m_fMoveFrequency) { + on (EBegin) : { + // adjust direction and speed + ULONG ulFlags = SetDesiredMovement(); + MovementAnimation(ulFlags); + resume; + } + on (ETimer) : { stop; } + } + } + + StopMoving(); + // return to the caller + return EReturn(); + }; + +/************************************************************ + * CITY DESTROYING * + ************************************************************/ + DestroyCity() + { + m_soSound.Set3DParameters(1000.0f, 500.0f, 3.0f, 1.0f); + + while(TRUE) + { + if( GetAction()->m_datType == DAT_RISE) + { + autocall Rise() EReturn; + } + else if( GetAction()->m_datType == DAT_ROAR) + { + SelectRandomAnger(); + autocall Angry() EReturn; + } + else if( GetAction()->m_datType == DAT_SMASH) + { + autocall Smash() EReturn; + } + else if( GetAction()->m_datType == DAT_PUNCH) + { + autocall Punch() EReturn; + } + else if( GetAction()->m_datType == DAT_HIT_GROUND) + { + autocall HitGround() EReturn; + } + else if( GetAction()->m_datType == DAT_JUMP) + { + // do nothing, obsolete + } + else if( GetAction()->m_datType == DAT_WAIT) + { + autocall WaitCurrentAnimEnd() EReturn; + StartModelAnim(DEVIL_ANIM_IDLE, 0); + autowait(GetModelObject()->GetAnimLength(DEVIL_ANIM_IDLE)*GetAction()->m_iWaitIdles); + } + else if( GetAction()->m_datType == DAT_WALK) + { + autocall WalkTo() EReturn; + } + else if( GetAction()->m_datType == DAT_STOP_DESTROYING) + { + return EReturn(); + } + else if(TRUE) + { + StartModelAnim(DEVIL_ANIM_IDLE, 0); + autowait(GetModelObject()->GetAnimLength(DEVIL_ANIM_IDLE)); + } + // switch to next action + m_penAction = GetAction()->m_penTarget; + if( GetAction()->m_penTrigger != NULL) + { + GetAction()->m_penTrigger->SendEvent(ETrigger()); + } + } + }; + + WaitCurrentAnimEnd() + { + autowait(_pTimer->TickQuantum); + CModelObject &mo = *GetModelObject(); + FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); + if( tmWait > _pTimer->TickQuantum) + { + FLOAT fTimeToWait = tmWait-_pTimer->TickQuantum*2; + if( fTimeToWait>=_pTimer->TickQuantum) + { + autowait(fTimeToWait); + } + } + return EReturn(); + } + + WaitWalkToEnd() + { + if(GetModelObject()->GetAnim()==DEVIL_ANIM_WALK) + { + autocall WaitCurrentAnimEnd() EReturn; + StartModelAnim(DEVIL_ANIM_FROMWALKTOIDLE, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_FROMWALKTOIDLE)-0.1f); + } + autocall WaitCurrentAnimEnd() EReturn; + return EReturn(); + } + + WaitWalkOrIdleToEnd() + { + if(GetModelObject()->GetAnim()==DEVIL_ANIM_WALK) + { + autocall WaitCurrentAnimEnd() EReturn; + StartModelAnim(DEVIL_ANIM_FROMWALKTOIDLE, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_FROMWALKTOIDLE)-0.1f); + } + else if(GetModelObject()->GetAnim()==DEVIL_ANIM_FROMIDLETOWALK) + { + autocall WaitCurrentAnimEnd() EReturn; + StartModelAnim(DEVIL_ANIM_FROMWALKTOIDLE, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_FROMWALKTOIDLE)-0.1f); + } + else if(GetModelObject()->GetAnim()==DEVIL_ANIM_IDLE) + { + autocall WaitCurrentAnimEnd() EReturn; + } + return EReturn(); + } + + Rise() + { + autocall WaitCurrentAnimEnd() EReturn; + PlaySound(m_soSound, SOUND_GETUP, SOF_3D); + GetModelObject()->PlayAnim(DEVIL_ANIM_GETUP, 0); + return EReturn(); + } + + Celebrate() + { + autocall WaitWalkToEnd() EReturn; + + PlaySound(m_soSound, SOUND_CELEBRATE01, SOF_3D); + GetModelObject()->PlayAnim(DEVIL_ANIM_CELEBRATE01, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_CELEBRATE01)-0.1f); + return EReturn(); + } + + Angry() + { + autocall WaitWalkToEnd() EReturn; + + GetModelObject()->PlayAnim(m_iAngryAnim, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soSound, m_iAngrySound, SOF_3D); + autowait( GetModelObject()->GetAnimLength(m_iAngryAnim)-0.1f); + return EReturn(); + } + + + SubBeamDamage1() + { + StopMoving(); + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + GetModelObject()->PlayAnim(DEVIL_ANIM_WOUNDSTART, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_WOUNDSTART)-0.1f); + GetModelObject()->PlayAnim(DEVIL_ANIM_WOUNDLOOP, AOF_LOOPING|AOF_SMOOTHCHANGE); + jump SubBeamDamage2(); + } + SubBeamDamage2() + { + while(TRUE) { + wait(0.1f) + { + on (EBegin) : { resume; } + on (EHitBySpaceShipBeam) : { + m_tmHitBySpaceShipBeam = _pTimer->CurrentTick(); + stop; + } + on (ETimer) : { jump SubBeamDamage3(); } + } + } + } + SubBeamDamage3() + { + GetModelObject()->PlayAnim(DEVIL_ANIM_WOUNDEND, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_WOUNDEND)-0.1f); + GetModelObject()->PlayAnim(DEVIL_ANIM_IDLE, AOF_LOOPING|AOF_SMOOTHCHANGE); + return EReturn(); + } + BeamDamage() + { + wait() + { + on (EBegin) : { call SubBeamDamage1(); } + on (EHitBySpaceShipBeam) : { + m_tmHitBySpaceShipBeam = _pTimer->CurrentTick(); + resume; + } + on (EReturn) : { stop; } + } + return EReturn(); + } + + Smash() + { + //autocall WaitCurrentAnimEnd() EReturn; + //autocall WaitWalkToEnd() EReturn; + + GetModelObject()->PlayAnim(DEVIL_ANIM_FROMWALKTOIDLE, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + GetModelObject()->PlayAnim(DEVIL_ANIM_SMASH, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + autowait(0.05f); + PlaySound(m_soSound, SOUND_SMASH, SOF_3D); + autowait(0.7f); + if( GetAction()->m_penToDestroy1 != NULL) + { + EBrushDestroyedByDevil ebdbd; + ebdbd.vDamageDir = FLOAT3D( -0.125f, 0.0f, -0.5f); + GetAction()->m_penToDestroy1->SendEvent(ebdbd); + } + autowait(2.8f-1.0f); + if( GetAction()->m_penToDestroy2 != NULL) + { + EBrushDestroyedByDevil ebdbd; + ebdbd.vDamageDir = FLOAT3D( -0.125f, 0.0f, -0.5f); + GetAction()->m_penToDestroy2->SendEvent(ebdbd); + } + return EReturn(); + } + + Punch() + { + //autocall WaitWalkToEnd() EReturn; + //autocall WaitCurrentAnimEnd() EReturn; + GetModelObject()->PlayAnim(DEVIL_ANIM_FROMWALKTOIDLE, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + GetModelObject()->PlayAnim(DEVIL_ANIM_PUNCH, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + + autowait(0.05f); + PlaySound(m_soSound, SOUND_PUNCH, SOF_3D); + autowait(0.8f); + if( GetAction()->m_penToDestroy1 != NULL) + { + EBrushDestroyedByDevil ebdbd; + ebdbd.vDamageDir = FLOAT3D( -0.125f, 0.0f, -0.5f); + GetAction()->m_penToDestroy1->SendEvent(ebdbd); + } + autowait(2.8f-1.1f); + if( GetAction()->m_penToDestroy2 != NULL) + { + EBrushDestroyedByDevil ebdbd; + ebdbd.vDamageDir = FLOAT3D( 0.125f, 0.0f, -0.5f); + GetAction()->m_penToDestroy2->SendEvent(ebdbd); + } + + return EReturn(); + } + + HitGround() + { + autocall WaitWalkToEnd() EReturn; + + PlaySound(m_soSound, SOUND_ATTACKCLOSE, SOF_3D); + GetModelObject()->PlayAnim(DEVIL_ANIM_ATTACKCLOSE, AOF_SMOOTHCHANGE); + autowait(1.44f); + ShakeItBaby(_pTimer->CurrentTick(), 5.0f); + + CPlacement3D plObelisk = GetPlacement(); + // spawn spray spray + CEntity *penEffector = CreateEntity( plObelisk, CLASS_EFFECTOR); + // set spawn parameters + ESpawnEffector eSpawnEffector; + eSpawnEffector.tmLifeTime = 6.0f; + eSpawnEffector.fSize = 1.0f; + eSpawnEffector.eetType = ET_HIT_GROUND; + eSpawnEffector.vDamageDir = FLOAT3D( 0.0f, 2.0f, 0.0f); + // initialize spray + penEffector->Initialize( eSpawnEffector); + + return EReturn(); + } + + GrabLowerWeapons() + { + autocall WaitWalkToEnd() EReturn; + GetModelObject()->PlayAnim(DEVIL_ANIM_GRABWEAPONS01, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soSound, SOUND_DRAW_LOWER_WEAPONS, SOF_3D); + autowait(0.84f); + AddLowerWeapons(); + WalkingAnim(); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + return EReturn(); + } + + GrabUpperWeapons() + { + autocall WaitWalkToEnd() EReturn; + GetModelObject()->PlayAnim(DEVIL_ANIM_GRABWEAPONS02, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soSound, SOUND_DRAW_UPPER_WEAPONS, SOF_3D); + autowait(0.84f); + AddUpperWeapons(); + m_bHasUpperWeapons = TRUE; + WalkingAnim(); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + return EReturn(); + } + + GrabBothWeapons() + { + autocall WaitWalkToEnd() EReturn; + GetModelObject()->PlayAnim(DEVIL_ANIM_GRABWEAPONS01, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soGrabLowerWeapons, SOUND_DRAW_LOWER_WEAPONS, SOF_3D); + autowait(0.84f); + AddLowerWeapons(); + GetModelObject()->PlayAnim(DEVIL_ANIM_GRABWEAPONS02, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soGrabUpperWeapons, SOUND_DRAW_UPPER_WEAPONS, SOF_3D); + autowait(0.84f); + AddUpperWeapons(); + m_bHasUpperWeapons = TRUE; + WalkingAnim(); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + return EReturn(); + } + + PreMainLoop(EVoid) : CEnemyBase::PreMainLoop + { + m_soSound.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_soGrabLowerWeapons.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_soGrabUpperWeapons.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_soJumpIntoPyramid.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_soLeft.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_soRight.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_soWeapon0.Set3DParameters(1000.0f, 500.0f, 1.0f, 1.0f); + m_soWeapon1.Set3DParameters(1000.0f, 500.0f, 1.0f, 1.0f); + m_soWeapon2.Set3DParameters(1000.0f, 500.0f, 1.0f, 1.0f); + m_soWeapon3.Set3DParameters(1000.0f, 500.0f, 1.0f, 1.0f); + m_soWeapon4.Set3DParameters(1000.0f, 500.0f, 1.0f, 1.0f); + + TurnOnPhysics(); + + if (m_penEnemy==NULL) + { + // get some player for trigger source if any is existing + CEntity *penEnemy = FixupCausedToPlayer(this, m_penEnemy, /*bWarning=*/FALSE); + if (penEnemy!=m_penEnemy) { + SetTargetSoft(penEnemy); + } + } + + return EReturn(); + } + +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + // Play wound animation + BeWounded(EDamage eDamage) : CEnemyBase::BeWounded + { + StopMoving(); + // determine damage anim and play the wounding + autowait(GetModelObject()->GetAnimLength(AnimForDamage(eDamage.fAmount))); + return EReturn(); + }; + +/************************************************************ + * C L O S E A T T A C K * + ************************************************************/ + Hit(EVoid) : CEnemyBase::Hit { + autocall WaitCurrentAnimEnd() EReturn; + StartModelAnim(DEVIL_ANIM_ATTACKCLOSE, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soSound, SOUND_ATTACKCLOSE, SOF_3D); + autowait(1.4f); + ShakeItBaby(_pTimer->CurrentTick(), 5.0f); + if( CalcDist(m_penEnemy) < m_fCloseDistance) + { + InflictDirectDamage(m_penEnemy, this, DMT_IMPACT, 1000.0f, + m_penEnemy->GetPlacement().pl_PositionVector, FLOAT3D(0,1,0)); + } + InflictHoofDamage( DEVIL_HIT_HOOF_OFFSET); + + autowait(GetModelObject()->GetAnimLength(DEVIL_ANIM_ATTACKCLOSE-1.4f)-_pTimer->TickQuantum); + return EReturn(); + }; + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + // initial preparation + InitializeAttack(EVoid) : CEnemyBase::InitializeAttack { + jump CEnemyBase::InitializeAttack(); + }; + + Fire(EVoid) : CEnemyBase::Fire + { + m_iToFireProjectiles = 0; + m_fAttackFireTime = 10.0f; + m_fPauseStretcher = 1.0f; + + if( m_dapAttackPower==DAP_MEDIUM_POWER_ATTACK && + (_pTimer->CurrentTick()-m_fLastWalkTime) > 6.0f) + { + m_fAttackFireTime = 6.0f; + m_fLastWalkTime = _pTimer->CurrentTick()+6.0f; + return; + } + + switch( m_dapAttackPower) + { + case DAP_PLAYER_HUNT: + if( _pTimer->CurrentTick()-m_tmLastAngry > 10.0f) + { + m_fAttackFireTime = 7.5+FRnd()*5; + m_tmLastAngry = _pTimer->CurrentTick(); + SelectRandomAnger(); + jump Angry(); + } + return; + break; + case DAP_LOW_POWER_ATTACK: + m_iToFireProjectiles = 2; + m_fAttackFireTime = 5.0f; + m_fPauseStretcher = 1.0f; + break; + case DAP_MEDIUM_POWER_ATTACK: + m_iToFireProjectiles = 3; + m_fAttackFireTime = 0.1f; + m_fPauseStretcher = 0.5f; + break; + case DAP_FULL_POWER_ATTACK: + m_iToFireProjectiles = 4; + m_fAttackFireTime = 0.1f; + m_fPauseStretcher = 0.1f; + break; + } + + INDEX iRnd = IRnd()%5; + if( !m_bHasUpperWeapons) + { + iRnd = IRnd()%3; + } + + /*iRnd = Clamp(INDEX(tmp_af[0]), INDEX(0), INDEX(4));*/ + switch(iRnd) + { + case 0: + jump FirePredictedProjectile(); + break; + case 1: + jump FireLaser(); + break; + case 2: + jump FireGuidedProjectile(); + break; + case 3: + jump FireRocketLauncher(); + break; + case 4: + jump FireElectricityGun(); + break; + } + }; + + // call this to lock on player for some time - set m_fLockOnEnemyTime before calling + DevilLockOnEnemy(EVoid) + { + // stop moving + StopMoving(); + // play animation for locking + ChargeAnim(); + // wait charge time + m_fLockStartTime = _pTimer->CurrentTick(); + while (m_fLockStartTime+GetProp(m_fLockOnEnemyTime) > _pTimer->CurrentTick()) { + // each tick + m_fMoveFrequency = 0.05f; + wait (m_fMoveFrequency) { + on (ETimer) : { stop; } + on (EBegin) : { + m_vDesiredPosition = PlayerDestinationPos(); + // if not heading towards enemy + if (!IsInPlaneFrustum(m_penEnemy, CosFast(30.0f))) { + m_fLockStartTime = -10000.0f; + stop; + } + +/* if (!IsInPlaneFrustum(m_penEnemy, CosFast(5.0f))) { + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = GetLockRotationSpeed(); + // if heading towards enemy + } else { + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = 0.0f; + }*/ + // adjust direction and speed + //ULONG ulFlags = SetDesiredMovement(); + //MovementAnimation(ulFlags); + resume; + } + } + } + // stop rotating + StopRotating(); + + // return to caller + return EReturn(); + }; + + AdjustWeaponForFire() + { + FLOAT3D vRelWeapon = GetWeaponPositionRelative(); + FLOAT3D vAbsWeapon = GetPlacement().pl_PositionVector + vRelWeapon*GetRotationMatrix(); + + m_fFireTime = _pTimer->CurrentTick()+m_fAdjustWeaponTime; + FLOAT3D vEnemy = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vDir = (vEnemy-vAbsWeapon).Normalize(); + ANGLE3D aAngles; + DirectionVectorToAngles(vDir, aAngles); + CPlacement3D plRelPl = CPlacement3D(FLOAT3D(0,0,0),aAngles); + plRelPl.AbsoluteToRelative(GetPlacement()); + FLOAT fWantedHdg = plRelPl.pl_OrientationAngle(1); + FLOAT fWantedPitch = plRelPl.pl_OrientationAngle(2); + + // adjust angle of projectile gun + if( m_iAttID == DEVIL_ATTACHMENT_PROJECTILEGUN) + { + FLOAT3D vShooting = GetPlacement().pl_PositionVector; + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT fDistanceFactor = 1.0f-ClampUp( (vShooting-vTarget).Length()/250.0f, 1.0f); + fWantedPitch = 20-fDistanceFactor*50.0f; + } + + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(m_iAttID); + m_fDeltaWeaponHdg = (fWantedHdg -amo.amo_plRelative.pl_OrientationAngle(1))/(m_fAdjustWeaponTime/_pTimer->TickQuantum); + m_fDeltaWeaponPitch = (fWantedPitch-amo.amo_plRelative.pl_OrientationAngle(2))/(m_fAdjustWeaponTime/_pTimer->TickQuantum); + while (m_fFireTime > _pTimer->CurrentTick()) + { + wait(_pTimer->TickQuantum) + { + on (EBegin) : + { + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(m_iAttID); + amo.amo_plRelative.pl_OrientationAngle(1) += m_fDeltaWeaponHdg; + amo.amo_plRelative.pl_OrientationAngle(2) += m_fDeltaWeaponPitch; + resume; + } + on (ETimer) : { stop; } + } + } + return EReturn(); + } + + StraightenUpWeapon() + { + FLOAT fAdjustWeaponTime = 0.25f; + m_fFireTime = _pTimer->CurrentTick()+fAdjustWeaponTime; + + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(m_iAttID); + m_fDeltaWeaponHdg = amo.amo_plRelative.pl_OrientationAngle(1)/(fAdjustWeaponTime/_pTimer->TickQuantum); + m_fDeltaWeaponPitch = amo.amo_plRelative.pl_OrientationAngle(2)/(fAdjustWeaponTime/_pTimer->TickQuantum); + while (m_fFireTime > _pTimer->CurrentTick()) + { + wait(_pTimer->TickQuantum) + { + on (EBegin) : + { + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(m_iAttID); + amo.amo_plRelative.pl_OrientationAngle(1) -= m_fDeltaWeaponHdg; + amo.amo_plRelative.pl_OrientationAngle(2) -= m_fDeltaWeaponPitch; + resume; + } + on (ETimer) : { stop; } + } + } + return EReturn(); + } + + FireLaser(EVoid) + { + autocall WaitWalkOrIdleToEnd() EReturn; + + // to fire + StartModelAnim(DEVIL_ANIM_FROMIDLETOATTACK01, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_FROMIDLETOATTACK01)-0.1f); + StartModelAnim(DEVIL_ANIM_ATTACK01, AOF_SMOOTHCHANGE|AOF_LOOPING); + + m_iAttID = DEVIL_ATTACHMENT_LASER; + m_fAdjustWeaponTime = 0.25f; + autocall AdjustWeaponForFire() EReturn; + + // fire lasers + StartFireLaser(); + m_iFiredProjectiles = 0; + while (m_iFiredProjectilesGetAnimLength(DEVIL_ANIM_FROMIDLETOATTACK02)-0.1f); + StartModelAnim(DEVIL_ANIM_ATTACK02, AOF_SMOOTHCHANGE|AOF_LOOPING); + + m_iAttID = DEVIL_ATTACHMENT_ROCKETLAUNCHER; + m_fAdjustWeaponTime = 0.5f; + autocall AdjustWeaponForFire() EReturn; + + // fire rockets + StartFireRocket(); + m_iFiredProjectiles = 0; + while (m_iFiredProjectilesGetAnimLength(DEVIL_ANIM_FROMIDLETOATTACK01)-0.1f); + StartModelAnim(DEVIL_ANIM_ATTACK01, AOF_SMOOTHCHANGE|AOF_LOOPING); + + m_iAttID = DEVIL_ATTACHMENT_PROJECTILEGUN; + m_fAdjustWeaponTime = 0.5f; + autocall AdjustWeaponForFire() EReturn; + + // start fireing predicted magic projectile + m_iFiredProjectiles = 0; + while (m_iFiredProjectilesGetAnimLength(DEVIL_ANIM_FROMATTACK01TOIDLE)-0.1f); + //StartModelAnim(DEVIL_ANIM_IDLE, AOF_SMOOTHCHANGE|AOF_LOOPING); + + //autowait(0.25f*m_fPauseStretcher); + + MaybeSwitchToAnotherPlayer(); + + // shoot completed + return EReturn(); + } + + FireElectricityGun(EVoid) + { + autocall WaitWalkOrIdleToEnd() EReturn; + + // to fire + StartModelAnim(DEVIL_ANIM_FROMIDLETOATTACK02, AOF_SMOOTHCHANGE); + autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_FROMIDLETOATTACK02)-0.1f); + StartModelAnim(DEVIL_ANIM_ATTACK02, AOF_SMOOTHCHANGE|AOF_LOOPING); + + m_iAttID = DEVIL_ATTACHMENT_ELETRICITYGUN; + m_fAdjustWeaponTime = 0.5f; + //autocall AdjustWeaponForFire() EReturn; + + // start fireing electricity + m_iFiredProjectiles = 0; + while (m_iFiredProjectilesGetEntityInfo()); + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, m_vElectricityTarget); + + // give some time so player can move away from electricity beam + autowait(0.4f); + + // fire electricity beam + m_bRenderElectricity = TRUE; + m_tmTemp = _pTimer->CurrentTick(); + m_tmNextFXTime = m_tmTemp-_pTimer->TickQuantum; + PlayWeaponSound( SOUND_GHOSTBUSTER); + while( _pTimer->CurrentTick() < m_tmTemp+0.75f) + { + wait(_pTimer->TickQuantum) { + on (EBegin): { + // correct electricity beam target + FLOAT3D vNewTarget; + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vNewTarget); + FLOAT3D vDiff = vNewTarget-m_vElectricityTarget; + // if we have valid length + if( vDiff.Length() > 1.0f) + { + // calculate adjustment + m_vElectricityTarget = m_vElectricityTarget+vDiff.Normalize()*10.0f*_pTimer->TickQuantum; + } + + // cast ray + CCastRay crRay( this, m_vElectricitySource, m_vElectricityTarget); + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_bPhysical = FALSE; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + GetWorld()->CastRay(crRay); + // if entity is hit + if( crRay.cr_penHit != NULL) + { + // apply damage + InflictDirectDamage( crRay.cr_penHit, this, DMT_BULLET, 50.0f*_pTimer->TickQuantum/0.5f, + FLOAT3D(0, 0, 0), (m_vElectricitySource-m_vElectricityTarget).Normalize()); + } + + if( _pTimer->CurrentTick()>m_tmNextFXTime) + { + m_tmNextFXTime = _pTimer->CurrentTick()+0.125f+FRnd()*0.125f; + CPlacement3D plElectricityTarget = CPlacement3D( m_vElectricityTarget, ANGLE3D(0,0,0)); + CEntity *penEffector = CreateEntity( plElectricityTarget, CLASS_EFFECTOR); + // set spawn parameters + ESpawnEffector eSpawnEffector; + eSpawnEffector.tmLifeTime = 6.0f; + eSpawnEffector.fSize = 0.025f; + eSpawnEffector.eetType = ET_HIT_GROUND; + eSpawnEffector.vDamageDir = FLOAT3D( 0.0f, 2.0f, 0.0f); + // initialize spray + penEffector->Initialize( eSpawnEffector); + } + + resume; + }; + on (ETimer): { stop; }; + } + } + m_soSound.Stop(); + m_bRenderElectricity = FALSE; + + autowait( 0.8f-m_fAdjustWeaponTime); + m_iFiredProjectiles++; + if (!IsInFrustum(m_penEnemy, CosFast(30.0f))) { + m_iFiredProjectiles = 10000; + } + } + autocall StraightenUpWeapon() EReturn; + + // from idle + StartModelAnim(DEVIL_ANIM_FROMATTACK02TOIDLE, AOF_SMOOTHCHANGE); + //autowait( GetModelObject()->GetAnimLength(DEVIL_ANIM_FROMATTACK02TOIDLE)-0.1f); + //StartModelAnim(DEVIL_ANIM_IDLE, AOF_SMOOTHCHANGE|AOF_LOOPING); + + MaybeSwitchToAnotherPlayer(); + + // shoot completed + return EReturn(); + } + + FireGuidedProjectile(EVoid) + { + autocall WaitWalkOrIdleToEnd() EReturn; + + StartModelAnim(DEVIL_ANIM_ATTACKBREATHSTART, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soLeft, SOUND_ATTACK_BREATH_START, SOF_3D); + + StartModelAnim(DEVIL_ANIM_ATTACKBREATH, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + PlaySound(m_soRight, SOUND_ATTACK_BREATH_LOOP, SOF_LOOP|SOF_3D); + + // start fireing predicted magic projectile + m_iFiredProjectiles = 0; + m_tmFireBreathStart = _pTimer->CurrentTick(); + m_tmFireBreathStop = UpperLimit(0.0f); + // calculate breath source and target positions + const FLOATmatrix3D &m = GetRotationMatrix(); + m_vFireBreathSource = GetPlacement().pl_PositionVector+MAGIC_PROJECTILE_EXIT*m; + m_vFireBreathTarget = m_penEnemy->GetPlacement().pl_PositionVector-FLOAT3D(0,20.0f,0); + while (m_iFiredProjectilesPlayAnim(DEVIL_ANIM_CLIMB, 0); + PlaySound(m_soJumpIntoPyramid, SOUND_CLIMB, SOF_3D); + autowait(7.0f); + + // turn it arround + m_tmTemp = _pTimer->CurrentTick(); + while( _pTimer->CurrentTick() < m_tmTemp+0.7f) + { + wait(_pTimer->TickQuantum) { + on (EBegin): { resume; }; + on (ETimer): { stop; }; + otherwise(): { resume; }; + } + CPlacement3D plCurrent = GetPlacement(); + FLOAT aDelta = -35.0f/0.7f*_pTimer->TickQuantum; + plCurrent.pl_OrientationAngle+=FLOAT3D(aDelta,0,0); + SetPlacement(plCurrent); + } + + ShakeItFarBaby(_pTimer->CurrentTick(), 1.5f); + autowait(GetModelObject()->GetAnimLength(DEVIL_ANIM_CLIMB)-7.335f-_pTimer->TickQuantum); + + SelectRandomAnger(); + GetModelObject()->PlayAnim(m_iAngryAnim, 0); + PlaySound(m_soSound, m_iAngrySound, SOF_3D); + autowait( GetModelObject()->GetAnimLength(m_iAngryAnim)-0.1f); + + StopMoving(); + StopRotating(); + TurnOnPhysics(); + autocall GrabBothWeapons() EReturn; + + m_dsDevilState = DS_PYRAMID_FIGHT; + m_dapAttackPower = DAP_MEDIUM_POWER_ATTACK; + m_fAttackRadius = 1e6f; + m_fAttackRunSpeed = 8.0f; + + return EReturn(); + } + + TeleportIntoPyramid(EVoid) + { + // remove weapons + RemoveWeapons(); + SetTargetNone(); + Teleport(m_plTeleport, FALSE); + StopMoving(); + StopRotating(); + + SelectRandomAnger(); + GetModelObject()->PlayAnim(m_iAngryAnim, 0); + PlaySound(m_soSound, m_iAngrySound, SOF_3D); + autowait( GetModelObject()->GetAnimLength(m_iAngryAnim)-0.1f); + + TurnOnPhysics(); + autocall GrabBothWeapons() EReturn; + + m_dsDevilState = DS_PYRAMID_FIGHT; + m_dapAttackPower = DAP_MEDIUM_POWER_ATTACK; + m_fAttackRadius = 1e6f; + m_fAttackRunSpeed = 8.0f; + + return EReturn(); + } + + RegenerationImpulse(EVoid) + { + m_dsPreRegenerationDevilState = m_dsDevilState; + m_dsDevilState = DS_REGENERATION_IMPULSE; + GetModelObject()->PlayAnim(DEVIL_ANIM_HEAL, 0); + PlaySound(m_soSound, SOUND_HEAL, SOF_3D); + + StopFireBreathParticles(); + m_tmRegenerationStart = _pTimer->CurrentTick(); + m_tmRegenerationStop = m_tmRegenerationStart+TM_HEALTH_IMPULSE-1.5f/*Regeneration particle life time*/; + // apply health impulse + m_tmTemp = _pTimer->CurrentTick(); + while( _pTimer->CurrentTick() < m_tmTemp+TM_HEALTH_IMPULSE) + { + wait(_pTimer->TickQuantum) { + on (EBegin): { resume; }; + on (ETimer): { stop; }; + otherwise(): { resume; }; + } + SetHealth(GetHealth()+HEALTH_IMPULSE*_pTimer->TickQuantum/TM_HEALTH_IMPULSE); + } + m_dsDevilState = m_dsPreRegenerationDevilState; + + return EReturn(); + } + + StopAttack(EVoid) : CEnemyBase::StopAttack { + if(m_penEnemy==NULL) + { + autocall Celebrate() EReturn; + } + + jump CEnemyBase::StopAttack(); + }; + + ContinueInMainLoop(EVoid) + { + SwitchToModel(); + // continue behavior in base class + if( !m_bWasOnceInMainLoop) + { + m_bWasOnceInMainLoop = TRUE; + jump CEnemyBase::MainLoop(); + } + else + { + // get some player for trigger source if any is existing + CEntity *penEnemy = FixupCausedToPlayer(this, m_penEnemy, /*bWarning=*/FALSE); + if (penEnemy!=m_penEnemy) { + SetTargetSoft(penEnemy); + } + + jump CEnemyBase::StandardBehavior(); + } + } +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + SetFlags(GetFlags()&~ENF_ALIVE); + StopFireBreathParticles(); + StopRegenerationParticles(); + // stop moving + StopMoving(); + DeathSound(); // death sound + // set physic flags + SetCollisionFlags(ECF_MODEL); + // start death anim + AnimForDeath(); + autowait(4.66f); + ShakeItFarBaby(_pTimer->CurrentTick(), 5.0f); + autowait(GetModelObject()->GetAnimLength(DEVIL_ANIM_DEATH)-4.66f); + m_tmDeathTime = _pTimer->CurrentTick(); + + CWorldSettingsController *pwsc = GetWSC(); + if (pwsc!=NULL) + { + pwsc->m_tmGlaringStarted = _pTimer->CurrentTick()+1.5f; + pwsc->m_tmGlaringEnded = pwsc->m_tmGlaringStarted+1.0f, + pwsc->m_fGlaringFadeInRatio = 0.2f; + pwsc->m_fGlaringFadeOutRatio = 0.7f; + } + autowait(1.5f); + PlaySound(m_soLeft, SOUND_DISAPPEAR, SOF_3D|SOF_VOLUMETRIC); + autowait(0.25f); + SwitchToEditorModel(); + + PlaySound(m_soRight, SOUND_DEATHPARTICLES, SOF_3D); + return EEnd(); + }; + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + m_sptType = SPT_NONE; + // declare yourself as a model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_WALKING&~EPF_TRANSLATEDBYGRAVITY); + SetCollisionFlags(((ECBI_MODEL)<StretchModel(FLOAT3D(SIZE, SIZE, SIZE)); + ModelChangeNotify(); + + StandingAnim(); + + // setup moving speed + m_fWalkSpeed = 10.0f; + m_aWalkRotateSpeed = AngleDeg(90.0f); + m_fAttackRunSpeed = 8.0f; + m_aAttackRotateSpeed = AngleDeg(90.0f); + m_fCloseRunSpeed = 8.0f; + m_aCloseRotateSpeed = AngleDeg(90.0f); + // setup attack distances + m_fAttackDistance = 1e24f; + m_fCloseDistance = 50.0f; + m_fStopDistance = 10.0f; + m_fAttackFireTime = 10.0f; + m_fCloseFireTime = 5.0f; + m_fIgnoreRange = UpperLimit(0.0f); + m_iScore = 1E6; + en_fAcceleration = en_fDeceleration = 50.0f; + m_fLockOnEnemyTime = 0.05f; + m_fPauseStretcher = 1.0f; + m_bWasOnceInMainLoop = FALSE; + + // setup light source + SetupLightSource(); + // set light animation if available + try { + m_aoLightAnimation.SetData_t(CTFILENAME("Animations\\BasicEffects.ani")); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load Animations\\BasicEffects.ani: %s"), strError); + } + PlayLightAnim(LIGHT_ANIM_NONE, 0); + + autowait(0.1f); + + wait() { + on (EBegin) : { resume; } + on (ETrigger) : { stop; } + } + + StartModelAnim(DEVIL_ANIM_POSEDOWN, 0); + SwitchToModel(); + + // set initial state + m_dsDevilState = DS_NOT_EXISTING; + + wait() + { + on (EBegin) : { + if( cht_bDebugFinalBoss) + { + CPrintF("Main loop, event: Begin\n"); + } + if(m_dsDevilState == DS_NOT_EXISTING) + { + m_dsDevilState = DS_DESTROYING_CITY; + call DestroyCity(); + } + resume; + } + on (ETrigger) : + { + if( cht_bDebugFinalBoss) + { + CPrintF("Main loop, event: Trigger\n"); + } + resume; + } + on (EDevilCommand eDevilCommand) : + { + if( cht_bDebugFinalBoss) + { + CTString strDevilCommand = DevilCommandType_enum.NameForValue(INDEX(eDevilCommand.dctType)); + CPrintF("Main loop, event: Devil command: %s\n",(const char*) strDevilCommand); + } + + if( eDevilCommand.dctType == DC_GRAB_LOWER_WEAPONS) + { + m_dapAttackPower = DAP_LOW_POWER_ATTACK; + m_dsDevilState = DS_ENEMY; + call GrabLowerWeapons(); + } + // force given action marker + else if( eDevilCommand.dctType == DC_FORCE_ACTION) + { + m_penAction = eDevilCommand.penForcedAction; + call DestroyCity(); + } + else if( eDevilCommand.dctType == DC_STOP_MOVING) + { + m_vStartPosition = GetPlacement().pl_PositionVector; + m_fAttackRadius = 0.0f; + } + else if( eDevilCommand.dctType == DC_STOP_ATTACK) + { + SetTargetNone(); + } + else if( eDevilCommand.dctType == DC_JUMP_INTO_PYRAMID) + { + GetModelObject()->PlayAnim( DEVIL_ANIM_IDLE, 0); + m_plTeleport = eDevilCommand.penForcedAction->GetPlacement(); + m_dsDevilState = DS_JUMPING_INTO_PYRAMID; + call JumpIntoPyramid(); + } + else if( eDevilCommand.dctType == DC_TELEPORT_INTO_PYRAMID) + { + GetModelObject()->PlayAnim( DEVIL_ANIM_IDLE, 0); + m_plTeleport = eDevilCommand.penForcedAction->GetPlacement(); + m_dsDevilState = DS_JUMPING_INTO_PYRAMID; + call TeleportIntoPyramid(); + } + resume; + } + on (ERegenerationImpuls) : + { + if( cht_bDebugFinalBoss) + { + CPrintF("Main loop, event: Regeneration impulse\n"); + } + m_bRenderElectricity = FALSE; + call RegenerationImpulse(); + resume; + } + on (EHitBySpaceShipBeam) : + { + if( cht_bDebugFinalBoss) + { + CPrintF("Main loop, event: Hit by space ship beam\n"); + } + m_bRenderElectricity = FALSE; + m_tmHitBySpaceShipBeam = _pTimer->CurrentTick(); + call BeamDamage(); + resume; + } + // if dead + on (EDeath eDeath) : { + if( !(GetFlags()&ENF_ALIVE)) + { + resume; + } + + if( cht_bDebugFinalBoss) + { + CPrintF("Main loop, event: Death\n"); + } + // die + m_bRenderElectricity = FALSE; + jump CEnemyBase::Die(eDeath); + } + on (EReturn) : + { + if( cht_bDebugFinalBoss) + { + CPrintF("Main loop, event: Return\n"); + } + if( m_dsDevilState==DS_DESTROYING_CITY) + { + m_soSound.Set3DParameters(1000.0f, 500.0f, 2.0f, 1.0f); + m_dsDevilState = DS_ENEMY; + if( m_dapAttackPower == DAP_NOT_ATTACKING) + { + m_dapAttackPower = DAP_PLAYER_HUNT; + } + } + call ContinueInMainLoop(); + resume; + } + } + }; +}; diff --git a/Sources/Entities/DevilMarker.es b/Sources/Entities/DevilMarker.es new file mode 100644 index 0000000..ae6bc88 --- /dev/null +++ b/Sources/Entities/DevilMarker.es @@ -0,0 +1,155 @@ +338 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; +uses "Entities/Devil"; + +enum DevilActionType { + 0 DAT_NONE "None", + 1 DAT_WALK "Walk", + 2 DAT_RISE "Rise", + 3 DAT_ROAR "Roar", + 4 DAT_PUNCH_LEFT "Punch left - obsolete", + 5 DAT_PUNCH_RIGHT "Punch right - obsolete", + 6 DAT_HIT_GROUND "Hit ground", + 7 DAT_JUMP "Jump", + 8 DAT_WAIT "Wait", + 9 DAT_STOP_DESTROYING "Stop destroying", + 10 DAT_NEXT_ACTION "Next action", + 11 DAT_GRAB_LOWER_WEAPONS "Grab lower weapons", + 12 DAT_STOP_MOVING "Stop moving", + 13 DAT_JUMP_INTO_PYRAMID "Jump into pyramid", + 14 DAT_SMASH_LEFT "Smash left - obsolete", + 15 DAT_SMASH_RIGHT "Smash right - obsolete", + 16 DAT_PUNCH "Punch", + 17 DAT_SMASH "Smash", + 18 DAT_FORCE_ATTACK_RADIUS "Force attack radius", + 19 DAT_TELEPORT_INTO_PYRAMID "Teleport into pyramid", + 20 DAT_DECREASE_ATTACK_RADIUS "Decrease attack radius", +}; + +class CDevilMarker: CMarker { +name "Devil Marker"; +thumbnail "Thumbnails\\EnemyMarker.tbn"; + +properties: + 1 enum DevilActionType m_datType "Action" 'A' = DAT_NONE, + 4 INDEX m_iWaitIdles "Wait idles" 'W' = 2, + 5 CEntityPointer m_penDevil "Devil" 'D', + 6 CEntityPointer m_penTrigger "Trigger" 'G', + 7 CEntityPointer m_penToDestroy1 "Destroy target 1" 'E', + 8 CEntityPointer m_penToDestroy2 "Destroy target 2" 'R', + 9 RANGE m_fAttackRadius "Attack radius" 'S' = 100.0f, + +components: + 1 model MODEL_MARKER "Models\\Editor\\EnemyMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\DevilMarker.tex" + +functions: + void SetDefaultName(void) + { + m_strName = DevilActionType_enum.NameForValue(INDEX(m_datType)); + } + + const CTString &GetDescription(void) const { + CTString strAction = DevilActionType_enum.NameForValue(INDEX(m_datType)); + if (m_penTarget==NULL) { + ((CTString&)m_strDescription).PrintF("%s (%s)->",(const char*) m_strName,(const char*) strAction); + } else { + ((CTString&)m_strDescription).PrintF("%s (%s)->%s",(const char*) m_strName,(const char*) strAction, + (const char*) m_penTarget->GetName()); + } + return m_strDescription; + } + + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\DevilMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if (ee.ee_slEvent==EVENTCODE_ETrigger) + { + if(m_datType==DAT_NEXT_ACTION && m_penDevil!=NULL && m_penTarget!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_FORCE_ACTION; + eDevilCommand.penForcedAction = m_penTarget; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + else if(m_datType==DAT_GRAB_LOWER_WEAPONS && m_penDevil!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_GRAB_LOWER_WEAPONS; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + else if(m_datType==DAT_STOP_MOVING && m_penDevil!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_STOP_MOVING; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + else if(m_datType==DAT_JUMP_INTO_PYRAMID && m_penDevil!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_JUMP_INTO_PYRAMID; + eDevilCommand.penForcedAction = this; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + else if(m_datType==DAT_TELEPORT_INTO_PYRAMID && m_penDevil!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_TELEPORT_INTO_PYRAMID; + eDevilCommand.penForcedAction = this; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + else if(m_datType==DAT_FORCE_ATTACK_RADIUS && m_penDevil!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_FORCE_ATTACK_RADIUS; + eDevilCommand.fAttackRadius = m_fAttackRadius; + eDevilCommand.vCenterOfAttack = GetPlacement().pl_PositionVector; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + else if(m_datType==DAT_DECREASE_ATTACK_RADIUS && m_penDevil!=NULL) + { + EDevilCommand eDevilCommand; + eDevilCommand.dctType = DC_DECREASE_ATTACK_RADIUS; + m_penDevil->SendEvent(eDevilCommand); + return TRUE; + } + } + return FALSE; + } + +procedures: + Main() { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + SetDefaultName(); + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + return; + } +}; + diff --git a/Sources/Entities/DevilProjectile.es b/Sources/Entities/DevilProjectile.es new file mode 100644 index 0000000..261bed9 --- /dev/null +++ b/Sources/Entities/DevilProjectile.es @@ -0,0 +1,270 @@ +511 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/BasicEffects"; +uses "Entities/Light"; + +// input parameter for launching the projectile +event EDevilProjectile { + CEntityPointer penLauncher, // who launched it + CEntityPointer penTarget, // target entity +}; + + +%{ +#define FLY_TIME 15.0f +#define ROTATE_SPEED 200.0f +#define MOVING_SPEED 30.0f +#define MOVING_FREQUENCY 0.1f +%} + + +class CDevilProjectile : CMovableModelEntity { +name "Devil projectile"; +thumbnail ""; + +properties: + 1 CEntityPointer m_penLauncher, // who lanuched it + 2 CEntityPointer m_penTarget, // target entity + + 10 FLOAT m_fIgnoreTime = 0.0f, // time when laucher will be ignored + 11 FLOAT m_fStartTime = 0.0f, // start time when launched + 12 FLOAT3D m_vDesiredAngle = FLOAT3D(0,0,0), + 13 BOOL m_bFly = FALSE, + + 20 CSoundObject m_soEffect, // sound channel + +{ + CLightSource m_lsLightSource; +} + +components: + 1 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 2 class CLASS_LIGHT "Classes\\Light.ecl", + +// ********* PLAYER ROCKET ********* + 10 model MODEL_FLARE "Models\\Enemies\\Devil\\Flare.mdl", + 11 texture TEXTURE_FLARE "Models\\Enemies\\Devil\\12.tex", + + +functions: + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CMovableModelEntity::Read_t(istr); + // setup light source + SetupLightSource(); + }; + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + }; + + // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 0.0f; + lsNew.ls_colColor = RGBToColor(0, 128, 128); + lsNew.ls_rFallOff = 5.0f; + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + }; + + + +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + // calculate rotation + void CalcHeadingRotation(ANGLE aWantedHeadingRelative, ANGLE &aRotation) { + // normalize it to [-180,+180] degrees + aWantedHeadingRelative = NormalizeAngle(aWantedHeadingRelative); + + // if desired position is left + if (aWantedHeadingRelative < -ROTATE_SPEED*MOVING_FREQUENCY) { + // start turning left + aRotation = -ROTATE_SPEED; + // if desired position is right + } else if (aWantedHeadingRelative > ROTATE_SPEED*MOVING_FREQUENCY) { + // start turning right + aRotation = +ROTATE_SPEED; + // if desired position is more-less ahead + } else { + aRotation = aWantedHeadingRelative/MOVING_FREQUENCY; + } + }; + + // calculate angle from position + void CalcAngleFromPosition() { + // target enemy body + FLOAT3D vTarget; +/* EntityInfo *peiTarget = (EntityInfo*) (m_penTarget->GetEntityInfo()); + GetEntityInfoPosition(m_penTarget, peiTarget->vTargetCenter, vTarget);*/ + vTarget = m_penTarget->GetPlacement().pl_PositionVector; + vTarget += FLOAT3D(m_penTarget->en_mRotation(1, 2), + m_penTarget->en_mRotation(2, 2), + m_penTarget->en_mRotation(3, 2)) * 2.0f; + + // find relative orientation towards the desired position + m_vDesiredAngle = (vTarget - GetPlacement().pl_PositionVector).Normalize(); + }; + + // rotate entity to desired angle + void RotateToAngle() { + // find relative heading towards the desired angle + ANGLE aRotation; + CalcHeadingRotation(GetRelativeHeading(m_vDesiredAngle), aRotation); + + // start rotating + SetDesiredRotation(ANGLE3D(aRotation, 0, 0)); + }; + + // fly move in direction + void FlyInDirection() { + RotateToAngle(); + + // target enemy body + FLOAT3D vTarget; +/* EntityInfo *peiTarget = (EntityInfo*) (m_penTarget->GetEntityInfo()); + GetEntityInfoPosition(m_penTarget, peiTarget->vTargetCenter, vTarget);*/ + vTarget = m_penTarget->GetPlacement().pl_PositionVector; + vTarget += FLOAT3D(m_penTarget->en_mRotation(1, 2), + m_penTarget->en_mRotation(2, 2), + m_penTarget->en_mRotation(3, 2)) * 2.0f; + + // determine translation speed + FLOAT3D vTranslation = (vTarget - GetPlacement().pl_PositionVector) * !en_mRotation; + vTranslation(1) = 0.0f; + vTranslation.Normalize(); + vTranslation *= MOVING_SPEED; + + // start moving + SetDesiredTranslation(vTranslation); + }; + + // fly entity to desired position + void FlyToPosition() { + CalcAngleFromPosition(); + FlyInDirection(); + }; + + // rotate entity to desired position + void RotateToPosition() { + CalcAngleFromPosition(); + RotateToAngle(); + }; + + // stop moving entity + void StopMoving() { + StopRotating(); + StopTranslating(); + }; + + // stop rotating entity + void StopRotating() { + SetDesiredRotation(ANGLE3D(0, 0, 0)); + }; + + // stop translating + void StopTranslating() { + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + }; + + + +/************************************************************ + * C O M M O N F U N C T I O N S * + ************************************************************/ + void ProjectileTouch(CEntityPointer penHit) { + // direct damage + FLOAT3D vDirection; + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, vDirection); + InflictDirectDamage(penHit, m_penLauncher, DMT_PROJECTILE, 15.0f, + GetPlacement().pl_PositionVector, vDirection); + }; + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + Fly(EVoid) { + // bounce loop + m_bFly = TRUE; + while(m_bFly && m_fStartTime+FLY_TIME > _pTimer->CurrentTick()) { + wait(0.1f) { + on (EBegin) : { + FlyToPosition(); + resume; + } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // ignore twister + bHit &= !IsOfClass(epass.penOther, "Twister"); + if (bHit) { + ProjectileTouch(epass.penOther); + m_bFly = FALSE; + stop; + } + resume; + } + on (ETouch etouch) : { + // clear time limit for launcher + m_fIgnoreTime = 0.0f; + resume; + } + on (ETimer) : { stop; } + } + } + return EEnd(); + }; + + // --->>> MAIN + Main(EDevilProjectile eLaunch) { + // remember the initial parameters + ASSERT(eLaunch.penLauncher!=NULL); + ASSERT(eLaunch.penTarget!=NULL); + m_penLauncher = eLaunch.penLauncher; + m_penTarget = eLaunch.penTarget; + + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetModel(MODEL_FLARE); + SetModelMainTexture(TEXTURE_FLARE); + + // setup light source + SetupLightSource(); + + // remember lauching time + m_fIgnoreTime = _pTimer->CurrentTick() + 1.0f; + + // fly + m_fStartTime = _pTimer->CurrentTick(); + autocall Fly() EEnd; + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/DoorController.es b/Sources/Entities/DoorController.es new file mode 100644 index 0000000..e0a1b6c --- /dev/null +++ b/Sources/Entities/DoorController.es @@ -0,0 +1,334 @@ +221 +%{ +#include "Entities/StdH/StdH.h" +#include +%} + +uses "Entities/KeyItem"; +uses "Entities/Player"; + +enum DoorType { + 0 DT_AUTO "Auto", // opens automatically + 1 DT_TRIGGERED "Triggered", // opens when triggered + 2 DT_LOCKED "Locked", // requires a key + 3 DT_TRIGGEREDAUTO "Triggered Auto", // opens automatically after being triggered +}; + +class CDoorController : CRationalEntity { +name "DoorController"; +thumbnail "Thumbnails\\DoorController.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "DoorController", + 2 CTString m_strDescription = "", + 3 CEntityPointer m_penTarget1 "Target1" 'T' COLOR(C_MAGENTA|0xFF), + 4 CEntityPointer m_penTarget2 "Target2" COLOR(C_MAGENTA|0xFF), + 5 FLOAT m_fWidth "Width" 'W' = 2.0f, + 6 FLOAT m_fHeight "Height" 'H' = 3.0f, + 7 BOOL m_bPlayersOnly "Players Only" 'P' = TRUE, + 8 enum DoorType m_dtType "Type" 'Y' = DT_AUTO, + 9 CTStringTrans m_strLockedMessage "Locked message" 'L' = "", + 13 CEntityPointer m_penLockedTarget "Locked target" COLOR(C_dMAGENTA|0xFF), // target to trigger when locked + 12 enum KeyItemType m_kitKey "Key" 'K' = KIT_ANKHWOOD, // key type (for locked door) + 14 BOOL m_bTriggerOnAnything "Trigger on anything" = FALSE, + 15 BOOL m_bActive "Active" 'A' = TRUE, // automatic door function can be activated/deactivated + + 10 BOOL m_bLocked = FALSE, // for lock/unlock door + 11 CEntityPointer m_penCaused, // for trigger relaying + +components: + 1 model MODEL_DOORCONTROLLER "Models\\Editor\\DoorController.mdl", + 2 texture TEXTURE_DOORCONTROLLER "Models\\Editor\\DoorController.tex", + +functions: + CEntity *GetTarget(void) const { return m_penTarget1; }; + + const CTString &GetDescription(void) const { + if (m_penTarget1!=NULL && m_penTarget2!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s,%s", + (const char*) m_penTarget1->GetName(),(const char*) m_penTarget2->GetName()); + } else if (m_penTarget1!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s", + (const char*) m_penTarget1->GetName()); + } else { + ((CTString&)m_strDescription).PrintF("->"); + } + return m_strDescription; + } + + // test if this door reacts on this entity + BOOL CanReactOnEntity(CEntity *pen) + { + if (pen==NULL) { + return FALSE; + } + // never react on non-live or dead entities + if (!(pen->GetFlags()&ENF_ALIVE)) { + return FALSE; + } + + if (m_bPlayersOnly && !IsDerivedFromClass(pen, "Player")) { + return FALSE; + } + + return TRUE; + } + + // test if this door can be triggered by this entity + BOOL CanTriggerOnEntity(CEntity *pen) + { + return m_bTriggerOnAnything || CanReactOnEntity(pen); + } + + void TriggerDoor(void) + { + if (m_penTarget1!=NULL) { + SendToTarget(m_penTarget1, EET_TRIGGER, m_penCaused); + } + if (m_penTarget2!=NULL) { + SendToTarget(m_penTarget2, EET_TRIGGER, m_penCaused); + } + } + + // apply mirror and stretch to the entity + void MirrorAndStretch(FLOAT fStretch, BOOL bMirrorX) + { + // stretch its ranges + m_fWidth*=fStretch; + m_fHeight*=fStretch; + } + +procedures: + + // entry point for automatic functioning + DoorAuto() + { + // go into active or inactive state + if (m_bActive) { + jump DoorAutoActive(); + } else { + jump DoorAutoInactive(); + } + } + + // automatic door active state + DoorAutoActive() + { + ASSERT(m_bActive); + while (TRUE) { + // wait + wait() { + // when someone enters + on (EPass ePass) : { + // if he can open the door + if (CanReactOnEntity(ePass.penOther)) { + // do it + m_penCaused = ePass.penOther; + TriggerDoor(); + + // this is a very ugly fix for cooperative not finishing in the demo level + // remove this when not needed any more!!!! + if(_SE_DEMO && GetSP()->sp_bCooperative && !GetSP()->sp_bSinglePlayer) { + if (m_strName=="Appear gold amon") { + CPlayer *penPlayer = (CPlayer*)&*ePass.penOther; + penPlayer->SetGameEnd(); + } + } + + resume; + } + resume; + } + // if door is deactivated + on (EDeactivate) : { + // go to inactive state + m_bActive = FALSE; + jump DoorAutoInactive(); + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } + + // automatic door inactive state + DoorAutoInactive() + { + ASSERT(!m_bActive); + while (TRUE) { + // wait + wait() { + // if door is activated + on (EActivate) : { + // go to active state + m_bActive = TRUE; + jump DoorAutoActive(); + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } + + // door when do not function anymore + DoorDummy() + { + wait() { + on (EBegin) : { + resume; + } + otherwise() : { + resume; + }; + } + } + + // door that wait to be triggered to open + DoorTriggered() + { + while (TRUE) { + // wait to someone enter + wait() { + on (EPass ePass) : { + if (CanReactOnEntity(ePass.penOther)) { + if (m_strLockedMessage!="") { + PrintCenterMessage(this, ePass.penOther, TranslateConst(m_strLockedMessage), 3.0f, MSS_INFO); + } + if (m_penLockedTarget!=NULL) { + SendToTarget(m_penLockedTarget, EET_TRIGGER, ePass.penOther); + } + resume; + } + } + on (ETrigger eTrigger) : { + m_penCaused = eTrigger.penCaused; + TriggerDoor(); + jump DoorDummy(); + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } + + // door that need a key to be unlocked to open + DoorLocked() + { + while (TRUE) { + // wait to someone enter + wait() { + on (EPass ePass) : { + if (IsDerivedFromClass(ePass.penOther, "Player")) { + CPlayer *penPlayer = (CPlayer*)&*ePass.penOther; + // if he has the key + ULONG ulKey = (1<m_ulKeys&ulKey) { + // use the key + penPlayer->m_ulKeys&=~ulKey; + // open the dook + TriggerDoor(); + + /* + // tell the key bearer that the key was used + CTString strMsg; + strMsg.PrintF(TRANS("%s used"), GetKeyName(m_kitKey)); + PrintCenterMessage(this, ePass.penOther, strMsg, 3.0f, MSS_INFO); + */ + // become automatic door + jump DoorAuto(); + // if he has no key + } else { + if (m_penLockedTarget!=NULL) { + SendToTarget(m_penLockedTarget, EET_TRIGGER, ePass.penOther); + } + } + resume; + } + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } + + // door that need to be triggered to start working automatically + DoorTriggeredAuto() + { + while (TRUE) { + // wait to be triggered + wait() { + on (ETrigger eTrigger) : { + // become auto door + jump DoorAuto(); + } + on (EPass ePass) : { + if (CanReactOnEntity(ePass.penOther)) { + if (m_strLockedMessage!="") { + PrintCenterMessage(this, ePass.penOther, TranslateConst(m_strLockedMessage), 3.0f, MSS_INFO); + } + if (m_penLockedTarget!=NULL) { + SendToTarget(m_penLockedTarget, EET_TRIGGER, ePass.penOther); + } + } + resume; + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } + + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_TOUCHMODEL); + + // set appearance + GetModelObject()->StretchModel(FLOAT3D(m_fWidth, m_fHeight, m_fWidth)); + SetModel(MODEL_DOORCONTROLLER); + SetModelMainTexture(TEXTURE_DOORCONTROLLER); + ModelChangeNotify(); + + // don't start in wed + autowait(0.1f); + + // dispatch to aproppriate loop + switch(m_dtType) { + case DT_AUTO: { + jump DoorAuto(); + } break; + case DT_TRIGGERED: { + jump DoorTriggered(); + } break; + case DT_TRIGGEREDAUTO: { + jump DoorTriggeredAuto(); + } break; + case DT_LOCKED: { + jump DoorLocked(); + } break; + } + } +}; + diff --git a/Sources/Entities/Dragonman.es b/Sources/Entities/Dragonman.es new file mode 100644 index 0000000..59d2301 --- /dev/null +++ b/Sources/Entities/Dragonman.es @@ -0,0 +1,616 @@ +321 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/DragonMan/DragonMan.h" +%} + +uses "Entities/EnemyFly"; +uses "Entities/Projectile"; + +enum DragonmanType { + 0 DT_SOLDIER "Soldier", + 1 DT_SERGEANT "Sergeant", + 2 DT_MONSTER "Monster", +}; + +%{ +// info structure +static EntityInfo eiDragonmanStand1 = { + EIBT_FLESH, 200.0f, + 0.0f, 1.55f, 0.0f, + 0.0f, 1.0f, 0.0f, +}; +static EntityInfo eiDragonmanStand2 = { + EIBT_FLESH, 200.0f*2, + 0.0f, 1.55f*2, 0.0f, + 0.0f, 1.0f*2, 0.0f, +}; +static EntityInfo eiDragonmanStand4 = { + EIBT_FLESH, 200.0f*4, + 0.0f, 1.55f*4, 0.0f, + 0.0f, 1.0f*4, 0.0f, +}; + +static EntityInfo eiDragonmanFly1 = { + EIBT_FLESH, 100.0f*1, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; +static EntityInfo eiDragonmanFly2 = { + EIBT_FLESH, 100.0f*2, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; +static EntityInfo eiDragonmanFly4 = { + EIBT_FLESH, 100.0f*4, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; + +#define FLY_FIRE1 FLOAT3D( 0.0f, 0.25f, -1.5f) +#define GROUND_RIGHT_FIRE1 FLOAT3D( 0.3f, 2.2f, -0.85f) +#define GROUND_LEFT_FIRE1 FLOAT3D(-0.3f, 1.7f, -0.85f) +#define FLAME_AIR1 FLOAT3D( 0.0f, 0.1f, -1.75f) +#define FLAME_GROUND1 FLOAT3D( 0.0f, 2.7f, -0.85f) +%} + + +class CDragonman : CEnemyFly { +name "Dragonman"; +thumbnail "Thumbnails\\Dragonman.tbn"; + +properties: + 1 enum DragonmanType m_EdtType "Character" 'C' = DT_SOLDIER, // type + 2 FLOAT3D m_vFlameSource = FLOAT3D(0,0,0), + 3 CEntityPointer m_penFlame, + 4 BOOL m_bBurnEnemy = FALSE, + 5 FLOAT m_fFireTime = 0.0f, + +components: + 0 class CLASS_BASE "Classes\\EnemyFly.ecl", + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + + 5 model MODEL_DRAGONMAN "Models\\Enemies\\Dragonman\\Dragonman.mdl", + 6 texture TEXTURE_DRAGONMAN1 "Models\\Enemies\\Dragonman\\Dragonman01.tex", + 7 texture TEXTURE_DRAGONMAN2 "Models\\Enemies\\Dragonman\\Dragonman02.tex", + 8 texture TEXTURE_DRAGONMAN3 "Models\\Enemies\\Dragonman\\Dragonman03.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Dragonman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Dragonman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Dragonman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Dragonman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Dragonman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Dragonman\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + if (m_bInAir) { + switch(m_EdtType) { + case DT_SOLDIER: + return &eiDragonmanFly1; + break; + case DT_SERGEANT: + return &eiDragonmanFly2; + break; + case DT_MONSTER: + return &eiDragonmanFly4; + break; + default: { + return &eiDragonmanFly1; + } break; + } + } else { + switch(m_EdtType) { + case DT_SOLDIER: + return &eiDragonmanStand1; + break; + case DT_SERGEANT: + return &eiDragonmanStand2; + break; + case DT_MONSTER: + return &eiDragonmanStand4; + break; + default: { + return &eiDragonmanStand1; + } break; + } + } + }; + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + CEnemyBase::FillEntityStatistics(pes); + switch(m_EdtType) { + case DT_SOLDIER : { pes->es_strName+=" Soldier"; } break; + case DT_SERGEANT : { pes->es_strName+=" Sergeant"; } break; + case DT_MONSTER : { pes->es_strName+=" Monster"; } break; + } + return TRUE; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // woman can't harm woman + if (!IsOfClass(penInflictor, "Dragonman")) { + CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + FLOAT3D GetStretchedVector(const FLOAT3D&v) + { + switch(m_EdtType) { + case DT_SOLDIER: + return v; + break; + case DT_SERGEANT: + return v*2.0f; + break; + case DT_MONSTER: + return v*4.0f; + break; + default: + ASSERT(FALSE); + return v; + } + } + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + if (m_bInAir) { + switch (IRnd()%2) { + case 0: iAnim = DRAGONMAN_ANIM_AIRWOUNDSLIGHT; break; + case 1: iAnim = DRAGONMAN_ANIM_AIRWOUND02CRITICAL; break; + default: ASSERTALWAYS("Dragonman unknown fly damage"); + } + } else { + switch (IRnd()%3) { + case 0: iAnim = DRAGONMAN_ANIM_GROUNDWOUNDCRITICALBACK; break; + case 1: iAnim = DRAGONMAN_ANIM_GROUNDWOUNDCRITICALFRONT; break; + case 2: iAnim = DRAGONMAN_ANIM_GROUNDWOUNDCRITICALBACK2; break; + default: ASSERTALWAYS("Dragonman unknown ground damage"); + } + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + if (m_bInAir) { + iAnim = DRAGONMAN_ANIM_AIRDEATH; + } else { + switch (IRnd()%2) { + case 0: iAnim = DRAGONMAN_ANIM_GROUNDDEATHBACK; break; + case 1: iAnim = DRAGONMAN_ANIM_GROUNDDEATHFRONT; break; + default: ASSERTALWAYS("Dragonman unknown ground death"); + } + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(DRAGONMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + if (m_bInAir) { + StartModelAnim(DRAGONMAN_ANIM_AIRSTANDLOOP, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(DRAGONMAN_ANIM_GROUNDSTANDLOOP, AOF_LOOPING|AOF_NORESTART); + } + }; + void WalkingAnim(void) { + if (m_bInAir) { + StartModelAnim(DRAGONMAN_ANIM_AIRFLYLOOP, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(DRAGONMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) { + if (m_bInAir) { + StartModelAnim(DRAGONMAN_ANIM_AIRFLYLOOP, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(DRAGONMAN_ANIM_GROUNDRUN, AOF_LOOPING|AOF_NORESTART); + } + }; + void RotatingAnim(void) { + if (m_bInAir) { + StartModelAnim(DRAGONMAN_ANIM_AIRFLYLOOP, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(DRAGONMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); + } + }; + FLOAT AirToGroundAnim(void) { + StartModelAnim(DRAGONMAN_ANIM_AIRTOGROUND, 0); + return(GetModelObject()->GetAnimLength(DRAGONMAN_ANIM_AIRTOGROUND)); + }; + FLOAT GroundToAirAnim(void) { + StartModelAnim(DRAGONMAN_ANIM_GROUNDTOAIR, 0); + return(GetModelObject()->GetAnimLength(DRAGONMAN_ANIM_GROUNDTOAIR)); + }; + void ChangeCollisionToAir() { + ChangeCollisionBoxIndexWhenPossible(DRAGONMAN_COLLISION_BOX_AIR); + }; + void ChangeCollisionToGround() { + ChangeCollisionBoxIndexWhenPossible(DRAGONMAN_COLLISION_BOX_GROUND); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + // flame source + void GetFlamerSourcePlacement(CPlacement3D &plFlame) { + plFlame.pl_PositionVector = m_vFlameSource; + }; + + // fire flame + void FireFlame(void) { + FLOAT3D vFlamePos; + if (m_bInAir) { + vFlamePos = GetStretchedVector(FLAME_AIR1); + } else { + vFlamePos = GetStretchedVector(FLAME_GROUND1); + } + + // create flame + CEntityPointer penFlame = ShootProjectile(PRT_FLAME, vFlamePos, ANGLE3D(0, 0, 0)); + // link last flame with this one (if not NULL or deleted) + if (m_penFlame!=NULL && !(m_penFlame->GetFlags()&ENF_DELETED)) { + ((CProjectile&)*m_penFlame).m_penParticles = penFlame; + } + // link to player weapons + ((CProjectile&)*penFlame).m_penParticles = this; + // store last flame + m_penFlame = penFlame; + // flame source position + m_vFlameSource = GetPlacement().pl_PositionVector + vFlamePos*GetRotationMatrix(); + }; + + +procedures: +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + BeWounded(EDamage eDamage) : CEnemyFly::BeWounded { + m_penFlame = NULL; + jump CEnemyFly::BeWounded(eDamage); + }; + + + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + FlyFire(EVoid) : CEnemyFly::FlyFire { + // fire projectile + StartModelAnim(DRAGONMAN_ANIM_AIRATTACK02, 0); + autowait(0.4f); + if (m_EdtType != DT_MONSTER) { + ShootProjectile(PRT_DRAGONMAN_FIRE, GetStretchedVector(FLY_FIRE1), ANGLE3D(0, 0, 0)); + } else { + ShootProjectile(PRT_DRAGONMAN_STRONG_FIRE, GetStretchedVector(FLY_FIRE1), ANGLE3D(0, 0, 0)); + } + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.15f); + if (m_EdtType != DT_MONSTER) { + ShootProjectile(PRT_DRAGONMAN_FIRE, GetStretchedVector(FLY_FIRE1), ANGLE3D(0, 0, 0)); + } else if (m_EdtType == DT_MONSTER) { + ShootProjectile(PRT_DRAGONMAN_STRONG_FIRE, GetStretchedVector(FLY_FIRE1), ANGLE3D(0, 0, 0)); + } + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.85f); +/* StandingAnim(); + autowait(FRnd() + _pTimer->TickQuantum); + */ + + return EReturn(); + }; + + FlyHit(EVoid) : CEnemyFly::FlyHit { + // fly + if (CalcDist(m_penEnemy) <= 7.5f) { + if (m_EdtType == DT_SOLDIER) { + jump FlyOnEnemy(); + } else { + jump FlyBurn(); + } + } + + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + }; + + FlyOnEnemy(EVoid) { + StartModelAnim(DRAGONMAN_ANIM_AIRATTACKCLOSELOOP, 0); + + // jump + FLOAT3D vDir = PlayerDestinationPos(); + vDir = (vDir - GetPlacement().pl_PositionVector).Normalize(); + vDir *= !GetRotationMatrix(); + vDir *= m_fFlyCloseRunSpeed*1.9f; + SetDesiredTranslation(vDir); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + + // animation - IGNORE DAMAGE WOUND - + SpawnReminder(this, 0.9f, 0); + m_iChargeHitAnimation = DRAGONMAN_ANIM_AIRATTACKCLOSELOOP; + if (m_EdtType == DT_SOLDIER) { + m_fChargeHitDamage = 25.0f; + m_fChargeHitSpeed = 15.0f; + } else if (m_EdtType == DT_SERGEANT) { + m_fChargeHitDamage = 30.0f; + m_fChargeHitSpeed = 20.0f; + } else if (TRUE) { + m_fChargeHitDamage = 30.0f; + m_fChargeHitSpeed = 20.0f; + } + m_fChargeHitAngle = 0.0f; + autocall CEnemyBase::ChargeHitEnemy() EReturn; + + StandingAnim(); + autowait(0.3f); + return EReturn(); + }; + + FlyBurn(EVoid) { + StartModelAnim(DRAGONMAN_ANIM_AIRATTACK02, 0); + + // burn + m_fFireTime = _pTimer->CurrentTick(); + FireFlame(); + m_bBurnEnemy = TRUE; + PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + while (m_bBurnEnemy) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + // flame + on (EBegin) : { + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + // rotate to enemy + m_aRotateSpeed = 10000.0f; + m_fMoveSpeed = 0.0f; + // flame + FireFlame(); + // stop + if (_pTimer->CurrentTick()-m_fFireTime >= 1.29f) { + m_bBurnEnemy = FALSE; + stop; + } + // adjust direction and speed + ULONG ulFlags = SetDesiredMovement(); + MovementAnimation(ulFlags); + resume; + } + on (ETimer) : { stop; } + } + } + m_soSound.Stop(); + + // link last flame with nothing (if not NULL or deleted) + if (m_penFlame!=NULL && !(m_penFlame->GetFlags()&ENF_DELETED)) { + ((CProjectile&)*m_penFlame).m_penParticles = NULL; + m_penFlame = NULL; + } + + StandingAnim(); + autowait(0.3f); + return EReturn(); + }; + + Fire(EVoid) : CEnemyBase::Fire { + // fire projectile + StartModelAnim(DRAGONMAN_ANIM_GROUNDATTACKCLOSELOOP, 0); + autowait(0.3f); + if (m_EdtType != DT_MONSTER) { + ShootProjectile(PRT_DRAGONMAN_FIRE, GetStretchedVector(GROUND_RIGHT_FIRE1), ANGLE3D(0, 0, 0)); + } else { + ShootProjectile(PRT_DRAGONMAN_STRONG_FIRE, GetStretchedVector(GROUND_RIGHT_FIRE1), ANGLE3D(0, 0, 0)); + } + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.8f); + if (m_EdtType != DT_MONSTER) { + ShootProjectile(PRT_DRAGONMAN_FIRE, GetStretchedVector(GROUND_LEFT_FIRE1), ANGLE3D(0, 0, 0)); + } else if (m_EdtType == DT_MONSTER) { + ShootProjectile(PRT_DRAGONMAN_STRONG_FIRE, GetStretchedVector(GROUND_LEFT_FIRE1), ANGLE3D(0, 0, 0)); + } + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.55f); + StandingAnim(); + autowait(FRnd() + _pTimer->TickQuantum); + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + // burn enemy + if (m_EdtType == DT_SERGEANT && CalcDist(m_penEnemy) <= 6.0f || + m_EdtType == DT_MONSTER && CalcDist(m_penEnemy) <= 20.0f) { + jump BurnEnemy(); + } + + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + }; + + BurnEnemy(EVoid) { + StartModelAnim(DRAGONMAN_ANIM_GROUNDATTACKDISTANT, 0); + + // burn + m_fFireTime = _pTimer->CurrentTick(); + FireFlame(); + m_bBurnEnemy = TRUE; + PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + while (m_bBurnEnemy) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + // flame + on (EBegin) : { + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + // rotate to enemy + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = 10000.0f; + // adjust direction and speed + SetDesiredMovement(); + // flame + FireFlame(); + // stop + if (_pTimer->CurrentTick()-m_fFireTime >= 1.29f) { + m_bBurnEnemy = FALSE; + stop; + } + resume; + } + on (ETimer) : { stop; } + } + } + m_soSound.Stop(); + + // link last flame with nothing (if not NULL or deleted) + if (m_penFlame!=NULL && !(m_penFlame->GetFlags()&ENF_DELETED)) { + ((CProjectile&)*m_penFlame).m_penParticles = NULL; + m_penFlame = NULL; + } + + StandingAnim(); + autowait(0.3f); + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + + if (m_EdtType == DT_SOLDIER) { + GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)); + ModelChangeNotify(); + SetHealth(150.0f); + m_fMaxHealth = 150.0f; + m_fDamageWounded = 100.0f; + } else if (m_EdtType == DT_SERGEANT) { + GetModelObject()->StretchModel(FLOAT3D(2.0f, 2.0f, 2.0f)); + ModelChangeNotify(); + SetHealth(450.0f); + m_fMaxHealth = 450.0f; + m_fDamageWounded = 300.0f; + } else if (TRUE) { + GetModelObject()->StretchModel(FLOAT3D(4.0f, 4.0f, 4.0f)); + ModelChangeNotify(); + SetHealth(1350.0f); + m_fMaxHealth = 1350.0f; + m_fDamageWounded = 1000.0f; + } + en_tmMaxHoldBreath = 10.0f; + en_fDensity = 2000.0f; + + // set your appearance + SetModel(MODEL_DRAGONMAN); + if (m_EdtType == DT_SOLDIER) { + SetModelMainTexture(TEXTURE_DRAGONMAN1); + } else if (m_EdtType == DT_SERGEANT) { + SetModelMainTexture(TEXTURE_DRAGONMAN2); + } else if (TRUE) { + SetModelMainTexture(TEXTURE_DRAGONMAN3); + } + // setup moving speed + if (m_EdtType == DT_SOLDIER) { + m_fWalkSpeed = FRnd()*1.5f + 2.5f; + m_aWalkRotateSpeed = FRnd()*20.0f + 50.0f; + m_fAttackRunSpeed = FRnd()*2.0f + 11.0f; + m_aAttackRotateSpeed = FRnd()*75 + 350.0f; + m_fCloseRunSpeed = FRnd()*2.0f + 6.0f; + m_aCloseRotateSpeed = FRnd()*50 + 500.0f; + } else if (m_EdtType == DT_SERGEANT) { + m_fWalkSpeed = (FRnd()*1.5f + 2.5f)*1.5f; + m_aWalkRotateSpeed = FRnd()*20.0f + 50.0f; + m_fAttackRunSpeed = (FRnd()*2.0f + 11.0f)*2; + m_aAttackRotateSpeed = FRnd()*75 + 350.0f; + m_fCloseRunSpeed = (FRnd()*2.0f + 6.0f)*1.5f; + m_aCloseRotateSpeed = FRnd()*50 + 500.0f; + } else if (TRUE) { + m_fWalkSpeed = (FRnd()*1.5f + 2.5f)*2; + m_aWalkRotateSpeed = FRnd()*20.0f + 50.0f; + m_fAttackRunSpeed = (FRnd()*2.0f + 11.0f)*4; + m_aAttackRotateSpeed = FRnd()*75 + 350.0f; + m_fCloseRunSpeed = (FRnd()*2.0f + 6.0f)*2; + m_aCloseRotateSpeed = FRnd()*50 + 500.0f; + } + // setup attack distances + m_fAttackDistance = 100.0f; + if (m_EdtType == DT_SOLDIER) { + m_fCloseDistance = 0.0f; + m_fStopDistance = 10.0f; + m_fFlyCloseDistance = 12.5f; + m_fFlyStopDistance = 0.0f; + m_iScore = 1000; + } else if (m_EdtType == DT_SERGEANT) { + m_fCloseDistance = 20.0f; + m_fStopDistance = 0.0f; + m_fFlyCloseDistance = 12.5f*2; + m_fFlyStopDistance = 0.0f; + m_iScore = 2000; + } else { + m_fCloseDistance = 40.0f; + m_fStopDistance = 0.0f; + m_fFlyCloseDistance = 12.5f*4; + m_fFlyStopDistance = 0.0f; + m_iScore = 10000; + } + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 2.0f; + m_fIgnoreRange = 200.0f; + // fly moving properties + m_fFlyWalkSpeed = FRnd()/2 + 2.0f; + m_aFlyWalkRotateSpeed = FRnd()*10.0f + 50.0f; + m_fFlyAttackRunSpeed = FRnd()*2.0f + 10.0f; + m_aFlyAttackRotateSpeed = FRnd()*75 + 350.0f; + m_fFlyCloseRunSpeed = FRnd()*2.0f + 9.0f; + m_aFlyCloseRotateSpeed = FRnd()*50 + 600.0f; + // attack properties - CAN BE SET + m_fFlyAttackDistance = 100.0f; + m_fFlyAttackFireTime = 3.0f; + m_fFlyCloseFireTime = 2.0f; + m_fFlyIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 100.0f; + m_fBodyParts = 8; + // flame source + m_vFlameSource = FLOAT3D(0, 0, 0); + m_fGroundToAirSpeed = m_fFlyAttackRunSpeed; + m_fAirToGroundSpeed = m_fFlyAttackRunSpeed*2; + m_fAirToGroundMin = 0.1f; + m_fAirToGroundMax = 0.1f; + + // continue behavior in base class + jump CEnemyFly::MainLoop(); + }; +}; diff --git a/Sources/Entities/EffectMarker.es b/Sources/Entities/EffectMarker.es new file mode 100644 index 0000000..9a70665 --- /dev/null +++ b/Sources/Entities/EffectMarker.es @@ -0,0 +1,291 @@ +611 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/Effector.h" +#include "Entities/BackgroundViewer.h" +#include "Entities/WorldSettingsController.h" +%} + +uses "Entities/Marker"; + +enum EffectMarkerType { + 0 EMT_NONE "None", // no FX + 1 EMT_PLAYER_APPEAR "Player appear", // effect of player appearing + 2 EMT_APPEARING_BIG_BLUE_FLARE "Appear big blue flare", // appear big blue flare + 3 EMT_BLEND_MODELS "Blend two models", // blend between two models + 4 EMT_DISAPPEAR_MODEL "Disappear model", // disappear model + 5 EMT_APPEAR_MODEL "Appear model", // appear model + 6 EMT_HIDE_ENTITY "Hide entity", // hide entity + 7 EMT_SHOW_ENTITY "Show entity", // show entity + 8 EMT_SHAKE_IT_BABY "Shake it baby", // earth quaker + 9 EMT_APPEAR_DISAPPEAR "Appear or Disappear model", // appear/disappear model +}; + +class CEffectMarker: CMarker +{ +name "Effect Marker"; +thumbnail "Thumbnails\\EffectMarker.tbn"; + +properties: + + 1 enum EffectMarkerType m_emtType "Effect type" 'Y' = EMT_NONE, // type of effect + 2 CEntityPointer m_penModel "FX Model" 'M', // model holder used in this effect + 3 FLOAT m_tmEffectLife "FX Life time" 'L' = 10.0f, // life time of this effect + 4 CEntityPointer m_penModel2 "FX Model 2" 'O', // second model holder used in this effect + 5 CEntityPointer m_penEffector, // ptr to spawned effector + 6 FLOAT m_fShakeFalloff "Shake fall off" = 250.0f, // ShakeFalloff + 7 FLOAT m_fShakeFade "Shake fade" = 3.0f, // ShakeFade + 8 FLOAT m_fShakeIntensityY "Shake intensity Y" = 0.1f, // ShakeIntensityY + 9 FLOAT m_fShakeFrequencyY "Shake frequency Y" = 5.0f, // ShakeFrequencyY + 10 FLOAT m_fShakeIntensityB "Shake intensity B" = 2.5f, // ShakeIntensityB + 11 FLOAT m_fShakeFrequencyB "Shake frequency B" = 7.2f, // ShakeFrequencyB + 12 FLOAT m_fShakeIntensityZ "Shake intensity Z" = 0.0f, // ShakeIntensityZ + 13 FLOAT m_fShakeFrequencyZ "Shake frequency Z" = 5.0f, // ShakeFrequencyZ + +components: + + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex", + 3 class CLASS_EFFECTOR "Classes\\Effector.ecl", + + +functions: + // Validate offered target for one property + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if(penTarget==NULL) + { + return FALSE; + } + // if should be modelobject + if( slPropertyOffset==offsetof(CEffectMarker, m_penModel) || + slPropertyOffset==offsetof(CEffectMarker, m_penModel2) ) + { + return IsOfClass(penTarget, "ModelHolder2"); + } + return TRUE; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if (ee.ee_slEvent==EVENTCODE_ETrigger) + { + switch(m_emtType) + { + case EMT_SHAKE_IT_BABY: + { + // ---------- Apply shake + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) + { + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + pwsc->m_tmShakeStarted = _pTimer->CurrentTick(); + pwsc->m_vShakePos = GetPlacement().pl_PositionVector; + pwsc->m_fShakeFalloff = m_fShakeFalloff; + pwsc->m_fShakeFade = m_fShakeFade; + pwsc->m_fShakeIntensityZ = m_fShakeIntensityZ; + pwsc->m_tmShakeFrequencyZ = m_fShakeFrequencyZ; + pwsc->m_fShakeIntensityY = m_fShakeIntensityY; + pwsc->m_tmShakeFrequencyY = m_fShakeFrequencyY; + pwsc->m_fShakeIntensityB = m_fShakeIntensityB; + pwsc->m_tmShakeFrequencyB = m_fShakeFrequencyB; + } + break; + } + case EMT_HIDE_ENTITY: + { + if( m_penTarget!=NULL) + { + m_penTarget->SetFlags(m_penTarget->GetFlags()|ENF_HIDDEN); + } + break; + } + case EMT_SHOW_ENTITY: + { + if( m_penTarget!=NULL) + { + m_penTarget->SetFlags(m_penTarget->GetFlags()&~ENF_HIDDEN); + } + break; + } + case EMT_PLAYER_APPEAR: + if( m_penModel!=NULL && IsOfClass(m_penModel, "ModelHolder2") ) + { + CModelObject *pmo = m_penModel->GetModelObject(); + if( pmo != NULL) + { + // spawn effect + CPlacement3D plFX= m_penModel->GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.eetType = ET_PORTAL_LIGHTNING; + eSpawnFX.penModel = m_penModel; + penFX->Initialize( eSpawnFX); + } + } + break; + case EMT_APPEARING_BIG_BLUE_FLARE: + { + // spawn effect + CPlacement3D plFX= GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.fSize = 1.0f; + eSpawnFX.eetType = ET_SIZING_BIG_BLUE_FLARE; + penFX->Initialize( eSpawnFX); + break; + } + case EMT_BLEND_MODELS: + if(m_penModel!=NULL && IsOfClass(m_penModel, "ModelHolder2") && + m_penModel2!=NULL && IsOfClass(m_penModel2, "ModelHolder2") ) + { + if( m_penEffector == NULL) + { + CModelObject *pmo1 = m_penModel->GetModelObject(); + CModelObject *pmo2 = m_penModel2->GetModelObject(); + if( pmo1 != NULL && pmo2 != NULL) + { + // spawn effect + CPlacement3D plFX= m_penModel->GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.eetType = ET_MORPH_MODELS; + eSpawnFX.penModel = m_penModel; + eSpawnFX.penModel2 = m_penModel2; + penFX->Initialize( eSpawnFX); + m_penEffector = penFX; + } + } + else + { + m_penEffector->SendEvent(ETrigger()); + } + } + break; + case EMT_DISAPPEAR_MODEL: + if(m_penModel!=NULL && IsOfClass(m_penModel, "ModelHolder2")) + { + if( m_penEffector == NULL) + { + CModelObject *pmo = m_penModel->GetModelObject(); + if( pmo != NULL) + { + // spawn effect + CPlacement3D plFX= m_penModel->GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.eetType = ET_DISAPPEAR_MODEL; + eSpawnFX.penModel = m_penModel; + penFX->Initialize( eSpawnFX); + m_penEffector = penFX; + } + } + else + { + m_penEffector->SendEvent(ETrigger()); + } + } + break; + case EMT_APPEAR_MODEL: + if(m_penModel!=NULL && IsOfClass(m_penModel, "ModelHolder2")) + { + if( m_penEffector == NULL) + { + CModelObject *pmo = m_penModel->GetModelObject(); + if( pmo != NULL) + { + // spawn effect + CPlacement3D plFX= m_penModel->GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.eetType = ET_APPEAR_MODEL; + eSpawnFX.penModel = m_penModel; + penFX->Initialize( eSpawnFX); + m_penEffector = penFX; + } + } + else + { + m_penEffector->SendEvent(ETrigger()); + } + } + break; + } + } + else if (ee.ee_slEvent==EVENTCODE_EActivate) + { + switch(m_emtType) + { + case EMT_APPEAR_DISAPPEAR: + if(m_penModel!=NULL && IsOfClass(m_penModel, "ModelHolder2")) + { + CModelObject *pmo = m_penModel->GetModelObject(); + if( pmo != NULL) + { + // spawn effect + CPlacement3D plFX= m_penModel->GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.eetType = ET_APPEAR_MODEL_NOW; + eSpawnFX.penModel = m_penModel; + penFX->Initialize( eSpawnFX); + m_penEffector = penFX; + } + } + break; + } + } + else if (ee.ee_slEvent==EVENTCODE_EDeactivate) + { + switch(m_emtType) + { + case EMT_APPEAR_DISAPPEAR: + if(m_penModel!=NULL && IsOfClass(m_penModel, "ModelHolder2")) + { + CModelObject *pmo = m_penModel->GetModelObject(); + if( pmo != NULL) + { + // spawn effect + CPlacement3D plFX= m_penModel->GetPlacement(); + CEntity *penFX = CreateEntity( plFX, CLASS_EFFECTOR); + ESpawnEffector eSpawnFX; + eSpawnFX.tmLifeTime = m_tmEffectLife; + eSpawnFX.eetType = ET_DISAPPEAR_MODEL_NOW; + eSpawnFX.penModel = m_penModel; + penFX->Initialize( eSpawnFX); + m_penEffector = penFX; + } + } + break; + } + } + return FALSE; + } + +procedures: + + Main() + { + // init model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + // reset entity ptr + m_penEffector = NULL; + return; + } +}; + diff --git a/Sources/Entities/Effector.es b/Sources/Entities/Effector.es new file mode 100644 index 0000000..09bcd59 --- /dev/null +++ b/Sources/Entities/Effector.es @@ -0,0 +1,468 @@ +608 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/Effector.h" +#include +%} + +enum EffectorEffectType { + 0 ET_NONE "None", // no particles + 1 ET_DESTROY_OBELISK "Destroy obelisk", // effect of obelisk destroying + 2 ET_DESTROY_PYLON "Destroy pylon", // effect of pylon destroying + 3 ET_HIT_GROUND "Hit ground", // effect of hitting ground + 4 ET_LIGHTNING "Lightning", // lightning effect + 5 ET_SIZING_BIG_BLUE_FLARE "Sizing big blue flare", // sizing big blue flare with reflections effect + 6 ET_SIZING_RING_FLARE "Sizing ring flare", // sizing ringed flare effect + 7 ET_MOVING_RING "Moving ring", // moving ring effect + 8 ET_PORTAL_LIGHTNING "Portal lightnings", // lightnings between portal vertices + 9 ET_MORPH_MODELS "Morph two models", // morph wto models + 10 ET_DISAPPEAR_MODEL "Disappear model", // disappear model + 11 ET_APPEAR_MODEL "Appear model", // appear model + 12 ET_DISAPPEAR_MODEL_NOW "Disappear model now", // disappear model now + 13 ET_APPEAR_MODEL_NOW "Appear model now", // appear model now +}; + +// input parameter for spawning effector +event ESpawnEffector { + enum EffectorEffectType eetType, // type of particles + FLOAT3D vDamageDir, // direction of damage + FLOAT3D vDestination, // FX Destination + FLOAT tmLifeTime, // FX's life period + FLOAT fSize, // misc size + INDEX ctCount, // misc count + CEntityPointer penModel, // ptr to model object used in this effect + CEntityPointer penModel2, // ptr to second model object used in this effect +}; + +%{ +void CEffector_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + switch ((EffectorEffectType)iUser) + { + case ET_MOVING_RING : + pdec->PrecacheModel(MODEL_POWER_RING); + pdec->PrecacheTexture(TEXTURE_POWER_RING); + break; + case ET_DESTROY_OBELISK : + case ET_DESTROY_PYLON : + case ET_HIT_GROUND : + case ET_LIGHTNING : + case ET_SIZING_BIG_BLUE_FLARE : + case ET_SIZING_RING_FLARE : + case ET_PORTAL_LIGHTNING : + case ET_MORPH_MODELS : + case ET_DISAPPEAR_MODEL : + case ET_APPEAR_MODEL : + case ET_DISAPPEAR_MODEL_NOW : + case ET_APPEAR_MODEL_NOW : + // no precaching needed + break; + default: + ASSERT(FALSE); + } +} + +// array for model vertices in absolute space +CStaticStackArray avModelFXVertices; +%} + +class CEffector: CMovableModelEntity { +name "Effector"; +thumbnail ""; +features "ImplementsOnPrecache"; +properties: + + 1 enum EffectorEffectType m_eetType = ET_NONE, // type of effect + 2 FLOAT m_tmStarted = 0.0f, // time when spawned + 3 FLOAT3D m_vDamageDir = FLOAT3D(0,0,0), // direction of damage + 4 FLOAT3D m_vFXDestination = FLOAT3D(0,0,0), // FX destination + 5 FLOAT m_tmLifeTime = 5.0f, // how long effect lives + 6 FLOAT m_fSize = 1.0f, // effect's stretcher + 8 INDEX m_ctCount = 0, // misc count + 10 BOOL m_bLightSource = FALSE, // effect is also light source + 11 CAnimObject m_aoLightAnimation, // light animation object + 12 INDEX m_iLightAnimation = -1, // light animation index + 13 BOOL m_bAlive = TRUE, // if effector is still alive + 14 CEntityPointer m_penModel, // ptr to model object used in this effect + 15 CEntityPointer m_penModel2, // ptr to second model object used in this effect + 16 BOOL m_bWaitTrigger = FALSE, // if effect is activated using trigger + + +{ + CLightSource m_lsLightSource; +} + +components: + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex", + 3 model MODEL_POWER_RING "Models\\CutSequences\\SpaceShip\\PowerRing.mdl", + 4 texture TEXTURE_POWER_RING "Models\\CutSequences\\SpaceShip\\PowerRing.tex" + +functions: + + // calculate life ratio + FLOAT CalculateLifeRatio(FLOAT fFadeInRatio, FLOAT fFadeOutRatio) + { + TIME tmDelta = _pTimer->GetLerpedCurrentTick()-m_tmStarted; + FLOAT fLifeRatio = CalculateRatio( tmDelta, 0, m_tmLifeTime, fFadeInRatio, fFadeOutRatio); + return fLifeRatio; + } + + void AdjustMipFactor(FLOAT &fMipFactor) + { + if (m_eetType==ET_DISAPPEAR_MODEL || m_eetType==ET_DISAPPEAR_MODEL_NOW && m_penModel!=NULL) + { + CModelObject *pmo = m_penModel->GetModelObject(); + TIME tmDelta = _pTimer->GetLerpedCurrentTick()-m_tmStarted; + FLOAT fLifeRatio; + if( m_tmStarted == -1) + { + fLifeRatio = 1.0f; + } + else if( tmDelta>=m_tmLifeTime) + { + fLifeRatio = 0.0f; + } + else + { + fLifeRatio = CalculateLifeRatio(0.0f, 1.0f); + } + UBYTE ubAlpha = UBYTE(255.0f*fLifeRatio); + COLOR col = C_WHITE|ubAlpha; + pmo->mo_colBlendColor = col; + } + if (m_eetType==ET_APPEAR_MODEL || m_eetType==ET_APPEAR_MODEL_NOW && m_penModel!=NULL) + { + CModelObject *pmo = m_penModel->GetModelObject(); + TIME tmDelta = _pTimer->GetLerpedCurrentTick()-m_tmStarted; + FLOAT fLifeRatio; + if( m_tmStarted == -1) + { + fLifeRatio = 0.0f; + } + else if( tmDelta>=m_tmLifeTime) + { + fLifeRatio = 1.0f; + } + else + { + fLifeRatio = CalculateLifeRatio(1.0f, 0.0f); + } + UBYTE ubAlpha = UBYTE(255.0f*fLifeRatio); + COLOR col = C_WHITE|ubAlpha; + pmo->mo_colBlendColor = col; + } + if (m_eetType==ET_MORPH_MODELS && m_penModel!=NULL && m_penModel2!=NULL) + { + CModelObject *pmo1 = m_penModel->GetModelObject(); + CModelObject *pmo2 = m_penModel2->GetModelObject(); + TIME tmDelta = _pTimer->GetLerpedCurrentTick()-m_tmStarted; + FLOAT fLifeRatio; + if( m_tmStarted == -1) + { + fLifeRatio = 0.0f; + } + else if( tmDelta>=m_tmLifeTime) + { + fLifeRatio = 1.0f; + } + else + { + fLifeRatio = CalculateLifeRatio(1.0f, 0.0f); + } + UBYTE ubAlpha1 = UBYTE(255.0f*(1-fLifeRatio)); + UBYTE ubAlpha2 = 255-ubAlpha1; + COLOR col1 = C_WHITE|ubAlpha1; + COLOR col2 = C_WHITE|ubAlpha2; + pmo1->mo_colBlendColor = col1; + pmo2->mo_colBlendColor = col2; + } + } + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + if(m_eetType==ET_MOVING_RING) + { + FLOAT fLifeRatio = CalculateLifeRatio(0.2f, 0.1f); + FLOAT fT = _pTimer->CurrentTick()-m_tmStarted; + FLOAT fPulse = 1.0f; + UBYTE ub = UBYTE (255.0f*fPulse*fLifeRatio); + COLOR col = RGBAToColor(ub,ub,ub,ub); + GetModelObject()->mo_colBlendColor = col; + } + + return FALSE; + } + + void RenderMovingLightnings(void) + { + // calculate life ratio + FLOAT fLifeRatio = CalculateLifeRatio(0.1f, 0.1f); + // fill array with absolute vertices of entity's model and its attached models + m_penModel->GetModelVerticesAbsolute(avModelFXVertices, 0.05f, 0.0f); + const FLOATmatrix3D &m = m_penModel->GetRotationMatrix(); + FLOAT3D vOrigin = m_penModel->GetPlacement().pl_PositionVector; + FLOAT fFXTime = 0.75f; + FLOAT fMaxHeight = 6.0f; + FLOAT fdh = 1.0f; + FLOAT tmDelta = _pTimer->GetLerpedCurrentTick()-m_tmStarted; + FLOAT fY0 = tmDelta; + + for(FLOAT fT=tmDelta; fT>0; fT-=fFXTime) + { + FLOAT fY = fT*2.0f; + if( fY>fMaxHeight) + { + continue; + } + // calculate height ratio + FLOAT fHeightRatio = CalculateRatio( fY, 0, fMaxHeight, 0.1f, 0.0f); + FLOAT fMinY = 1e6f; + FLOAT fMinY2 = -1e6f; + INDEX iLower = -1; + INDEX iUpper = -1; + for( INDEX iVtx=0; iVtxfY && v(2)fMinY2 && v(1)<0) + { + iUpper = iVtx; + fMinY2 = v(2); + } + } + // if we found valid vertex + if( iLower!=-1 && iUpper!=-1) + { + FLOAT3D vRelHi = (avModelFXVertices[iUpper]-vOrigin)*!m; + FLOAT3D vRelLow = (avModelFXVertices[iLower]-vOrigin)*!m; + FLOAT fLerpFactor = (fY-vRelLow(2))/(vRelHi(2)-vRelLow(2)); + FLOAT3D vRel = Lerp(vRelLow, vRelHi, fLerpFactor); + vRel(2) = fY; + FLOAT3D vAbs1 = vOrigin+vRel*m; + vRel(1)=-vRel(1); + FLOAT3D vAbs2 = vOrigin+vRel*m; + // render lightning + Particles_Ghostbuster( vAbs1, vAbs2, 16, 0.325f, fHeightRatio*fLifeRatio, 5.0f); + } + } + avModelFXVertices.Clear(); + } + + // particles + void RenderParticles(void) + { + // calculate ratio + FLOAT fRatio; + TIME tmNow = _pTimer->GetLerpedCurrentTick(); + TIME tmDelta = tmNow - m_tmStarted; + FLOAT fLivingRatio = tmDelta/m_tmLifeTime; + if(fLivingRatio<0.25f) { + fRatio = Clamp( fLivingRatio/0.25f, 0.0f, 1.0f); + } else if(fLivingRatio>0.75f) { + fRatio = Clamp( (-fLivingRatio+1.0f)/0.25f, 0.0f, 1.0f); + } else { + fRatio = 1.0f; + } + + switch( m_eetType) + { + case ET_DESTROY_OBELISK: + Particles_DestroyingObelisk( this, m_tmStarted); + break; + case ET_DESTROY_PYLON: + Particles_DestroyingPylon( this, m_vDamageDir, m_tmStarted); + break; + case ET_HIT_GROUND: + Particles_HitGround( this, m_tmStarted, m_fSize); + break; + case ET_LIGHTNING: + Particles_Ghostbuster(GetPlacement().pl_PositionVector, m_vFXDestination, m_ctCount, m_fSize, fRatio); + break; + case ET_PORTAL_LIGHTNING: + RenderMovingLightnings(); + break; + } + }; + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CMovableModelEntity::Read_t(istr); + // setup light source + if( m_bLightSource) { + SetupLightSource(); + } + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if( m_bLightSource && !IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + // Setup light source + void SetupLightSource(void) + { + if( m_iLightAnimation>=0) + { // set light animation if available + try { + m_aoLightAnimation.SetData_t(CTFILENAME("Animations\\Effector.ani")); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load Animations\\Effector.ani: %s"), strError); + } + // play light animation + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, 0); + } + } + + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_LENSFLAREONLY; + lsNew.ls_rHotSpot = 0.0f; + switch (m_eetType) { + case ET_SIZING_RING_FLARE: + lsNew.ls_colColor = C_WHITE|CT_OPAQUE; + lsNew.ls_rHotSpot = 100.0f; + lsNew.ls_rFallOff = 300.0f; + lsNew.ls_plftLensFlare = &_lftWhiteGlowStarNG; + break; + + case ET_SIZING_BIG_BLUE_FLARE: + lsNew.ls_colColor = C_WHITE|CT_OPAQUE; + lsNew.ls_rHotSpot = 500.0f*m_fSize; + lsNew.ls_rFallOff = 1000.0f*m_fSize; + lsNew.ls_plftLensFlare = &_lftBlueStarBlueReflections; + break; + + default: + ASSERTALWAYS("Unknown light source"); + } + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + // setup light animation + lsNew.ls_paoLightAnimation = NULL; + if (m_aoLightAnimation.GetData()!=NULL) { + lsNew.ls_paoLightAnimation = &m_aoLightAnimation; + } + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } +/************************************************************ + * MAIN * + ************************************************************/ + +procedures: + + Main( ESpawnEffector eSpawn) + { + // set appearance + InitAsEditorModel(); + + SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); + SetCollisionFlags(ECF_TOUCHMODEL); + SetFlags( GetFlags()|ENF_SEETHROUGH); + + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // setup variables + m_eetType = eSpawn.eetType; + m_vDamageDir = eSpawn.vDamageDir; + m_tmStarted = _pTimer->CurrentTick(); + m_tmLifeTime = eSpawn.tmLifeTime; + m_vFXDestination = eSpawn.vDestination; + m_fSize = eSpawn.fSize; + m_ctCount = eSpawn.ctCount; + m_bAlive = TRUE; + m_penModel = eSpawn.penModel; + m_penModel2 = eSpawn.penModel2; + m_bWaitTrigger = FALSE; + + autowait(0.1f); + + if(m_eetType==ET_MOVING_RING) + { + SetModel(MODEL_POWER_RING); + SetModelMainTexture(TEXTURE_POWER_RING); + en_fAcceleration = 1e6f; + FLOAT fSpeed = 550.0f; + SetDesiredTranslation(FLOAT3D(0,-fSpeed,0)); + FLOAT fPathLen = GetPlacement().pl_PositionVector(2)-m_vFXDestination(2); + // t=s/v + m_tmLifeTime = fPathLen/fSpeed; + SwitchToModel(); + FLOAT fSize = 36.0f; + FLOAT3D vStretch = FLOAT3D(fSize, fSize*2.0f, fSize); + GetModelObject()->StretchModel(vStretch); + ModelChangeNotify(); + } + // spetial initializations + if(m_eetType==ET_SIZING_RING_FLARE) + { + m_bLightSource = TRUE; + m_iLightAnimation = 0; + } + if(m_eetType==ET_SIZING_BIG_BLUE_FLARE) + { + m_bLightSource = TRUE; + m_iLightAnimation = 1; + } + if(m_eetType==ET_MORPH_MODELS || m_eetType==ET_DISAPPEAR_MODEL || m_eetType==ET_APPEAR_MODEL) + { + m_bWaitTrigger = TRUE; + m_tmStarted = -1; + } + if(m_eetType==ET_DISAPPEAR_MODEL_NOW || m_eetType==ET_APPEAR_MODEL_NOW) + { + m_bWaitTrigger = FALSE; + m_tmStarted = _pTimer->CurrentTick(); + } + + // setup light source + if (m_bLightSource) { SetupLightSource(); } + + while(_pTimer->CurrentTick()CurrentTick(); + m_bWaitTrigger = FALSE; + // live forever + m_bAlive = TRUE; + } + resume; + } + on( ETimer):{ stop;} + } + // check if moving ring reached target position + if(m_eetType==ET_MOVING_RING) + { + if( GetPlacement().pl_PositionVector(2) < m_vFXDestination(2)) + { + m_bAlive = FALSE; + } + } + } + + Destroy(); + return; + } +}; diff --git a/Sources/Entities/Elemental.es b/Sources/Entities/Elemental.es new file mode 100644 index 0000000..5e6d8a2 --- /dev/null +++ b/Sources/Entities/Elemental.es @@ -0,0 +1,1503 @@ +322 +%{ +#include "Entities/StdH/StdH.h" +//#include "Models/Enemies/Elementals/AirMan.h" +//#include "Models/Enemies/Elementals/IceMan.h" +#include "Models/Enemies/Elementals/Stoneman.h" +//#include "Models/Enemies/Elementals/Twister.h" +//#include "Models/Enemies/Elementals/WaterMan.h" +//#include "Models/Enemies/Elementals/Projectile/IcePyramid.h" +#include "Models/Enemies/Elementals/Projectile/LavaStone.h" + +#include "Models/Enemies/ElementalLava/ElementalLava.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/BackgroundViewer.h" + +// lava elemental definitions +#define LAVAMAN_SMALL_STRETCH (2.0f*0.75f) +#define LAVAMAN_BIG_STRETCH (4.0f*1.25f) +#define LAVAMAN_LARGE_STRETCH (16.0f*2.5f) + +#define LAVAMAN_BOSS_FIRE_RIGHT FLOAT3D(1.01069f, 0.989616f, -1.39743f) +#define LAVAMAN_BOSS_FIRE_LEFT FLOAT3D(-0.39656f, 1.08619f, -1.34373f) +#define LAVAMAN_FIRE_LEFT FLOAT3D(-0.432948f, 1.51133f, -0.476662f) + +#define LAVAMAN_FIRE_SMALL (LAVAMAN_FIRE_LEFT*LAVAMAN_SMALL_STRETCH) +#define LAVAMAN_FIRE_BIG (LAVAMAN_FIRE_LEFT*LAVAMAN_BIG_STRETCH) +#define LAVAMAN_FIRE_LARGE_LEFT (LAVAMAN_BOSS_FIRE_LEFT*LAVAMAN_LARGE_STRETCH) +#define LAVAMAN_FIRE_LARGE_RIGHT (LAVAMAN_BOSS_FIRE_RIGHT*LAVAMAN_LARGE_STRETCH) + +#define LAVAMAN_SPAWN_BIG (FLOAT3D(0.0171274f, 1.78397f, -0.291414f)*LAVAMAN_BIG_STRETCH) +#define LAVAMAN_SPAWN_LARGE (FLOAT3D(0.0171274f, 1.78397f, -0.291414f)*LAVAMAN_LARGE_STRETCH) + +%} + +uses "Entities/EnemyBase"; +//uses "Entities/Twister"; +//uses "Entities/Water"; + +enum ElementalType { + 0 ELT_AIR "obsolete", // air elemental + 1 ELT_ICE "obsolete", // ice elemental + 2 ELT_LAVA "Lava", // lava elemental + 3 ELT_STONE "obsolete", // stone elemental + 4 ELT_WATER "obsolete", // water elemental +}; + + +enum ElementalCharacter { + 0 ELC_SMALL "Small", // small (fighter) + 1 ELC_BIG "Big", // big + 2 ELC_LARGE "Large", // large +}; + + +enum ElementalState { + 0 ELS_NORMAL "Normal", // normal state + 1 ELS_BOX "Box", // in box + 2 ELS_PLANE "Plane", // as plane +}; + + +%{ +#define ECF_AIR ( \ + ((ECBI_BRUSH|ECBI_MODEL|ECBI_CORPSE|ECBI_ITEM|ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID)<es_strName+=" Water"; } break; + case ELT_AIR : { pes->es_strName+=" Air"; } break; + case ELT_STONE : { pes->es_strName+=" Stone"; } break; + case ELT_LAVA : { pes->es_strName+=" Lava"; } break; + case ELT_ICE : { pes->es_strName+=" Ice"; } break; + } + switch(m_EecChar) { + case ELC_LARGE: pes->es_strName+=" Large"; break; + case ELC_BIG: pes->es_strName+=" Big"; break; + case ELC_SMALL: pes->es_strName+=" Small"; break; + } + return TRUE; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // elemental can't harm elemental + if( IsOfClass(penInflictor, "Elemental")) { + return; + } + + // boss can't be telefragged + if( m_EecChar==ELC_LARGE && dmtType==DMT_TELEPORT) + { + return; + } + + INDEX ctShouldSpawn = Clamp( INDEX((m_fMaxHealth-GetHealth())/m_fSpawnDamage), INDEX(0), INDEX(10)); + CTString strChar = ElementalCharacter_enum.NameForValue(INDEX(m_EecChar)); + //CPrintF( "Character: %s, MaxHlt = %g, Hlt = %g, SpwnDmg = %g, Spawned: %d, Should: %d\n", + // strChar, m_fMaxHealth, GetHealth(), m_fSpawnDamage, m_ctSpawned, ctShouldSpawn); + + if (m_bSpawnEnabled && m_bSpawnWhenHarmed && (m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG)) + { + INDEX ctShouldSpawn = Clamp( INDEX((m_fMaxHealth-GetHealth())/m_fSpawnDamage), INDEX(0), INDEX(10)); + if(m_ctSpawned=ctShouldSpawn) + { + return; + } + + CPlacement3D pl; + // spawn placement + if (m_EecChar==ELC_LARGE) { + pl = CPlacement3D(LAVAMAN_SPAWN_LARGE, ANGLE3D(-90.0f+FRnd()*180.0f, 30+FRnd()*30, 0)); + } else { + pl = CPlacement3D(LAVAMAN_SPAWN_BIG, ANGLE3D(-90.0f+FRnd()*180.0f, 40+FRnd()*20, 0)); + } + pl.RelativeToAbsolute(GetPlacement()); + + // create entity + CEntityPointer pen = GetWorld()->CreateEntity(pl, GetClass()); + ((CElemental&)*pen).m_EetType = m_EetType; + // elemental size + if (m_EecChar==ELC_LARGE) { + ((CElemental&)*pen).m_EecChar = ELC_BIG; + } else { + ((CElemental&)*pen).m_EecChar = ELC_SMALL; + } + // start properties + ((CElemental&)*pen).m_EesStartState = ELS_BOX; + ((CElemental&)*pen).m_fDensity = m_fDensity; + ((CElemental&)*pen).m_colColor = m_colColor; + ((CElemental&)*pen).m_penEnemy = m_penEnemy; + ((CElemental&)*pen).m_ttTarget = m_ttTarget; + ((CElemental&)*pen).m_bSpawned = TRUE; + pen->Initialize(EVoid()); + // set moving + if (m_EecChar==ELC_LARGE) { + ((CElemental&)*pen).LaunchAsFreeProjectile(FLOAT3D(0, 0, -40.0f), this); + } else { + ((CElemental&)*pen).LaunchAsFreeProjectile(FLOAT3D(0, 0, -20.0f), this); + } + ((CElemental&)*pen).SetDesiredRotation(ANGLE3D(0, 0, FRnd()*360-180)); + + // spawn particle debris explosion + CEntity *penSpray = CreateEntity( pl, CLASS_BLOOD_SPRAY); + penSpray->SetParent( pen); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 4.0f; + eSpawnSpray.fSizeMultiplier = 0.5f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); + eSpawnSpray.penOwner = pen; + penSpray->Initialize( eSpawnSpray); + m_ctSpawned++; + }; + + // throw rocks + void ThrowRocks(ProjectileType EptProjectile) { + // projectile type and position + FLOAT3D vPos; + ANGLE3D aAngle; + // throw rocks + switch (m_EecChar) { + case ELC_LARGE: { + vPos = FIRE_ROCKS_LARGE; + ShootProjectile(EptProjectile, vPos, ANGLE3D(0, 0, 0)); + aAngle = ANGLE3D(FRnd()*5.0f+5.0f, FRnd()*3.0f-2.0f, 0); + ShootProjectile(EptProjectile, vPos, aAngle); + aAngle = ANGLE3D(FRnd()*-5.0f-5.0f, FRnd()*3.0f-2.0f, 0); + ShootProjectile(EptProjectile, vPos, aAngle); + break; } + case ELC_BIG: { + vPos = FIRE_ROCKS_BIG; + ShootProjectile(EptProjectile, vPos, ANGLE3D(0, 0, 0)); + aAngle = ANGLE3D(FRnd()*4.0f+4.0f, FRnd()*3.0f-2.0f, 0); + ShootProjectile(EptProjectile, vPos, aAngle); + aAngle = ANGLE3D(FRnd()*-4.0f-4.0f, FRnd()*3.0f-2.0f, 0); + ShootProjectile(EptProjectile, vPos, aAngle); + break; } + default: { + vPos = FIRE_ROCKS; + ShootProjectile(EptProjectile, vPos, ANGLE3D(0, 0, 0)); + aAngle = ANGLE3D(FRnd()*3.0f+3.0f, FRnd()*3.0f-2.0f, 0); + ShootProjectile(EptProjectile, vPos, aAngle); + aAngle = ANGLE3D(FRnd()*-3.0f-3.0f, FRnd()*3.0f-2.0f, 0); + ShootProjectile(EptProjectile, vPos, aAngle); + } + } + }; + + void BossFirePredictedLavaRock(FLOAT3D vFireingRel) + { + FLOAT3D vShooting = GetPlacement().pl_PositionVector+vFireingRel*GetRotationMatrix(); + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vSpeedDest = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute; + FLOAT fLaunchSpeed; + FLOAT fRelativeHdg; + + FLOAT fDistanceFactor = ClampUp( (vShooting-vTarget).Length()/150.0f, 1.0f)-0.75f; + FLOAT fPitch = fDistanceFactor*45.0f; + + // calculate parameters for predicted angular launch curve + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + CalculateAngularLaunchParams( vShooting, peiTarget->vTargetCenter[1]-6.0f/3.0f, vTarget, + vSpeedDest, fPitch, fLaunchSpeed, fRelativeHdg); + + // target enemy body + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + // launch + CPlacement3D pl; + PrepareFreeFlyingProjectile(pl, vShootTarget, vFireingRel, ANGLE3D( fRelativeHdg, fPitch, 0)); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_LAVAMAN_BIG_BOMB; + eLaunch.fSpeed = fLaunchSpeed; + penProjectile->Initialize(eLaunch); + } + + class CWorldSettingsController *GetWSC(void) + { + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + return pwsc; + } + + /* Shake ground */ + void ShakeItBaby(FLOAT tmShaketime, FLOAT fPower) + { + CWorldSettingsController *pwsc = GetWSC(); + if (pwsc!=NULL) { + pwsc->m_tmShakeStarted = tmShaketime; + pwsc->m_vShakePos = GetPlacement().pl_PositionVector; + pwsc->m_fShakeFalloff = 450.0f; + pwsc->m_fShakeFade = 3.0f; + + pwsc->m_fShakeIntensityZ = 0; + pwsc->m_tmShakeFrequencyZ = 5.0f; + pwsc->m_fShakeIntensityY = 0.1f*fPower; + pwsc->m_tmShakeFrequencyY = 5.0f; + pwsc->m_fShakeIntensityB = 2.5f*fPower; + pwsc->m_tmShakeFrequencyB = 7.2f; + } + } + + // hit ground + void HitGround(void) { + FLOAT3D vSource; + if( m_penEnemy != NULL) + { + vSource = GetPlacement().pl_PositionVector + + FLOAT3D(m_penEnemy->en_mRotation(1, 2), m_penEnemy->en_mRotation(2, 2), m_penEnemy->en_mRotation(3, 2)); + } + else + { + vSource = GetPlacement().pl_PositionVector; + } + + // damage + if (m_EecChar==ELC_LARGE) { + InflictRangeDamage(this, DMT_IMPACT, 150.0f, vSource, 7.5f, m_fCloseDistance); + ShakeItBaby(_pTimer->CurrentTick(), 5.0f); + } else if (m_EecChar==ELC_BIG) { + InflictRangeDamage(this, DMT_IMPACT, 75.0f, vSource, 5.0f, m_fCloseDistance); + ShakeItBaby(_pTimer->CurrentTick(), 2.0f); + } else { + InflictRangeDamage(this, DMT_IMPACT, 25.0f, vSource, 2.5f, m_fCloseDistance); + } + }; + + // fire water +/* void FireWater(void) { + // target enemy body + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + + // water projectile + CPlacement3D pl; + EWater ew; + ew.penLauncher = this; + if (m_EecChar==ELC_LARGE) { + ew.EwsSize = WTS_LARGE; + // launch + PreparePropelledProjectile(pl, vShootTarget, WATER_LARGE_LEFT, ANGLE3D(0, 0, 0)); + CEntityPointer penWater = CreateEntity(pl, CLASS_WATER); + penWater->Initialize(ew); + // launch + PreparePropelledProjectile(pl, vShootTarget, WATER_LARGE_RIGHT, ANGLE3D(0, 0, 0)); + penWater = CreateEntity(pl, CLASS_WATER); + penWater->Initialize(ew); + } else if (m_EecChar==ELC_BIG) { + ew.EwsSize = WTS_BIG; + // launch + PreparePropelledProjectile(pl, vShootTarget, WATER_BIG_LEFT, ANGLE3D(0, 0, 0)); + CEntityPointer penWater = CreateEntity(pl, CLASS_WATER); + penWater->Initialize(ew); + // launch + PreparePropelledProjectile(pl, vShootTarget, WATER_BIG_RIGHT, ANGLE3D(0, 0, 0)); + penWater = CreateEntity(pl, CLASS_WATER); + penWater->Initialize(ew); + } else { + ew.EwsSize = WTS_SMALL; + // launch + PreparePropelledProjectile(pl, vShootTarget, WATER_LEFT, ANGLE3D(0, 0, 0)); + CEntityPointer penWater = CreateEntity(pl, CLASS_WATER); + penWater->Initialize(ew); + // launch + PreparePropelledProjectile(pl, vShootTarget, WATER_RIGHT, ANGLE3D(0, 0, 0)); + penWater = CreateEntity(pl, CLASS_WATER); + penWater->Initialize(ew); + } + }; +*/ + + // add attachments + void AddAttachments(void) { + switch (m_EetType) { +/* case ELT_AIR: + if (GetModelObject()->GetAttachmentModel(AIRMAN_ATTACHMENT_TWISTER)==NULL) { + AddAttachmentToModel(this, *GetModelObject(), AIRMAN_ATTACHMENT_TWISTER, + MODEL_AIR_TWISTER, TEXTURE_AIR, 0, 0, 0); + GetModelObject()->mo_ColorMask &= ~AIRMAN_PART_BODYDOWN; + } + break; + case ELT_ICE: + if (GetModelObject()->GetAttachmentModel(ICEMAN_ATTACHMENT_ICEPICK)==NULL) { + AddAttachmentToModel(this, *GetModelObject(), ICEMAN_ATTACHMENT_ICEPICK, + MODEL_ICE_PICK, TEXTURE_ICE, TEXTURE_ICE, TEX_SPEC_STRONG, 0); + } + break;*/ + case ELT_LAVA: + if (GetModelObject()->GetAttachmentModel(ELEMENTALLAVA_ATTACHMENT_BODY_FLARE)==NULL) { + AddAttachmentToModel(this, *GetModelObject(), ELEMENTALLAVA_ATTACHMENT_BODY_FLARE, MODEL_LAVA_BODY_FLARE, TEXTURE_LAVA_FLARE, 0, 0, 0); + AddAttachmentToModel(this, *GetModelObject(), ELEMENTALLAVA_ATTACHMENT_RIGHT_HAND_FLARE, MODEL_LAVA_HAND_FLARE, TEXTURE_LAVA_FLARE, 0, 0, 0); + AddAttachmentToModel(this, *GetModelObject(), ELEMENTALLAVA_ATTACHMENT_LEFT_HAND_FLARE, MODEL_LAVA_HAND_FLARE, TEXTURE_LAVA_FLARE, 0, 0, 0); + } + break; +/* case ELT_STONE: + if (GetModelObject()->GetAttachmentModel(STONEMAN_ATTACHMENT_MAUL)==NULL) { + AddAttachmentToModel(this, *GetModelObject(), STONEMAN_ATTACHMENT_MAUL, + MODEL_STONE_MAUL, TEXTURE_STONE, 0, 0, 0); + } + break; + case ELT_WATER: + if (GetModelObject()->GetAttachmentModel(WATERMAN_ATTACHMENT_BODY_FLARE)==NULL) { + AddAttachmentToModel(this, *GetModelObject(), WATERMAN_ATTACHMENT_BODY_FLARE, + MODEL_WATER_BODY_FLARE, TEXTURE_WATER_FLARE, 0, 0, 0); + } + break;*/ + } + GetModelObject()->StretchModel(GetModelObject()->mo_Stretch); + ModelChangeNotify(); + }; + + // remove attachments + void RemoveAttachments(void) { + switch (m_EetType) { +/* case ELT_AIR: + RemoveAttachmentFromModel(*GetModelObject(), AIRMAN_ATTACHMENT_TWISTER); + GetModelObject()->mo_ColorMask |= AIRMAN_PART_BODYDOWN; + break; + case ELT_ICE: + RemoveAttachmentFromModel(*GetModelObject(), ICEMAN_ATTACHMENT_ICEPICK); + break;*/ + case ELT_LAVA: + RemoveAttachmentFromModel(*GetModelObject(), ELEMENTALLAVA_ATTACHMENT_BODY_FLARE); + RemoveAttachmentFromModel(*GetModelObject(), ELEMENTALLAVA_ATTACHMENT_RIGHT_HAND_FLARE); + RemoveAttachmentFromModel(*GetModelObject(), ELEMENTALLAVA_ATTACHMENT_LEFT_HAND_FLARE); + break; +/* case ELT_STONE: + RemoveAttachmentFromModel(*GetModelObject(), STONEMAN_ATTACHMENT_MAUL); + break; + case ELT_WATER: + RemoveAttachmentFromModel(*GetModelObject(), WATERMAN_ATTACHMENT_BODY_FLARE); + break;*/ + } + }; + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + // spawn body parts + void BlowUp(void) { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm()/2; + + INDEX iCount = 1; + switch (m_EecChar) { + case ELC_SMALL: iCount = 3; break; + case ELC_BIG: iCount = 5; break; + case ELC_LARGE: iCount = 7; break; + } + + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + vNormalizedDamage *= 1.75f; + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + + // spawn debris +/* + switch (m_EetType) { + case ELT_ICE: { + Debris_Begin(EIBT_ICE, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); + for (iDebris=0; iDebrisGetModelObject()), ICEPYRAMID_ATTACHMENT_FLARE, + MODEL_ELEM_ICE_FLARE, TEXTURE_ELEM_FLARE, 0, 0, 0); + pen->GetModelObject()->StretchModel(pen->GetModelObject()->mo_Stretch); + ModelChangeNotify(); + }} + break; + case ELT_LAVA: { + Debris_Begin(EIBT_FIRE, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); + for (iDebris=0; iDebrisGetModelObject()), LAVASTONE_ATTACHMENT_FLARE, + MODEL_ELEM_LAVASTONE_FLARE, TEXTURE_ELEM_FLARE, 0, 0, 0); + pen->GetModelObject()->StretchModel(pen->GetModelObject()->mo_Stretch); + ModelChangeNotify(); + }} + break; + case ELT_STONE: { + Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); + for (iDebris=0; iDebrisGetRenderType()&RT_BRUSH) { + // stop waiting + StopMoving(); + stop; + } + resume; + } + otherwise() : { resume; } + } + StartModelAnim(ELEMENTALLAVA_ANIM_MELTUP, 0); + return EReturn(); + }; + + + +/************************************************************ + * FIRE PROCEDURES * + ************************************************************/ + // + // STONEMAN + // +/* StonemanFire(EVoid) { + StartModelAnim(STONEMAN_ANIM_ATTACK05, 0); + autowait(0.7f); + // throw rocks + if (m_EecChar==ELC_LARGE) { + ThrowRocks(PRT_STONEMAN_LARGE_FIRE); + } else if (m_EecChar==ELC_BIG) { + ThrowRocks(PRT_STONEMAN_BIG_FIRE); + } else { + ThrowRocks(PRT_STONEMAN_FIRE); + } + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + autowait(0.9f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + + StonemanHit(EVoid) { + StartModelAnim(STONEMAN_ANIM_ATTACK06, 0); + autowait(0.6f); + HitGround(); + PlaySound(m_soSound, SOUND_LAVA_KICK, SOF_3D); + autowait(0.5f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + */ + + // + // LAVAMAN + // + + LavamanFire(EVoid) + { + m_bSpawnEnabled = TRUE; + // shoot projectiles + if (m_EecChar==ELC_LARGE) + { + CModelObject &mo = *GetModelObject(); + FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKBOSS, AOF_SMOOTHCHANGE); + autowait(tmWait+0.95f); + BossFirePredictedLavaRock(LAVAMAN_FIRE_LARGE_RIGHT); + PlaySound(m_soFireR, SOUND_LAVA_FIRE, SOF_3D); + autowait(2.0150f-0.95f); + BossFirePredictedLavaRock(LAVAMAN_FIRE_LARGE_LEFT); + PlaySound(m_soFireL, SOUND_LAVA_FIRE, SOF_3D); + StartModelAnim(ELEMENTALLAVA_ANIM_WALKBIG, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + MaybeSwitchToAnotherPlayer(); + // set next shoot time + m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/5.0f); + return EReturn(); + } + else if (m_EecChar==ELC_BIG) + { + CModelObject &mo = *GetModelObject(); + FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKLEFTHAND, AOF_SMOOTHCHANGE); + autowait(tmWait+0.90f); + FLOAT3D vShooting = GetPlacement().pl_PositionVector; + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vSpeedDest = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute; + FLOAT fLaunchSpeed; + FLOAT fRelativeHdg; + + FLOAT fPitch = 20.0f; + + // calculate parameters for predicted angular launch curve + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + CalculateAngularLaunchParams( vShooting, LAVAMAN_FIRE_BIG(2)-peiTarget->vTargetCenter[1]-1.5f/3.0f, vTarget, + vSpeedDest, fPitch, fLaunchSpeed, fRelativeHdg); + + // target enemy body + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + // launch + CPlacement3D pl; + PrepareFreeFlyingProjectile(pl, vShootTarget, LAVAMAN_FIRE_BIG, ANGLE3D( fRelativeHdg, fPitch, 0)); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_LAVAMAN_BOMB; + eLaunch.fSpeed = fLaunchSpeed; + penProjectile->Initialize(eLaunch); + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + } + else if (TRUE) + { + CModelObject &mo = *GetModelObject(); + FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKLEFTHAND, AOF_SMOOTHCHANGE); + autowait(tmWait+0.8f); + ShootProjectile(PRT_LAVAMAN_STONE, LAVAMAN_FIRE_SMALL, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + } + + autowait( GetModelObject()->GetAnimLength( ELEMENTALLAVA_ANIM_ATTACKLEFTHAND) - 0.9f); + + StandingAnim(); + autowait(_pTimer->TickQuantum); + + if (m_EecChar!=ELC_SMALL) { + MaybeSwitchToAnotherPlayer(); + } + + // set next shoot time + m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/5.0f); + + return EReturn(); + }; + + LavamanStones(EVoid) + { + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKLEFTHAND, 0); + autowait(0.7f); + // throw rocks + if (m_EecChar==ELC_LARGE) { + ThrowRocks(PRT_LAVAMAN_STONE); + } else if (m_EecChar==ELC_BIG) { + ThrowRocks(PRT_LAVAMAN_STONE); + } else { + ThrowRocks(PRT_LAVAMAN_STONE); + } + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + autowait(0.9f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + + LavamanHit(EVoid) + { + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS, 0); + autowait(0.6f); + HitGround(); + PlaySound(m_soFireL, SOUND_LAVA_KICK, SOF_3D); + StartModelAnim(ELEMENTALLAVA_ANIM_WALKBIG, AOF_SMOOTHCHANGE); + autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; + return EReturn(); + }; + +/* + // + // ICEMAN + // + IcemanFire(EVoid) { + StartModelAnim(STONEMAN_ANIM_ATTACK05, 0); + autowait(0.7f); + // throw rocks + if (m_EecChar==ELC_LARGE) { + ThrowRocks(PRT_ICEMAN_LARGE_FIRE); + } else if (m_EecChar==ELC_BIG) { + ThrowRocks(PRT_ICEMAN_BIG_FIRE); + } else { + ThrowRocks(PRT_ICEMAN_FIRE); + } + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + autowait(0.9f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + + IcemanHit(EVoid) { + StartModelAnim(STONEMAN_ANIM_ATTACK01, 0); + autowait(0.6f); + HitGround(); + PlaySound(m_soSound, SOUND_LAVA_KICK, SOF_3D); + autowait(0.5f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + + + // + // AIRMAN + // + AirmanFire(EVoid) { + StartModelAnim(STONEMAN_ANIM_ATTACK06, 0); + autowait(1.0f); + // spawn twister + CPlacement3D pl = m_penEnemy->GetPlacement(); + FLOAT fR, fA; + ETwister et; + fA = FRnd()*360.0f; + if (m_EecChar==ELC_LARGE) { + fR = FRnd()*10.0f; + et.EtsSize = TWS_LARGE; + } else if (m_EecChar==ELC_BIG) { + fR = FRnd()*7.5f; + et.EtsSize = TWS_BIG; + } else { + fR = FRnd()*5.0f; + et.EtsSize = TWS_SMALL; + } + pl.pl_PositionVector += FLOAT3D(CosFast(fA)*fR, 0, SinFast(fA)*fR);; + CEntityPointer penTwister = CreateEntity(pl, CLASS_TWISTER); + et.penOwner = this; + penTwister->Initialize(et); + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + autowait(0.6f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + + + // + // WATERMAN + // + WatermanFire(EVoid) { + StartModelAnim(STONEMAN_ANIM_ATTACK02, 0); + autowait(0.5f); + // throw rocks + FireWater(); + PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); + autowait(0.6f); + // stand a while + StandingAnim(); + autowait(FRnd()/3+_pTimer->TickQuantum); + return EReturn(); + }; + */ + + +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + // Play wound animation and falling body part + BeWounded(EDamage eDamage) : CEnemyBase::BeWounded { + // spawn additional elemental + if( m_bSpawnEnabled) + { + SpawnNewElemental(); + } + jump CEnemyBase::BeWounded(eDamage); + }; + +/************************************************************ + * CHANGE STATE PROCEDURES * + ************************************************************/ + // box to normal + BoxToNormal(EVoid) { + m_EesCurrentState = ELS_NORMAL; + SetPhysicsFlags(EPF_MODEL_WALKING); + ChangeCollisionBoxIndexWhenPossible(STONEMAN_COLLISION_BOX_NORMAL); + StartModelAnim(STONEMAN_ANIM_MORPHBOXUP, 0); + AddAttachments(); + autowait(GetModelObject()->GetAnimLength(STONEMAN_ANIM_MORPHBOXUP)); + return EReturn(); + }; + + // normal to box +/* NormalToBox(EVoid) { + StartModelAnim(STONEMAN_ANIM_MORPHBOXDOWN, 0); + autowait(GetModelObject()->GetAnimLength(STONEMAN_ANIM_MORPHBOXDOWN)); + m_EesCurrentState = ELS_BOX; + SetPhysicsFlags(EPF_BOX_PLANE_ELEMENTAL); + ChangeCollisionBoxIndexWhenPossible(STONEMAN_COLLISION_BOX_BOX); + RemoveAttachments(); + return EReturn(); + };*/ + + // plane to normal + PlaneToNormal(EVoid) { + m_EesCurrentState = ELS_NORMAL; + SwitchToModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + ChangeCollisionBoxIndexWhenPossible(ELEMENTALLAVA_COLLISION_BOX_NORMAL); + INDEX iAnim; + if (m_EetType == ELT_LAVA) { + iAnim = ELEMENTALLAVA_ANIM_MELTUP; + } else { +// iAnim = STONEMAN_ANIM_MORPHPLANEUP; + } + StartModelAnim(iAnim, 0); + AddAttachments(); + autowait(GetModelObject()->GetAnimLength(iAnim)); + return EReturn(); + }; + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + InitializeAttack(EVoid) : CEnemyBase::InitializeAttack { + // change state from box to normal + if (m_EesCurrentState==ELS_BOX) + { + autocall BoxToNormal() EReturn; + } + // change state from plane to normal + else if (m_EesCurrentState==ELS_PLANE) + { + autocall PlaneToNormal() EReturn; + } + jump CEnemyBase::InitializeAttack(); + }; + + Fire(EVoid) : CEnemyBase::Fire { + // fire projectile + switch (m_EetType) { +// case ELT_STONE: jump StonemanFire(); break; + case ELT_LAVA: jump LavamanFire(); break; +// case ELT_ICE: jump IcemanFire(); break; +// case ELT_AIR: jump AirmanFire(); break; +// case ELT_WATER: jump WatermanFire(); break; + } + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + // hit ground + switch (m_EetType) { +// case ELT_STONE: jump StonemanHit(); break; + case ELT_LAVA: jump LavamanHit(); break; +// case ELT_ICE: jump IcemanHit(); break; +// case ELT_AIR: jump AirmanFire(); break; +// case ELT_WATER: jump WatermanFire(); break; + } + return EReturn(); + }; + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death + { + if (m_bSpawnOnBlowUp && (m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG)) { + SpawnNewElemental(); + SpawnNewElemental(); + } + // air fade out + if (m_EetType == ELT_AIR) { + m_fFadeStartTime = _pTimer->CurrentTick(); + m_bFadeOut = TRUE; + m_fFadeTime = 2.0f; + autowait(m_fFadeTime); + } + autocall CEnemyBase::Death() EEnd; + GetModelObject()->mo_toBump.SetData( NULL); + return EEnd(); + }; + + BossAppear(EVoid) + { + autowait(2.0f); + m_fFadeStartTime = _pTimer->CurrentTick(); + GetModelObject()->PlayAnim(ELEMENTALLAVA_ANIM_ANGER, 0); + PlaySound(m_soSound, SOUND_LAVA_ANGER, SOF_3D); + autowait(GetModelObject()->GetAnimLength(ELEMENTALLAVA_ANIM_ANGER)-_pTimer->TickQuantum); + + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS, AOF_SMOOTHCHANGE); + autowait(0.7f); + HitGround(); + PlaySound(m_soFireL, SOUND_LAVA_KICK, SOF_3D); + autowait(GetModelObject()->GetAnimLength(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS)-0.7f-_pTimer->TickQuantum); + + StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS, 0); + autowait(0.6f); + HitGround(); + PlaySound(m_soFireR, SOUND_LAVA_KICK, SOF_3D); + autowait(GetModelObject()->GetAnimLength(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS)-0.6f-_pTimer->TickQuantum); + + + return EReturn(); + } + + // overridable called before main enemy loop actually begins + PreMainLoop(EVoid) : CEnemyBase::PreMainLoop + { + // if spawned by other entity + if (m_bSpawned) { + m_bSpawned = FALSE; + m_bCountAsKill = FALSE; + // wait till touching the ground + autocall FallOnFloor() EReturn; + } + + if (m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG && m_EetType==ELT_LAVA) + { + PlaySound(m_soBackground, SOUND_LAVA_LAVABURN, SOF_3D|SOF_LOOP); + } + + if( m_EecChar==ELC_LARGE) + { + autocall BossAppear() EReturn; + } + return EReturn(); + } + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + if (m_EetType!=ELT_LAVA) { + m_EetType=ELT_LAVA; + } + // declare yourself as a model + InitAsModel(); + // movable + if (m_bMovable) { + SetPhysicsFlags(EPF_MODEL_WALKING); + // non movable + } else { + SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); + } + // air elemental + if (m_EetType==ELT_AIR) { + SetCollisionFlags(ECF_AIR); + // solid elemental + } else { + SetCollisionFlags(ECF_MODEL); + } + SetFlags(GetFlags()|ENF_ALIVE); + en_fDensity = m_fDensity; + m_fSpawnDamage = 1e6f; + m_fDamageWounded = 1e6f; + m_bSpawnEnabled = FALSE; + m_bBoss = FALSE; + + // set your appearance + switch (m_EetType) { +/* case ELT_AIR: + SetComponents(this, *GetModelObject(), MODEL_AIR, TEXTURE_AIR, 0, 0, 0); + break; + case ELT_ICE: + SetComponents(this, *GetModelObject(), MODEL_ICE, TEXTURE_ICE, TEXTURE_ICE, TEX_SPEC_STRONG, 0); + break;*/ + case ELT_LAVA: + m_fBlowUpAmount = 1E30f; + SetComponents(this, *GetModelObject(), MODEL_LAVA, TEXTURE_LAVA, 0, 0, TEXTURE_LAVA_DETAIL); + break; +/* case ELT_STONE: + SetComponents(this, *GetModelObject(), MODEL_STONE, TEXTURE_STONE, 0, 0, 0); + break; + case ELT_WATER: + SetComponents(this, *GetModelObject(), MODEL_WATER, TEXTURE_WATER, TEXTURE_WATER, TEX_SPEC_STRONG, 0); + break;*/ + } + ModelChangeNotify(); + + // character settings + if (m_EecChar==ELC_LARGE) + { + // this one is boss! + m_sptType = SPT_SMALL_LAVA_STONES; + m_bBoss = TRUE; + SetHealth(10000.0f); + m_fMaxHealth = 10000.0f; + // after loosing this ammount of damage we will spawn new elemental + m_fSpawnDamage = 2000.0f; + // setup moving speed + m_fWalkSpeed = FRnd()/2 + 1.0f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); + m_fAttackRunSpeed = FRnd() + 2.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd() + 2.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 300.0f; + m_fCloseDistance = 60.0f; + m_fStopDistance = 30.0f; + m_fAttackFireTime = 0.5f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 600.0f; + m_iScore = 50000; + } + else if (m_EecChar==ELC_BIG) + { + m_sptType = SPT_LAVA_STONES; + SetHealth(800.0f); + m_fMaxHealth = 800.0f; + // after loosing this ammount of damage we will spawn new elemental + m_fSpawnDamage = 500.0f; + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); + m_fAttackRunSpeed = FRnd()*1.0f + 6.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 300.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 2.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 300.0f); + // setup attack distances + m_fAttackDistance = 150.0f; + m_fCloseDistance = 20.0f; + m_fStopDistance = 5.0f; + m_fAttackFireTime = 0.5f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 400.0f; + // damage/explode properties + m_iScore = 2500; + } + else + { + m_sptType = SPT_LAVA_STONES; + SetHealth(100.0f); + m_fMaxHealth = 100.0f; + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); + m_fAttackRunSpeed = FRnd()*2.0f + 6.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 500.0f); + m_fCloseRunSpeed = FRnd()*3.0f + 4.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 500.0f); + // setup attack distances + m_fAttackDistance = 100.0f; + m_fCloseDistance = 10.0f; + m_fStopDistance = 5.0f; + m_fAttackFireTime = 1.5f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_iScore = 500; + } + + // non movable + if (!m_bMovable) + { + m_EesStartState = ELS_NORMAL; + m_bSpawnWhenHarmed = FALSE; + m_bSpawnOnBlowUp = FALSE; + // fire count + if (m_iFireCount <= 0) + { + WarningMessage("Entity: %s - Fire count must be greater than zero",(const char*) GetName()); + m_iFireCount = 1; + } + } + + // state and flare attachments + m_EesCurrentState = m_EesStartState; + RemoveAttachments(); + switch (m_EesCurrentState) { + case ELS_NORMAL: + SetPhysicsFlags(EPF_MODEL_WALKING); + AddAttachments(); + break; + case ELS_BOX: + SetPhysicsFlags(EPF_BOX_PLANE_ELEMENTAL); + break; + case ELS_PLANE: + SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); + SwitchToEditorModel(); + break; + } + StandingAnim(); + + // stretch + if (m_EecChar==ELC_SMALL) { + GetModelObject()->StretchModel(FLOAT3D(LAVAMAN_SMALL_STRETCH, LAVAMAN_SMALL_STRETCH, LAVAMAN_SMALL_STRETCH)); + } + else if (m_EecChar==ELC_LARGE) { + GetModelObject()->StretchModel(FLOAT3D(LAVAMAN_LARGE_STRETCH, LAVAMAN_LARGE_STRETCH, LAVAMAN_LARGE_STRETCH)); + } else if (m_EecChar==ELC_BIG) { + GetModelObject()->StretchModel(FLOAT3D(LAVAMAN_BIG_STRETCH, LAVAMAN_BIG_STRETCH, LAVAMAN_BIG_STRETCH)); + } + ModelChangeNotify(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/EnemyBase.es b/Sources/Entities/EnemyBase.es new file mode 100644 index 0000000..fd33d72 --- /dev/null +++ b/Sources/Entities/EnemyBase.es @@ -0,0 +1,2785 @@ +310 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/Common/PathFinding.h" +#include "Entities/NavigationMarker.h" +extern void JumpFromBouncer(CEntity *penToBounce, CEntity *penBouncer); +extern INDEX ent_bReportBrokenChains; +%} + +uses "Entities/Watcher"; +uses "Entities/BasicEffects"; +uses "Entities/Projectile"; +uses "Entities/Debris"; +uses "Entities/EnemyMarker"; +uses "Entities/MusicHolder"; +uses "Entities/BloodSpray"; + +event ERestartAttack { +}; + +// self sent in Active loop to reconsider what enemy should do +event EReconsiderBehavior { +}; + +// force wound +event EForceWound { +}; + +enum TargetType { + 0 TT_NONE "", // no target + 1 TT_SOFT "", // soft target - only spoted player but not heavily angry at him + 2 TT_HARD "", // hard target - player has provoked enemy and it is very angry +}; + +enum DestinationType { + 0 DT_PLAYERCURRENT "", // go to where player is now + 1 DT_PLAYERSPOTTED "", // go to where player was last seen + 2 DT_PATHTEMPORARY "", // go to navigation marker - temporary, only until you spot player again + 3 DT_PATHPERSISTENT "", // go to navigation marker - until you really get there +}; + +%{ +#define MF_MOVEZ (1L<<0) +#define MF_ROTATEH (1L<<1) +#define MF_MOVEXZY (1L<<2) +%} + +class export CEnemyBase : CMovableModelEntity { +name "Enemy Base"; +thumbnail ""; +features "HasName", "IsTargetable", "CanBePredictable"; + +properties: + 1 CEntityPointer m_penWatcher, // watcher + 2 FLOAT3D m_vStartPosition = FLOAT3D(0,0,0), // start position + 3 CEntityPointer m_penEnemy, // current enemy + 4 enum TargetType m_ttTarget = TT_NONE, // type of target + 5 CTString m_strDescription = "Enemy base", + 6 CTString m_strName "Name" 'N' = "Enemy base", + 7 CSoundObject m_soSound, + 8 FLOAT3D m_vStartDirection = FLOAT3D(0,0,-1), // for returning to start + 9 BOOL m_bOnStartPosition = TRUE, + 29 FLOAT m_fFallHeight "Fall height" = 8.0f, + 31 FLOAT m_fStepHeight "Step height" = -1.0f, + 17 RANGE m_fSenseRange "Sense Range" = 0.0f, // immediately spots any player that gets closer than this + 28 FLOAT m_fViewAngle "View angle" 'V' = 360.0f, // view frustum angle for spotting players + + // moving/attack properties - CAN BE SET + // these following must be ordered exactly like this for GetProp() to function + 10 FLOAT m_fWalkSpeed = 1.0f, // walk speed + 11 ANGLE m_aWalkRotateSpeed = AngleDeg(10.0f), // walk rotate speed + 12 FLOAT m_fAttackRunSpeed = 1.0f, // attack run speed + 13 ANGLE m_aAttackRotateSpeed = AngleDeg(10.0f), // attack rotate speed + 14 FLOAT m_fCloseRunSpeed = 1.0f, // close run speed + 15 ANGLE m_aCloseRotateSpeed = AngleDeg(10.0f), // close rotate speed + 20 FLOAT m_fAttackDistance = 50.0f, // attack distance mode + 21 FLOAT m_fCloseDistance = 10.0f, // close distance mode + 22 FLOAT m_fAttackFireTime = 2.0f, // attack distance fire time + 23 FLOAT m_fCloseFireTime = 1.0f, // close distance fire time + 24 FLOAT m_fStopDistance = 0.0f, // stop moving toward enemy if closer than stop distance + 25 FLOAT m_fIgnoreRange = 200.0f, // cease attack if enemy farther + 26 FLOAT m_fLockOnEnemyTime = 0.0f, // time needed to fire + + // damage/explode properties - CAN BE SET + 40 FLOAT m_fBlowUpAmount = 0.0f, // damage in minus for blow up + 41 INDEX m_fBodyParts = 4, // number of spawned body parts + 42 FLOAT m_fDamageWounded = 0.0f, // damage amount to be wounded + 43 FLOAT3D m_vDamage = FLOAT3D(0,0,0), // current damage impact + 44 FLOAT m_tmLastDamage = -1000.0f, + 46 BOOL m_bRobotBlowup = FALSE, // set for robots parts blowup, otherwise blowup flesh + 47 FLOAT m_fBlowUpSize = 2.0f, + + // logic temporary variables -> DO NOT USE +133 FLOAT m_fMoveTime = 0.0f, + 52 FLOAT3D m_vDesiredPosition = FLOAT3D(0,0,0), + 53 enum DestinationType m_dtDestination = DT_PLAYERCURRENT, // type of current desired position + 59 CEntityPointer m_penPathMarker, // current path finding marker + 18 FLOAT3D m_vPlayerSpotted = FLOAT3D(0,0,0), // where player was last spotted + 54 FLOAT m_fMoveFrequency = 0.0f, + 55 FLOAT m_fMoveSpeed = 0.0f, + 56 ANGLE m_aRotateSpeed = 0, + 57 FLOAT m_fLockStartTime = 0.0f, + 58 FLOAT m_fRangeLast = 0.0f, +130 BOOL m_bFadeOut = FALSE, +131 FLOAT m_fFadeStartTime = 0.0f, +132 FLOAT m_fFadeTime = 0.0f, + + // attack temporary -> DO NOT USE + 60 FLOAT m_fShootTime = 0.0f, // time when entity will try to shoot on enemy + 61 FLOAT m_fDamageConfused = 0.0f, // damage amount when entity shoot concentration is spoiled + 62 INDEX m_iChargeHitAnimation = 0.0f, // charge hit (close attack) properties + 63 FLOAT m_fChargeHitDamage = 0.0f, + 64 FLOAT m_fChargeHitAngle = 0.0f, + 65 FLOAT m_fChargeHitSpeed = 0.0f, + + // editor variables + 83 CEntityPointer m_penSpawnerTarget, // for re-spawning + 84 CEntityPointer m_penDeathTarget "Death target" 'D', // death target + 85 enum EventEType m_eetDeathType "Death event type" 'F' = EET_TRIGGER, // death event type + 86 BOOL m_bTemplate "Template" = FALSE, // template enemy for spawning new enemies + 88 RANGE m_fAttackRadius "Radius of attack" 'A' = 10000.0f, // attack sphere range radius + 89 COLOR m_colColor "Color" 'L' = 0x00, // color + 90 BOOL m_bDeaf "Deaf" = FALSE, // deaf + 91 BOOL m_bBlind "Blind" = FALSE, // blind + 92 FLOAT m_tmGiveUp "Give up time" = 5.0f, // how fast enemy gives up attack + 93 FLOAT m_tmReflexMin "Reflex Min" = 0.0f, // how much to wait before reacting on spotting the player + 94 FLOAT m_tmReflexMax "Reflex Max" = 0.0f, + 95 FLOAT m_fActivityRange "Activity Range" = 0.0f, + + // random values variables +106 BOOL m_bApplyRandomStretch "Apply random stretch" = FALSE, // apply random stretch +107 FLOAT m_fRandomStretchFactor "Random stretch factor" = 0.1f, // random stretch +108 FLOAT m_fStretchMultiplier "Stretch multiplier" = 1.0f, // stretch multiplier +109 FLOAT m_fRandomStretchMultiplier = 1.0f, // calculated random stretch + + // marker variables +120 CEntityPointer m_penMarker "Marker" 'M' COLOR(C_RED|0xFF), // enemy marker pointer + +// fuss variables +140 CEntityPointer m_penMainMusicHolder, +141 FLOAT m_tmLastFussTime = 0.0f, + +142 FLOAT m_iScore = -100000, // how many points this enemy gives when killed +143 FLOAT m_fMaxHealth = -1.0f, // must set this because of crosshair colorizing +144 BOOL m_bBoss = FALSE, // set for bosses (for health display) + +145 FLOAT m_fSpiritStartTime = 0.0f, // time when spirit effect has started + +146 FLOAT m_tmSpraySpawned = 0.0f, // time when damage has been applied +147 FLOAT m_fSprayDamage = 0.0f, // total ammount of damage +148 CEntityPointer m_penSpray, // the blood spray +149 FLOAT m_fMaxDamageAmmount = 0.0f, // max ammount of damage received in in last few ticks +150 FLOAT3D m_vLastStain = FLOAT3D(0,0,0), // where last stain was left +151 enum SprayParticlesType m_sptType = SPT_BLOOD, // type of particles + + { + TIME m_tmPredict; // time to predict the entity to + } + + +components: + + 1 class CLASS_WATCHER "Classes\\Watcher.ecl", + 2 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + 3 class CLASS_DEBRIS "Classes\\Debris.ecl", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 5 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + +// ************** FLESH PARTS ************** + 10 model MODEL_FLESH "Models\\Effects\\Debris\\Flesh\\Flesh.mdl", + 11 model MODEL_FLESH_APPLE "Models\\Effects\\Debris\\Fruits\\Apple.mdl", + 12 model MODEL_FLESH_BANANA "Models\\Effects\\Debris\\Fruits\\Banana.mdl", + 13 model MODEL_FLESH_BURGER "Models\\Effects\\Debris\\Fruits\\CheeseBurger.mdl", + 14 model MODEL_FLESH_LOLLY "Models\\Effects\\Debris\\Fruits\\LollyPop.mdl", + 15 model MODEL_FLESH_ORANGE "Models\\Effects\\Debris\\Fruits\\Orange.mdl", + + 20 texture TEXTURE_FLESH_RED "Models\\Effects\\Debris\\Flesh\\FleshRed.tex", + 21 texture TEXTURE_FLESH_GREEN "Models\\Effects\\Debris\\Flesh\\FleshGreen.tex", + 22 texture TEXTURE_FLESH_APPLE "Models\\Effects\\Debris\\Fruits\\Apple.tex", + 23 texture TEXTURE_FLESH_BANANA "Models\\Effects\\Debris\\Fruits\\Banana.tex", + 24 texture TEXTURE_FLESH_BURGER "Models\\Effects\\Debris\\Fruits\\CheeseBurger.tex", + 25 texture TEXTURE_FLESH_LOLLY "Models\\Effects\\Debris\\Fruits\\LollyPop.tex", + 26 texture TEXTURE_FLESH_ORANGE "Models\\Effects\\Debris\\Fruits\\Orange.tex", + +// ************** MACHINE PARTS ************** + 31 model MODEL_MACHINE "Models\\Effects\\Debris\\Stone\\Stone.mdl", + 32 texture TEXTURE_MACHINE "Models\\Effects\\Debris\\Stone\\Stone.tex", + + +functions: + + void CEnemyBase(void) + { + m_tmPredict = 0; + } + + // called by other entities to set time prediction parameter + void SetPredictionTime(TIME tmAdvance) // give time interval in advance to set + { + ASSERT(!IsPredictor()); + m_tmPredict = _pTimer->CurrentTick()+tmAdvance; + } + + // called by engine to get the upper time limit + TIME GetPredictionTime(void) // return moment in time up to which to predict this entity + { + return m_tmPredict; + } + + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("%s killed %s"),(const char*) GetClass()->ec_pdecDLLClass->dec_strName,(const char*) strPlayerName); + return str; + } + + virtual FLOAT GetCrushHealth(void) + { + return 0.0f; + } + + // if should be counted as kill + virtual BOOL CountAsKill(void) + { + return TRUE; + } + + virtual BOOL ForcesCannonballToExplode(void) + { + return FALSE; + } + + // overridable function for access to different properties of derived classes (flying/diving) + virtual FLOAT &GetProp(FLOAT &m_fBase) + { + return m_fBase; + } + + // overridable function to get range for switching to another player + virtual FLOAT GetThreatDistance(void) + { + // closer of close or stop range + return Max(GetProp(m_fCloseDistance), GetProp(m_fStopDistance)); + } + + // check if we maybe switch to some other player (for large beasts in coop) + void MaybeSwitchToAnotherPlayer(void) + { + // if in single player + if (GetSP()->sp_bSinglePlayer) { + // no need to check + return; + } + + // if current player is inside threat distance + if (CalcDist(m_penEnemy)CheckAnotherPlayer(m_penEnemy); + if (penNewEnemy!=m_penEnemy && penNewEnemy!=NULL) { + m_penEnemy = penNewEnemy; + SendEvent(EReconsiderBehavior()); + } + } + + class CWatcher *GetWatcher(void) + { + ASSERT(m_penWatcher!=NULL); + return (CWatcher*)&*m_penWatcher; + } + export void Copy(CEntity &enOther, ULONG ulFlags) + { + CMovableModelEntity::Copy(enOther, ulFlags); + CEnemyBase *penOther = (CEnemyBase *)(&enOther); + } + + void Precache(void) + { + PrecacheModel(MODEL_FLESH); + PrecacheModel(MODEL_FLESH_APPLE); + PrecacheModel(MODEL_FLESH_BANANA); + PrecacheModel(MODEL_FLESH_BURGER); + PrecacheModel(MODEL_MACHINE); + PrecacheTexture(TEXTURE_MACHINE); + PrecacheTexture(TEXTURE_FLESH_RED); + PrecacheTexture(TEXTURE_FLESH_GREEN); + PrecacheTexture(TEXTURE_FLESH_APPLE); + PrecacheTexture(TEXTURE_FLESH_BANANA); + PrecacheTexture(TEXTURE_FLESH_BURGER); + PrecacheTexture(TEXTURE_FLESH_LOLLY); + PrecacheTexture(TEXTURE_FLESH_ORANGE); + PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSPILL); + PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSTAIN); + PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSTAINGROW); + PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODEXPLODE); + PrecacheClass(CLASS_BASIC_EFFECT, BET_BOMB); + PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + PrecacheClass(CLASS_DEBRIS); + } + + // get position you would like to go to when following player + virtual FLOAT3D PlayerDestinationPos(void) + { + return m_penEnemy->GetPlacement().pl_PositionVector; + } + + // calculate delta to given entity + FLOAT3D CalcDelta(CEntity *penEntity) + { + ASSERT(penEntity!=NULL); + // find vector from you to target + return penEntity->GetPlacement().pl_PositionVector - GetPlacement().pl_PositionVector; + }; + // calculate distance to given entity + FLOAT CalcDist(CEntity *penEntity) + { + return CalcDelta(penEntity).Length(); + }; + + BOOL IfTargetCrushed(CEntity *penOther, const FLOAT3D &vDirection) + { + if( IsOfClass(penOther, "ModelHolder2")) + { + FLOAT fCrushHealth = GetCrushHealth(); + if( fCrushHealth>((CRationalEntity &)*penOther).GetHealth()) + { + InflictDirectDamage(penOther, this, + DMT_EXPLOSION, fCrushHealth, GetPlacement().pl_PositionVector, vDirection); + return TRUE; + } + } + return FALSE; + } + + // calculate delta to given entity in current gravity plane + FLOAT3D CalcPlaneDelta(CEntity *penEntity) + { + ASSERT(penEntity!=NULL); + FLOAT3D vPlaneDelta; + // find vector from you to target in XZ plane + GetNormalComponent( + penEntity->GetPlacement().pl_PositionVector - GetPlacement().pl_PositionVector, + en_vGravityDir, vPlaneDelta); + return vPlaneDelta; + }; + + // calculate distance to given entity in current gravity plane + FLOAT CalcPlaneDist(CEntity *penEntity) + { + return CalcPlaneDelta(penEntity).Length(); + }; + + // get cos of angle in direction + FLOAT GetFrustumAngle(const FLOAT3D &vDir) + { + // find front vector + FLOAT3D vFront = -GetRotationMatrix().GetColumn(3); + // make dot product to determine if you can see target (view angle) + return (vDir/vDir.Length())%vFront; + } + + // get cos of angle in direction in current gravity plane + FLOAT GetPlaneFrustumAngle(const FLOAT3D &vDir) + { + FLOAT3D vPlaneDelta; + // find vector from you to target in XZ plane + GetNormalComponent(vDir, en_vGravityDir, vPlaneDelta); + // find front vector + FLOAT3D vFront = -GetRotationMatrix().GetColumn(3); + FLOAT3D vPlaneFront; + GetNormalComponent(vFront, en_vGravityDir, vPlaneFront); + // make dot product to determine if you can see target (view angle) + vPlaneDelta.Normalize(); + vPlaneFront.Normalize(); + return vPlaneDelta%vPlaneFront; + } + + // determine if you can see something in given direction + BOOL IsInFrustum(CEntity *penEntity, FLOAT fCosHalfFrustum) + { + // get direction to the entity + FLOAT3D vDelta = CalcDelta(penEntity); + // find front vector + FLOAT3D vFront = -GetRotationMatrix().GetColumn(3); + // make dot product to determine if you can see target (view angle) + FLOAT fDotProduct = (vDelta/vDelta.Length())%vFront; + return fDotProduct >= fCosHalfFrustum; + }; + + // determine if you can see something in given direction in current gravity plane + BOOL IsInPlaneFrustum(CEntity *penEntity, FLOAT fCosHalfFrustum) + { + // get direction to the entity + FLOAT3D vPlaneDelta = CalcPlaneDelta(penEntity); + // find front vector + FLOAT3D vFront = -GetRotationMatrix().GetColumn(3); + FLOAT3D vPlaneFront; + GetNormalComponent(vFront, en_vGravityDir, vPlaneFront); + // make dot product to determine if you can see target (view angle) + vPlaneDelta.Normalize(); + vPlaneFront.Normalize(); + FLOAT fDot = vPlaneDelta%vPlaneFront; + return fDot >= fCosHalfFrustum; + }; + + // cast a ray to entity checking only for brushes + BOOL IsVisible(CEntity *penEntity) + { + ASSERT(penEntity!=NULL); + // get ray source and target + FLOAT3D vSource, vTarget; + GetPositionCastRay(this, penEntity, vSource, vTarget); + + // cast the ray + CCastRay crRay(this, vSource, vTarget); + crRay.cr_ttHitModels = CCastRay::TT_NONE; // check for brushes only + crRay.cr_bHitTranslucentPortals = FALSE; + en_pwoWorld->CastRay(crRay); + + // if hit nothing (no brush) the entity can be seen + return (crRay.cr_penHit==NULL); + }; + + // cast a ray to entity checking all + BOOL IsVisibleCheckAll(CEntity *penEntity) + { + ASSERT(penEntity!=NULL); + // get ray source and target + FLOAT3D vSource, vTarget; + GetPositionCastRay(this, penEntity, vSource, vTarget); + + // cast the ray + CCastRay crRay(this, vSource, vTarget); + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; // check for model collision box + crRay.cr_bHitTranslucentPortals = FALSE; + en_pwoWorld->CastRay(crRay); + + // if the ray hits wanted entity + return crRay.cr_penHit==penEntity; + }; + + /* calculates launch velocity and heading correction for angular launch */ + void CalculateAngularLaunchParams( + FLOAT3D vShooting, FLOAT fShootHeight, + FLOAT3D vTarget, FLOAT3D vSpeedDest, + ANGLE aPitch, + FLOAT &fLaunchSpeed, + FLOAT &fRelativeHdg) + { + FLOAT3D vNewTarget = vTarget; + FLOAT3D &vGravity = en_vGravityDir; + FLOAT fYt; + FLOAT fXt; + FLOAT fA = TanFast(AngleDeg(aPitch)); + FLOAT fTime = 0.0f; + FLOAT fLastTime = 0.0f; + + INDEX iIterations = 0; + do + { + iIterations++; + FLOAT3D vDistance = vNewTarget-vShooting; + FLOAT3D vXt, vYt; + GetParallelAndNormalComponents(vDistance, vGravity, vYt, vXt); + fYt = vYt.Length(); + if (vGravity%vYt>0) { + fYt=-fYt; + } + fXt = vXt.Length(); + fLastTime=fTime; + fTime = Sqrt(2.0f)*Sqrt((fA*fXt+fShootHeight-fYt)/en_fGravityA); + vNewTarget = vTarget+vSpeedDest*fTime; + } + while( (Abs(fTime-fLastTime) > _pTimer->TickQuantum) && (iIterations<10) ); + + // calculate launch speed + fLaunchSpeed = fXt/(fTime*Cos(aPitch)); + + // calculate heading correction + FLOAT fHdgTargetNow = GetRelativeHeading( (vTarget-vShooting).Normalize()); + FLOAT fHdgTargetMoved = GetRelativeHeading( (vNewTarget-vShooting).Normalize()); + fRelativeHdg = fHdgTargetMoved-fHdgTargetNow; + } + + /* calculates predicted position for propelled projectile */ + FLOAT3D CalculatePredictedPosition( FLOAT3D vShootPos, FLOAT3D vTarget, + FLOAT fSpeedSrc, FLOAT3D vSpeedDst, FLOAT fClampY) + { + FLOAT3D vNewTarget = vTarget; + FLOAT3D &vGravity = en_vGravityDir; + FLOAT fTime = 0.0f; + FLOAT fLastTime = 0.0f; + INDEX iIterations = 0; + FLOAT3D vDistance = vNewTarget-vShootPos; + + // iterate to obtain accurate position + do + { + iIterations++; + fLastTime=fTime; + fTime = vDistance.Length()/fSpeedSrc; + vNewTarget = vTarget + vSpeedDst*fTime + vGravity*0.5f*fTime*fTime; + vNewTarget(2) = ClampDn( vNewTarget(2), fClampY); + vDistance = vNewTarget-vShootPos; + } + while( (Abs(fTime-fLastTime) > _pTimer->TickQuantum) && (iIterations<10) ); + return vNewTarget; + } + + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Marker"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\EnemyMarker.ecl"); + strTargetProperty = "Marker"; + return TRUE; + } + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penMarker!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s",(const char*) m_penMarker->GetName()); + } + return m_strDescription; + } + + virtual const CTFileName &GetComputerMessageName(void) const { + static CTFileName fnm(CTString("")); + return fnm; + } + + // add to prediction any entities that this entity depends on + void AddDependentsToPrediction(void) + { + m_penSpray->AddToPrediction(); + if (m_penWatcher!=NULL) { + GetWatcher()->AddToPrediction(); + } + } + + // create a checksum value for sync-check + void ChecksumForSync(ULONG &ulCRC, INDEX iExtensiveSyncCheck) { + CMovableModelEntity::ChecksumForSync(ulCRC, iExtensiveSyncCheck); + } + // dump sync data to text file + void DumpSync_t(CTStream &strm, INDEX iExtensiveSyncCheck) // throw char * + { + CMovableModelEntity ::DumpSync_t(strm, iExtensiveSyncCheck); + strm.FPrintF_t("enemy: "); + if (m_penEnemy!=NULL) { + strm.FPrintF_t("id: %08X\n", m_penEnemy->en_ulID); + } else { + strm.FPrintF_t("none\n"); + } + } + + /* Read from stream. */ + void Read_t( CTStream *istr) { + CMovableModelEntity::Read_t(istr); + + // add to fuss if needed + if (m_penMainMusicHolder!=NULL) { + ((CMusicHolder&)*m_penMainMusicHolder).m_cenFussMakers.Add(this); + } + }; + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = GetClass()->ec_pdecDLLClass->dec_strName; + if (m_bTemplate) { + pes->es_ctCount = 0; + } else { + pes->es_ctCount = 1; + } + pes->es_ctAmmount = 1; + pes->es_fValue = GetHealth(); + pes->es_iScore = m_iScore; + return TRUE; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // if template + if (m_bTemplate) { + // do nothing + return; + } + + FLOAT fNewDamage = fDamageAmmount; + + // adjust damage + fNewDamage *=DamageStrength( ((EntityInfo*)GetEntityInfo())->Eeibt, dmtType); + // apply game extra damage per enemy and per player + fNewDamage *=GetGameDamageMultiplier(); + + // if no damage + if (fNewDamage==0) { + // do nothing + return; + } + FLOAT fKickDamage = fNewDamage; + if( (dmtType == DMT_EXPLOSION) || (dmtType == DMT_IMPACT) || (dmtType == DMT_CANNONBALL_EXPLOSION) ) + { + fKickDamage*=1.5; + } + if (dmtType==DMT_DROWNING || dmtType==DMT_CLOSERANGE) { + fKickDamage /= 10; + } + + // get passed time since last damage + TIME tmNow = _pTimer->CurrentTick(); + TIME tmDelta = tmNow-m_tmLastDamage; + m_tmLastDamage = tmNow; + + // fade damage out + if (tmDelta>=_pTimer->TickQuantum*3) { + m_vDamage=FLOAT3D(0,0,0); + } + // add new damage + FLOAT3D vDirectionFixed; + if (vDirection.ManhattanNorm()>0.5f) { + vDirectionFixed = vDirection; + } else { + vDirectionFixed = -en_vGravityDir; + } + FLOAT3D vDamageOld = m_vDamage; +/* if( (dmtType == DMT_EXPLOSION) || (dmtType == DMT_CANNONBALL_EXPLOSION) ) + { + m_vDamage+=(vDirectionFixed/2-en_vGravityDir/2)*fKickDamage; + } + else*/ + { + m_vDamage+=(vDirectionFixed-en_vGravityDir/2)*fKickDamage; + } + + FLOAT fOldLen = vDamageOld.Length(); + FLOAT fNewLen = m_vDamage.Length(); + FLOAT fOldRootLen = Sqrt(fOldLen); + FLOAT fNewRootLen = Sqrt(fNewLen); + + FLOAT fMassFactor = 300.0f/((EntityInfo*)GetEntityInfo())->fMass; + + if( !(en_ulFlags & ENF_ALIVE)) + { + fMassFactor /= 3; + } + + if(fOldLen != 0.0f) + { + // cancel last push + GiveImpulseTranslationAbsolute( -vDamageOld/fOldRootLen*fMassFactor); + } + + //-en_vGravityDir*fPushStrength/10 + + // push it back + GiveImpulseTranslationAbsolute( m_vDamage/fNewRootLen*fMassFactor); + + /*if ((m_tmSpraySpawned<=_pTimer->CurrentTick()-_pTimer->TickQuantum || + m_fSprayDamage+fNewDamage>50.0f) + && m_fSpiritStartTime==0) {*/ + + if( m_fMaxDamageAmmountCurrentTick()-_pTimer->TickQuantum*8 || + m_fSprayDamage+fNewDamage>50.0f) + && m_fSpiritStartTime==0) { + + // spawn blood spray + CPlacement3D plSpray = CPlacement3D( vHitPoint, ANGLE3D(0, 0, 0)); + m_penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + if(m_sptType != SPT_ELECTRICITY_SPARKS) + { + m_penSpray->SetParent( this); + } + + ESpawnSpray eSpawnSpray; + + if( m_fMaxDamageAmmount > 10.0f) + { + eSpawnSpray.fDamagePower = 3.0f; + } + else if(m_fSprayDamage+fNewDamage>50.0f) + { + eSpawnSpray.fDamagePower = 2.0f; + } + else + { + eSpawnSpray.fDamagePower = 1.0f; + } + + eSpawnSpray.sptType = m_sptType; + eSpawnSpray.fSizeMultiplier = 1.0f; + + // setup direction of spray + FLOAT3D vHitPointRelative = vHitPoint - GetPlacement().pl_PositionVector; + FLOAT3D vReflectingNormal; + GetNormalComponent( vHitPointRelative, en_vGravityDir, vReflectingNormal); + vReflectingNormal.Normalize(); + + vReflectingNormal(1)/=5.0f; + + FLOAT3D vProjectedComponent = vReflectingNormal*(vDirection%vReflectingNormal); + FLOAT3D vSpilDirection = vDirection-vProjectedComponent*2.0f-en_vGravityDir*0.5f; + + eSpawnSpray.vDirection = vSpilDirection; + eSpawnSpray.penOwner = this; + + // initialize spray + m_penSpray->Initialize( eSpawnSpray); + m_tmSpraySpawned = _pTimer->CurrentTick(); + m_fSprayDamage = 0.0f; + m_fMaxDamageAmmount = 0.0f; + } + m_fSprayDamage+=fNewDamage; + + CMovableModelEntity::ReceiveDamage(penInflictor, + dmtType, fNewDamage, vHitPoint, vDirection); + }; + + +/************************************************************ + * FADE OUT * + ************************************************************/ + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + colAmbient = AddColors( colAmbient, m_colColor); + if( m_bFadeOut) { + FLOAT fTimeRemain = m_fFadeStartTime + m_fFadeTime - _pTimer->CurrentTick(); + if( fTimeRemain < 0.0f) { fTimeRemain = 0.0f; } + COLOR colAlpha = GetModelObject()->mo_colBlendColor; + colAlpha = (colAlpha&0xFFFFFF00) + (COLOR(fTimeRemain/m_fFadeTime*0xFF)&0xFF); + GetModelObject()->mo_colBlendColor = colAlpha; + } else { + if (GetSP()->sp_bMental) { + if (GetHealth()<=0) { + GetModelObject()->mo_colBlendColor = C_WHITE&0xFF; + } else { + extern FLOAT ent_tmMentalIn ; + extern FLOAT ent_tmMentalOut ; + extern FLOAT ent_tmMentalFade; + FLOAT tmIn = ent_tmMentalIn ; + FLOAT tmOut = ent_tmMentalOut ; + FLOAT tmFade = ent_tmMentalFade; + FLOAT tmExist = tmFade+tmIn+tmFade; + FLOAT tmTotal = tmFade+tmIn+tmFade+tmOut; + + FLOAT tmTime = _pTimer->GetLerpedCurrentTick(); + FLOAT fFactor = 1; + if (tmTime>0.1f) { + tmTime += en_ulID*123.456f; + tmTime = fmod(tmTime, tmTotal); + fFactor = CalculateRatio(tmTime, 0, tmExist, tmFade/tmExist, tmFade/tmExist); + } + + GetModelObject()->mo_colBlendColor = C_WHITE|INDEX(0xFF*fFactor); + } + } + } + return CMovableModelEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + }; + + + // fuss functions + void AddToFuss(void) + { + if (IsPredictor()) { + // remember last fuss time + m_tmLastFussTime = _pTimer->CurrentTick(); + return; + } + + // if no music holder remembered - not in fuss + if (m_penMainMusicHolder==NULL) { + // find main music holder + m_penMainMusicHolder = _pNetwork->GetEntityWithName("MusicHolder", 0); + // if no music holder found + if (m_penMainMusicHolder==NULL) { + // just remember last fuss time + m_tmLastFussTime = _pTimer->CurrentTick(); + // cannot make fuss + return; + } + // add to end of fuss list + ((CMusicHolder&)*m_penMainMusicHolder).m_cenFussMakers.Add(this); + // if boss set as boss + if (m_bBoss) { + ((CMusicHolder&)*m_penMainMusicHolder).m_penBoss = this; + } + // remember last fuss time + m_tmLastFussTime = _pTimer->CurrentTick(); + + // if music holder remembered - still in fuss + } else { + // must be in list + ASSERT(((CMusicHolder&)*m_penMainMusicHolder).m_cenFussMakers.IsMember(this)); + // if boss set as boss + if (m_bBoss) { + ((CMusicHolder&)*m_penMainMusicHolder).m_penBoss = this; + } + // just remember last fuss time + m_tmLastFussTime = _pTimer->CurrentTick(); + } + } + void RemoveFromFuss(void) + { + if (IsPredictor()) { + return; + } + // if no music holder remembered + if (m_penMainMusicHolder==NULL) { + // not in fuss + return; + } + // just remove from list + ((CMusicHolder&)*m_penMainMusicHolder).m_cenFussMakers.Remove(this); + // if boss, clear boss + if (m_bBoss) { + if (((CMusicHolder&)*m_penMainMusicHolder).m_penBoss != this) { + CPrintF(TRANS("More than one boss active!\n")); + ((CMusicHolder&)*m_penMainMusicHolder).m_penBoss = NULL; + } + } + m_penMainMusicHolder = NULL; + } + + // check if should give up attacking + BOOL ShouldCeaseAttack(void) + { + // if there is no valid the enemy + if (m_penEnemy==NULL || + !(m_penEnemy->GetFlags()&ENF_ALIVE) || + (m_penEnemy->GetFlags()&ENF_DELETED)) { + // cease attack + return TRUE; + } + // if not active in fighting + if (_pTimer->CurrentTick()>m_tmLastFussTime+m_tmGiveUp) { + // cease attack + return TRUE; + } + // otherwise, continue + return FALSE; + } + + // Stretch model - MUST BE DONE BEFORE SETTING MODEL! + void StretchModel(void) + { + FLOAT3D vStretch = GetModelObject()->mo_Stretch; + + // apply defined stretch + vStretch *= m_fStretchMultiplier; + + // if should apply random stretch + if (m_bApplyRandomStretch) + { + // will be done only when user clicks "Apply random" switch + m_bApplyRandomStretch = FALSE; + // get rnd for random stretch + m_fRandomStretchMultiplier = (FRnd()-0.5f)*m_fRandomStretchFactor+1.0f; + } + + // apply random stretch + vStretch *= m_fRandomStretchMultiplier; + + GetModelObject()->StretchModel( vStretch); + ModelChangeNotify(); + }; + + // check if an entity is valid for being your new enemy + BOOL IsValidForEnemy(CEntity *penPlayer) + { + return + penPlayer!=NULL && + IsDerivedFromClass(penPlayer, "Player") && + penPlayer->GetFlags()&ENF_ALIVE; + } + + // unset target + void SetTargetNone(void) + { + m_ttTarget = TT_NONE; + m_dtDestination = DT_PLAYERCURRENT; + m_penEnemy = NULL; + } + + // set new player as soft target if possible + BOOL SetTargetSoft(CEntity *penPlayer) + { + // if invalid target + if (!IsValidForEnemy(penPlayer)) { + // do nothing + return FALSE; + } + // if we already have any kind of target + if (m_ttTarget!=TT_NONE) { + // do nothing + return FALSE; + } + // remember new soft target + CEntity *penOld = m_penEnemy; + m_ttTarget = TT_SOFT; + m_dtDestination = DT_PLAYERCURRENT; + m_penEnemy = penPlayer; + return penOld!=penPlayer; + } + + // set new player as hard target if possible + BOOL SetTargetHard(CEntity *penPlayer) + { + // if invalid target + if (!IsValidForEnemy(penPlayer)) { + // do nothing + return FALSE; + } + // if we already have hard target + if (m_ttTarget==TT_HARD) { + // do nothing + return FALSE; + } + // remember new hard target + CEntity *penOld = m_penEnemy; + m_ttTarget = TT_HARD; + m_dtDestination = DT_PLAYERCURRENT; + m_penEnemy = penPlayer; + return penOld!=penPlayer; + } + + // force new player to be hard target + BOOL SetTargetHardForce(CEntity *penPlayer) + { + // if invalid target + if (!IsValidForEnemy(penPlayer)) { + // do nothing + return FALSE; + } + // remember new hard target + CEntity *penOld = m_penEnemy; + m_ttTarget = TT_HARD; + m_dtDestination = DT_PLAYERCURRENT; + m_penEnemy = penPlayer; + return penOld!=penPlayer; + } + +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + + // get movement frequency for attack + virtual FLOAT GetAttackMoveFrequency(FLOAT fEnemyDistance) + { + if (fEnemyDistance>GetProp(m_fCloseDistance)) { + return 0.5f; + } else { + return 0.25f; + } + } + + // set speeds for movement towards desired position + virtual void SetSpeedsToDesiredPosition(const FLOAT3D &vPosDelta, FLOAT fPosDist, BOOL bGoingToPlayer) + { + FLOAT fEnemyDistance = CalcDist(m_penEnemy); + FLOAT fCloseDistance = GetProp(m_fCloseDistance); + FLOAT fStopDistance = GetProp(m_fStopDistance); + // find relative direction angle + FLOAT fCos = GetPlaneFrustumAngle(vPosDelta); + // if may move and + if (MayMoveToAttack() && + // more or less ahead and + fCos>CosFast(45.0f) && + // not too close + fEnemyDistance>fStopDistance) { + // move and rotate towards it + if (fEnemyDistanceGetProp(m_fWalkSpeed)) { + RunningAnim(); + } else { + WalkingAnim(); + } + } else if (ulFlags&MF_ROTATEH) { + RotatingAnim(); + } else { + if (m_penEnemy!=NULL) { + StandingAnimFight(); + } else { + StandingAnim(); + } + } + } + + // set desired rotation and translation to go/orient towards desired position + // and get the resulting movement type + virtual ULONG SetDesiredMovement(void) + { + ULONG ulFlags = 0; + + // get delta to desired position + FLOAT3D vDelta = m_vDesiredPosition - GetPlacement().pl_PositionVector; + + // if we may rotate + if (m_aRotateSpeed>0.0f) { + // get desired heading orientation + FLOAT3D vDir = vDelta; + vDir.Normalize(); + ANGLE aWantedHeadingRelative = GetRelativeHeading(vDir); + + // normalize it to [-180,+180] degrees + aWantedHeadingRelative = NormalizeAngle(aWantedHeadingRelative); + + ANGLE aHeadingRotation; + // if desired position is left + if (aWantedHeadingRelative < -m_aRotateSpeed*m_fMoveFrequency) { + // start turning left + aHeadingRotation = -m_aRotateSpeed; + // if desired position is right + } else if (aWantedHeadingRelative > m_aRotateSpeed*m_fMoveFrequency) { + // start turning right + aHeadingRotation = +m_aRotateSpeed; + // if desired position is more-less ahead + } else { + // keep just the adjusting fraction of speed + aHeadingRotation = aWantedHeadingRelative/m_fMoveFrequency; + } + // start rotating + SetDesiredRotation(ANGLE3D(aHeadingRotation, 0, 0)); + + if (Abs(aHeadingRotation)>1.0f) { + ulFlags |= MF_ROTATEH; + } + + // if we may not rotate + } else { + // stop rotating + SetDesiredRotation(ANGLE3D(0, 0, 0)); + } + + // if we may move + if (m_fMoveSpeed>0.0f) { + // determine translation speed + FLOAT3D vTranslation(0.0f, 0.0f, 0.0f); + vTranslation(3) = -m_fMoveSpeed; + + // start moving + SetDesiredTranslation(vTranslation); + + ulFlags |= MF_MOVEZ; + + // if we may not move + } else { + // stop translating + SetDesiredTranslation(FLOAT3D(0, 0, 0)); + } + + return ulFlags; + }; + + // stop moving entity + void StopMoving() + { + StopRotating(); + StopTranslating(); + }; + + // stop desired rotation + void StopRotating() + { + SetDesiredRotation(ANGLE3D(0, 0, 0)); + }; + + // stop desired translation + void StopTranslating() + { + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + }; + + // calc distance to entity in one plane (relative to owner gravity) + FLOAT CalcDistanceInPlaneToDestination(void) + { + // find vector from you to target in XZ plane + FLOAT3D vNormal; + GetNormalComponent(m_vDesiredPosition - GetPlacement().pl_PositionVector, en_vGravityDir, vNormal); + return vNormal.Length(); + }; + + // initialize path finding + virtual void StartPathFinding(void) + { + ASSERT(m_dtDestination==DT_PATHPERSISTENT || m_dtDestination==DT_PATHTEMPORARY); + + CEntity *penMarker; + FLOAT3D vPath; + // find first marker to go to + PATH_FindFirstMarker(this, + GetPlacement().pl_PositionVector, m_penEnemy->GetPlacement().pl_PositionVector, + penMarker, vPath); + // if not found, or not visible + if (penMarker==NULL || !IsVisible(penMarker)) { + // no path finding + m_dtDestination=DT_PLAYERSPOTTED; + // remember as if spotted position + m_vPlayerSpotted = PlayerDestinationPos(); + return; + } + // remember the marker and position + m_vDesiredPosition = vPath, + m_penPathMarker = penMarker; + } + + // find next navigation marker to go to + virtual void FindNextPathMarker(void) + { + // if invalid situation + if (m_penPathMarker==NULL) { + // this should not happen + ASSERT(FALSE); + // no path finding + m_dtDestination=DT_PLAYERCURRENT; + return; + } + + // find first marker to go to + CEntity *penMarker = m_penPathMarker; + FLOAT3D vPath; + PATH_FindNextMarker(this, + GetPlacement().pl_PositionVector, m_penEnemy->GetPlacement().pl_PositionVector, + penMarker, vPath); + + // if not found + if (penMarker==NULL || !IsVisible(penMarker)) { + // no path finding + m_dtDestination=DT_PLAYERSPOTTED; + // remember as if spotted position + m_vPlayerSpotted = PlayerDestinationPos(); + return; + } + + // remember the marker and position + m_vDesiredPosition = vPath, + m_penPathMarker = penMarker; + } + + // check if a touch event triggers pathfinding + BOOL CheckTouchForPathFinding(const ETouch &eTouch) + { + // if no enemy + if (m_penEnemy==NULL) { + // do nothing + return FALSE; + } + + // if already path finding + if (m_dtDestination==DT_PATHPERSISTENT || m_dtDestination==DT_PATHTEMPORARY) { + // do nothing + return FALSE; + } + + FLOAT3D vDir = en_vDesiredTranslationRelative; + vDir.Normalize(); + vDir*=GetRotationMatrix(); + // if the touched plane is more or less orthogonal to the current velocity + if ((eTouch.plCollision%vDir)<-0.5f) { + if (m_penEnemy!=NULL && IsVisible(m_penEnemy)) { + m_dtDestination = DT_PATHPERSISTENT; + } else { + m_dtDestination = DT_PATHTEMPORARY; + } + StartPathFinding(); + return m_penPathMarker!=NULL; + } else { + return FALSE; + } + } + + // check if a wouldfall event triggers pathfinding + BOOL CheckFallForPathFinding(const EWouldFall &eWouldFall) + { + // if no enemy + if (m_penEnemy==NULL) { + // do nothing + return FALSE; + } + + // if already path finding + if (m_dtDestination==DT_PATHPERSISTENT || m_dtDestination==DT_PATHTEMPORARY) { + // do nothing + return FALSE; + } + + if (m_penEnemy!=NULL && IsVisible(m_penEnemy)) { + m_dtDestination = DT_PATHPERSISTENT; + } else { + m_dtDestination = DT_PATHTEMPORARY; + } + StartPathFinding(); + + return m_penPathMarker!=NULL; + } + + +/************************************************************ + * ATTACK SPECIFIC * + ************************************************************/ + // can attack (shoot) at entity in plane - ground support + BOOL CanAttackEnemy(CEntity *penTarget, FLOAT fCosAngle) { + if (IsInPlaneFrustum(penTarget, fCosAngle)) { + if (IsVisibleCheckAll(penTarget)) { + return TRUE; + } + } + return FALSE; + }; + + // close attack if possible + virtual BOOL CanHitEnemy(CEntity *penTarget, FLOAT fCosAngle) { + if (IsInFrustum(penTarget, fCosAngle)) { + return IsVisibleCheckAll(penTarget); + } + return FALSE; + }; + + // see entity + BOOL SeeEntity(CEntity *pen, FLOAT fCosAngle) { + if (IsInFrustum(pen, fCosAngle)) { + return IsVisible(pen); + } + return FALSE; + }; + + // see entity in plane + BOOL SeeEntityInPlane(CEntity *pen, FLOAT fCosAngle) { + CalcPlaneDist(pen); + if (IsInPlaneFrustum(pen, fCosAngle)) { + return IsVisible(pen); + } + return FALSE; + }; + + // prepare propelled projectile + void PreparePropelledProjectile(CPlacement3D &plProjectile, FLOAT3D vShootTarget, + const FLOAT3D &vOffset, const ANGLE3D &aOffset) + { + FLOAT3D vDiff = (vShootTarget - (GetPlacement().pl_PositionVector + vOffset*GetRotationMatrix())).Normalize(); + + // find orientation towards target + FLOAT3D mToTargetX, mToTargetY, mToTargetZ; + mToTargetZ = -vDiff; + mToTargetY = -en_vGravityDir; + mToTargetX = (mToTargetY*mToTargetZ).Normalize(); + mToTargetY = (mToTargetZ*mToTargetX).Normalize(); + FLOATmatrix3D mToTarget; + mToTarget(1,1) = mToTargetX(1); mToTarget(1,2) = mToTargetY(1); mToTarget(1,3) = mToTargetZ(1); + mToTarget(2,1) = mToTargetX(2); mToTarget(2,2) = mToTargetY(2); mToTarget(2,3) = mToTargetZ(2); + mToTarget(3,1) = mToTargetX(3); mToTarget(3,2) = mToTargetY(3); mToTarget(3,3) = mToTargetZ(3); + + // calculate placement of projectile to be at given offset + plProjectile.pl_PositionVector = GetPlacement().pl_PositionVector + vOffset*GetRotationMatrix(); + FLOATmatrix3D mDirection; + MakeRotationMatrixFast(mDirection, aOffset); + DecomposeRotationMatrixNoSnap(plProjectile.pl_OrientationAngle, mToTarget*mDirection); + }; + + // prepare free flying projectile + void PrepareFreeFlyingProjectile(CPlacement3D &plProjectile, FLOAT3D vShootTarget, + const FLOAT3D &vOffset, const ANGLE3D &aOffset) + { + FLOAT3D vDiff = (vShootTarget - (GetPlacement().pl_PositionVector + vOffset*GetRotationMatrix())).Normalize(); + + // find orientation towards target + FLOAT3D mToTargetX, mToTargetY, mToTargetZ; + mToTargetZ = -vDiff; + mToTargetY = -en_vGravityDir; + mToTargetX = (mToTargetY*mToTargetZ).Normalize(); + mToTargetZ = (mToTargetX*mToTargetY).Normalize(); + FLOATmatrix3D mToTarget; + mToTarget(1,1) = mToTargetX(1); mToTarget(1,2) = mToTargetY(1); mToTarget(1,3) = mToTargetZ(1); + mToTarget(2,1) = mToTargetX(2); mToTarget(2,2) = mToTargetY(2); mToTarget(2,3) = mToTargetZ(2); + mToTarget(3,1) = mToTargetX(3); mToTarget(3,2) = mToTargetY(3); mToTarget(3,3) = mToTargetZ(3); + + // calculate placement of projectile to be at given offset + plProjectile.pl_PositionVector = GetPlacement().pl_PositionVector + vOffset*GetRotationMatrix(); + FLOATmatrix3D mDirection; + MakeRotationMatrixFast(mDirection, aOffset); + DecomposeRotationMatrixNoSnap(plProjectile.pl_OrientationAngle, mToTarget*mDirection); + }; + + // shoot projectile on enemy + CEntity *ShootProjectile(enum ProjectileType pt, const FLOAT3D &vOffset, const ANGLE3D &aOffset) { + ASSERT(m_penEnemy != NULL); + + // target enemy body + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + + // launch + CPlacement3D pl; + PreparePropelledProjectile(pl, vShootTarget, vOffset, aOffset); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = pt; + penProjectile->Initialize(eLaunch); + + return penProjectile; + }; + + // shoot projectile on enemy + CEntity *ShootPredictedProjectile(enum ProjectileType pt, FLOAT3D vPredictedPos, const FLOAT3D &vOffset, const ANGLE3D &aOffset) { + ASSERT(m_penEnemy != NULL); + + // target enemy body (predicted) + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + FLOAT3D vShootTarget = vPredictedPos; + if (peiTarget != NULL) + { + // get body center vector + FLOAT3D vBody = FLOAT3D(peiTarget->vTargetCenter[0],peiTarget->vTargetCenter[1],peiTarget->vTargetCenter[2]); + FLOATmatrix3D mRotation; + MakeRotationMatrixFast(mRotation, m_penEnemy->GetPlacement().pl_OrientationAngle); + vShootTarget = vPredictedPos + vBody*mRotation; + } + // launch + CPlacement3D pl; + PreparePropelledProjectile(pl, vShootTarget, vOffset, aOffset); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = pt; + penProjectile->Initialize(eLaunch); + + return penProjectile; + }; + + BOOL WouldNotLeaveAttackRadius(void) + { + if (m_fAttackRadius<=0) { + return FALSE; + } + // test if we are inside radius + BOOL bInsideNow = (m_vStartPosition-GetPlacement().pl_PositionVector).Length() < m_fAttackRadius; + // test if going towards enemy leads us to center of attack radius circle + BOOL bEnemyTowardsCenter = + (m_vStartPosition-m_penEnemy->GetPlacement().pl_PositionVector).Length() < + (GetPlacement().pl_PositionVector-m_penEnemy->GetPlacement().pl_PositionVector).Length(); + return bInsideNow || bEnemyTowardsCenter; + } + + // check whether may move while attacking + virtual BOOL MayMoveToAttack(void) + { + // check if enemy is diving + CMovableEntity *pen = (CMovableEntity *)&*m_penEnemy; + CContentType &ctUp = pen->en_pwoWorld->wo_actContentTypes[pen->en_iUpContent]; + BOOL bEnemyDiving = !(ctUp.ct_ulFlags&CTF_BREATHABLE_LUNGS); + // may move if can go to enemy without leaving attack radius, and entity is not diving + return WouldNotLeaveAttackRadius() && !bEnemyDiving; + }; + + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + // should this enemy blow up (spawn debris) + virtual BOOL ShouldBlowUp(void) + { + // blow up if + return + // allowed + GetSP()->sp_bGibs && + // dead and + GetHealth()<=0 && + // has received large enough damage lately and + m_vDamage.Length() > m_fBlowUpAmount && + // not already disappearing + m_fSpiritStartTime==0; + } + + + // base function for blowing up + void BlowUpBase(void) + { + // call derived function + BlowUp(); + } + + + // spawn body parts + virtual void BlowUp(void) + { + // blow up notify + BlowUpNotify(); + const BOOL bGibs = GetSP()->sp_bGibs; + + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + vNormalizedDamage *= 0.75f; + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + + // if allowed and fleshy + if( bGibs && !m_bRobotBlowup) + { + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + // determine debris texture (color) + ULONG ulFleshTexture = TEXTURE_FLESH_GREEN; + ULONG ulFleshModel = MODEL_FLESH; + if( iBloodType==2) { ulFleshTexture = TEXTURE_FLESH_RED; } + // spawn debris + Debris_Begin(EIBT_FLESH, DPT_BLOODTRAIL, BET_BLOODSTAIN, m_fBlowUpSize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); + for( INDEX iDebris = 0; iDebrisInitialize(eSpawnEffect); + } + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + } + + +/************************************************************ + * CLASS SUPPORT FUNCTIONS * + ************************************************************/ + + // leave stain + virtual void LeaveStain( BOOL bGrow) + { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + + // on plane + if( GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + // if near to polygon and away from last stain point + if( (vPoint-GetPlacement().pl_PositionVector).Length()<0.5f + && (m_vLastStain-vPoint).Length()>1.0f ) { + m_vLastStain = vPoint; + FLOAT fStretch = box.Size().Length(); + ese.colMuliplier = C_WHITE|CT_OPAQUE; + // stain + if (bGrow) { + ese.betType = BET_BLOODSTAINGROW; + ese.vStretch = FLOAT3D( fStretch*1.5f, fStretch*1.5f, 1.0f); + } else { + ese.betType = BET_BLOODSTAIN; + ese.vStretch = FLOAT3D( fStretch*0.75f, fStretch*0.75f, 1.0f); + } + ese.vNormal = FLOAT3D( vPlaneNormal); + ese.vDirection = FLOAT3D( 0, 0, 0); + FLOAT3D vPos = vPoint+ese.vNormal/50.0f*(FRnd()+0.5f); + CEntityPointer penEffect = CreateEntity( CPlacement3D(vPos, ANGLE3D(0,0,0)), CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + } + }; + + virtual void AdjustDifficulty(void) + { + FLOAT fMoveSpeed = GetSP()->sp_fEnemyMovementSpeed; + FLOAT fAttackSpeed = GetSP()->sp_fEnemyMovementSpeed; +// m_fWalkSpeed *= fMoveSpeed; +// m_aWalkRotateSpeed *= fMoveSpeed; + m_fAttackRunSpeed *= fMoveSpeed; + m_aAttackRotateSpeed *= fMoveSpeed; + m_fCloseRunSpeed *= fMoveSpeed; + m_aCloseRotateSpeed *= fMoveSpeed; + m_fAttackFireTime *= 1/fAttackSpeed; + m_fCloseFireTime *= 1/fAttackSpeed; +/* + CSessionProperties::GameDificulty gd = GetSP()->sp_gdGameDificulty; + + switch(gd) { + case CSessionProperties::GD_EASY: { + } break; + case CSessionProperties::GD_NORMAL: { + } break; + case CSessionProperties::GD_HARD: { + } break; + case CSessionProperties::GD_SERIOUS: { + } break; + } + */ + } + + +/************************************************************ + * SOUND VIRTUAL FUNCTIONS * + ************************************************************/ + + // wounded -> yell + void WoundedNotify(const EDamage &eDamage) + { + // if no enemy + if (m_penEnemy==NULL) { + // do nothing + return; + } + + // if not killed from short distance + if (eDamage.dmtType!=DMT_CLOSERANGE) { + // yell + ESound eSound; + eSound.EsndtSound = SNDT_YELL; + eSound.penTarget = m_penEnemy; + SendEventInRange(eSound, FLOATaabbox3D(GetPlacement().pl_PositionVector, 25.0f)); + } + }; + + // see enemy -> shout + void SeeNotify() + { + // if no enemy + if (m_penEnemy==NULL) { + // do nothing + return; + } + // yell + ESound eSound; + eSound.EsndtSound = SNDT_SHOUT; + eSound.penTarget = m_penEnemy; + SendEventInRange(eSound, FLOATaabbox3D(GetPlacement().pl_PositionVector, 50.0f)); + }; + + + +/************************************************************ + * VIRTUAL FUNCTIONS THAT NEED OVERRIDE * + ************************************************************/ + virtual void StandingAnim(void) {}; + virtual void StandingAnimFight(void) { StandingAnim(); }; + virtual void WalkingAnim(void) {}; + virtual void RunningAnim(void) {}; + virtual void RotatingAnim(void) {}; + virtual void ChargeAnim(void) {}; + virtual INDEX AnimForDamage(FLOAT fDamage) { return 0; }; + virtual void BlowUpNotify(void) {}; + virtual INDEX AnimForDeath(void) { return 0; }; + virtual void DeathNotify(void) {}; + virtual void IdleSound(void) {}; + virtual void SightSound(void) {}; + virtual void WoundSound(void) {}; + virtual void DeathSound(void) {}; + virtual FLOAT GetLockRotationSpeed(void) { return 2000.0f;}; + + + // render particles + void RenderParticles(void) { + // no particles when not existing + if (GetRenderType()!=CEntity::RT_MODEL) { + return; + } + // if is dead + if( m_fSpiritStartTime != 0.0f) + { + Particles_Death(this, m_fSpiritStartTime); + } + } + + // adjust sound and watcher parameters here if needed + virtual void EnemyPostInit(void) {}; + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if (ee.ee_slEvent==EVENTCODE_ETouch) + { + if( GetCrushHealth() != 0.0f) + { + ETouch eTouch = ((ETouch &) ee); + if (IsOfClass(eTouch.penOther, "ModelHolder2") || + IsOfClass(eTouch.penOther, "MovingBrush") || + IsOfClass(eTouch.penOther, "DestroyableArchitecture") ) + { + InflictDirectDamage(eTouch.penOther, this, DMT_EXPLOSION, GetCrushHealth(), + eTouch.penOther->GetPlacement().pl_PositionVector, -(FLOAT3D&)eTouch.plCollision); + } + } + } + return CMovableModelEntity::HandleEvent(ee); + } + +procedures: + +//********************************************************** +// MOVEMENT PROCEDURES +//********************************************************** + + // move to given destination position + MoveToDestination(EVoid) + { + // setup parameters + m_fMoveFrequency = 0.25f; + m_fMoveTime = _pTimer->CurrentTick() + 45.0f; + // while not there and time not expired + while (CalcDistanceInPlaneToDestination()>m_fMoveSpeed*m_fMoveFrequency*2.0f && + m_fMoveTime>_pTimer->CurrentTick()) { + // every once in a while + wait (m_fMoveFrequency) { + on (EBegin) : { + // adjust direction and speed + ULONG ulFlags = SetDesiredMovement(); + MovementAnimation(ulFlags); + resume; + } + on (ETimer) : { stop; } + } + } + + // return to the caller + return EReturn(); + }; + + // go to next randomly choosen position inside patrol range + MoveToRandomPatrolPosition(EVoid) + { + // if the marker is invalid + if (!IsOfClass(m_penMarker, "Enemy Marker")) { + // this should not happen + ASSERT(FALSE); + // return to caller + return EReturn(); + } + // get the marker + CEnemyMarker *pem = (CEnemyMarker *)&*m_penMarker; + + // get random destination position + FLOAT fMin = pem->m_fPatrolAreaInner; + FLOAT fMax = pem->m_fPatrolAreaOuter; + if (fMin<0) { + fMin = 0; + } + if (fMaxSendEvent(EStart()); + + // stand in place + StandingAnim(); + + // repeat forever + while(TRUE) { + // wait some time + autowait(Lerp(5.0f, 20.0f, FRnd())); + // play idle sound + IdleSound(); + } + } + + // return to start position + ReturnToStartPosition(EVoid) + { + jump BeIdle(); +/* + // start watching + GetWatcher()->SendEvent(EStart()); + + m_vDesiredPosition = m_vStartPosition; + m_vStartDirection = (GetPlacement().pl_PositionVector-m_vStartPosition).Normalize(); + m_fMoveSpeed = GetProp(m_fAttackRunSpeed); + m_aRotateSpeed = GetProp(m_aAttackRotateSpeed); + RunningAnim(); + autocall MoveToDestination() EReturn; + + WalkingAnim(); + m_vDesiredAngle = m_vStartDirection; + StopTranslating(); + + autocall RotateToStartDirection() EReturn; + + StopMoving(); + StandingAnim(); + + jump BeIdle(); + */ + }; + /* + // rotate to destination + RotateToStartDirection(EVoid) + { + + m_fMoveFrequency = 0.1f; + m_fMoveTime = _pTimer->CurrentTick() + 45.0f; + while (Abs(GetRelativeHeading(GetDesiredPositionDir()))>GetProp(m_aRotateSpeed)*m_fMoveFrequency*1.5f && + m_fMoveTime>_pTimer->CurrentTick()) { + autowait(m_fMoveFrequency); + } + + return EReturn(); + }; + */ + + + // move through markers + MoveThroughMarkers() + { + // start watching + GetWatcher()->SendEvent(EStart()); + + // while there is a valid marker, take values from it + while (m_penMarker!=NULL && IsOfClass(m_penMarker, "Enemy Marker")) { + CEnemyMarker *pem = (CEnemyMarker *)&*m_penMarker; + + // the marker position is our new start position for attack range + m_vStartPosition = m_penMarker->GetPlacement().pl_PositionVector; + // make a random position to walk to at the marker + FLOAT fR = FRnd()*pem->m_fMarkerRange; + FLOAT fA = FRnd()*360.0f; + m_vDesiredPosition = m_vStartPosition+FLOAT3D(CosFast(fA)*fR, 0, SinFast(fA)*fR); + // if running + if (pem->m_betRunToMarker==BET_TRUE) { + // use attack speeds + m_fMoveSpeed = GetProp(m_fAttackRunSpeed); + m_aRotateSpeed = GetProp(m_aAttackRotateSpeed); + // start running anim + RunningAnim(); + // if not running + } else { + // use walk speeds + m_fMoveSpeed = GetProp(m_fWalkSpeed); + m_aRotateSpeed = GetProp(m_aWalkRotateSpeed); + // start walking anim + WalkingAnim(); + } + + // move to the new destination position + autocall MoveToDestination() EReturn; + + // read new blind/deaf values + CEnemyMarker *pem = (CEnemyMarker *)&*m_penMarker; + SetBoolFromBoolEType(m_bBlind, pem->m_betBlind); + SetBoolFromBoolEType(m_bDeaf, pem->m_betDeaf); + + // if should patrol there + if (pem->m_fPatrolTime>0.0f) { + // spawn a reminder to notify us when the time is up + SpawnReminder(this, pem->m_fPatrolTime, 0); + // wait + wait() { + // initially + on (EBegin) : { + // start patroling + call DoPatrolling(); + } + // if time is up + on (EReminder) : { + // stop patroling + stop; + } + } + } + + CEnemyMarker *pem = (CEnemyMarker *)&*m_penMarker; + // if should wait on the marker + if (pem->m_fWaitTime > 0.0f) { + // stop there + StopMoving(); + StandingAnim(); + // wait + autowait(pem->m_fWaitTime); + } + + // wait a bit always (to prevent eventual busy-looping) + autowait(0.05f); + + // take next marker in loop + m_penMarker = ((CEnemyMarker&)*m_penMarker).m_penTarget; + } // when no more markers + + // stop where you are + StopMoving(); + StandingAnim(); + + // return to called + return EReturn(); + }; + + +//********************************************************** +// ATTACK PROCEDURES +//********************************************************** + + // sequence that is activated when a new player is spotted visually or heard + NewEnemySpotted() + { + // calculate reflex time + FLOAT tmReflex = Lerp(m_tmReflexMin, m_tmReflexMax, FRnd()); + tmReflex = ClampDn(tmReflex, 0.0f); + + // if should wait + if (tmReflex>=_pTimer->TickQuantum) { + // stop where you are + StopMoving(); + StandingAnim(); + + // wait the reflex time + wait(tmReflex) { + on (ETimer) : { stop; } + // pass all damage events + on (EDamage) : { pass; } + // pass space beam hit + on (EHitBySpaceShipBeam) : { pass;} + // ignore all other events + otherwise () : { resume; } + } + } + + // play sight sound + SightSound(); + + // return to caller + return EReturn(); + } + + // stop attack + StopAttack(EVoid) { + // start watching + GetWatcher()->SendEvent(EStart()); + // no damager + SetTargetNone(); + m_fDamageConfused = 0.0f; + // stop moving + StopMoving(); + + return EReturn(); + }; + + // initial preparation + InitializeAttack(EVoid) + { + // disable blind/deaf mode + m_bBlind = FALSE; + m_bDeaf = FALSE; + + SeeNotify(); // notify seeing + GetWatcher()->SendEvent(EStop()); // stop looking + // make fuss + AddToFuss(); + // remember spotted position + m_vPlayerSpotted = PlayerDestinationPos(); + + // set timers + if (CalcDist(m_penEnemy)CurrentTick() + FRnd(); + } + m_fDamageConfused = m_fDamageWounded; + + return EReturn(); + }; + + + // attack enemy + AttackEnemy(EVoid) { + // initial preparation + autocall InitializeAttack() EReturn; + + // while you have some enemy + while (m_penEnemy != NULL) { + // attack it + autocall PerformAttack() EReturn; + } + + // stop attack + autocall StopAttack() EReturn; + + // return to Active() procedure + return EBegin(); + }; + + // repeat attacking enemy until enemy is dead or you give up + PerformAttack() + { + // reset last range + m_fRangeLast = 1E9f; + + // set player's position as destination position + m_vDesiredPosition = PlayerDestinationPos(); + m_dtDestination = DT_PLAYERCURRENT; + + // repeat + while(TRUE) + { + // if attacking is futile + if (ShouldCeaseAttack()) { + // cease it + SetTargetNone(); + return EReturn(); + } + + // get distance from enemy + FLOAT fEnemyDistance = CalcDist(m_penEnemy); + // if just entered close range + if (m_fRangeLast>GetProp(m_fCloseDistance) && fEnemyDistance<=GetProp(m_fCloseDistance)) { + // reset shoot time to make it attack immediately + m_fShootTime = 0.0f; + } + m_fRangeLast = fEnemyDistance; + + // determine movement frequency depending on enemy distance or path finding + m_fMoveFrequency = GetAttackMoveFrequency(fEnemyDistance); + if (m_dtDestination==DT_PATHPERSISTENT||m_dtDestination==DT_PATHTEMPORARY) { + m_fMoveFrequency = 0.1f; + } + + // wait one time interval + wait(m_fMoveFrequency) { + on (ETimer) : { stop; } + // initially + on (EBegin) : { + + // if you haven't fired/hit enemy for some time + if (_pTimer->CurrentTick() > m_fShootTime) { + + // if you have new player visible closer than current and in threat distance + CEntity *penNewEnemy = GetWatcher()->CheckCloserPlayer(m_penEnemy, GetThreatDistance()); + if (penNewEnemy!=NULL) { + // switch to that player + SetTargetHardForce(penNewEnemy); + // start new behavior + SendEvent(EReconsiderBehavior()); + stop; + } + + // if you can see player + if (IsVisible(m_penEnemy)) { + // remember spotted position + m_vPlayerSpotted = PlayerDestinationPos(); + // if going to player spotted or temporary path position + if (m_dtDestination==DT_PLAYERSPOTTED||m_dtDestination==DT_PATHTEMPORARY) { + // switch to player current position + m_dtDestination=DT_PLAYERCURRENT; + } + + // if you cannot see player + } else { + // if going to player's current position + if (m_dtDestination==DT_PLAYERCURRENT) { + // switch to position where player was last seen + m_dtDestination=DT_PLAYERSPOTTED; + } + } + + // try firing/hitting again now + call FireOrHit(); + + // if between two fire/hit monents + } else { + // if going to player spotted or temporary path position and you just seen the player + if ((m_dtDestination==DT_PLAYERSPOTTED||m_dtDestination==DT_PATHTEMPORARY) + && IsVisible(m_penEnemy)) { + // switch to player current position + m_dtDestination=DT_PLAYERCURRENT; + // remember spotted position + m_vPlayerSpotted = PlayerDestinationPos(); + } + } + + // if you are not following the player and you are near current destination position + FLOAT fAllowedError = m_fMoveSpeed*m_fMoveFrequency*2.0f; + if (m_dtDestination==DT_PATHPERSISTENT||m_dtDestination==DT_PATHTEMPORARY) { + fAllowedError = ((CNavigationMarker&)*m_penPathMarker).m_fMarkerRange; + } + if (m_dtDestination!=DT_PLAYERCURRENT && + (CalcDistanceInPlaneToDestination()CurrentTick() + GetProp(m_fCloseFireTime)*(1.0f + FRnd()/3.0f); + // hit + autocall Hit() EReturn; + + // else if player is in fire range and in front + } else if (CalcDist(m_penEnemy)CurrentTick() + GetProp(m_fCloseFireTime)*(1.0f + FRnd()/3.0f); + } else { + m_fShootTime = _pTimer->CurrentTick() + GetProp(m_fAttackFireTime)*(1.0f + FRnd()/3.0f); + } + // fire + autocall Fire() EReturn; + + // if cannot fire nor hit + } else { + // make sure we don't retry again too soon + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + } + + // return to caller + return EReturn(); + }; + +//********************************************************** +// COMBAT IMPLEMENTATION +//********************************************************** + + // this is called to hit the player when near + Hit(EVoid) + { + return EReturn(); + } + + // this is called to shoot at player when far away or otherwise unreachable + Fire(EVoid) + { + return EReturn(); + } + +//********************************************************** +// COMBAT HELPERS +//********************************************************** + + // call this to lock on player for some time - set m_fLockOnEnemyTime before calling + LockOnEnemy(EVoid) + { + // stop moving + StopMoving(); + // play animation for locking + ChargeAnim(); + // wait charge time + m_fLockStartTime = _pTimer->CurrentTick(); + while (m_fLockStartTime+GetProp(m_fLockOnEnemyTime) > _pTimer->CurrentTick()) { + // each tick + m_fMoveFrequency = 0.05f; + wait (m_fMoveFrequency) { + on (ETimer) : { stop; } + on (EBegin) : { + m_vDesiredPosition = PlayerDestinationPos(); + // if not heading towards enemy + if (!IsInPlaneFrustum(m_penEnemy, CosFast(5.0f))) { + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = GetLockRotationSpeed(); + // if heading towards enemy + } else { + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = 0.0f; + } + // adjust direction and speed + ULONG ulFlags = SetDesiredMovement(); + //MovementAnimation(ulFlags); don't do this, or they start to jive + resume; + } + } + } + // stop rotating + StopRotating(); + + // return to caller + return EReturn(); + }; + + // call this to jump onto player - set charge properties before calling and spawn a reminder + ChargeHitEnemy(EVoid) + { + // wait for length of hit animation + wait(GetModelObject()->GetAnimLength(m_iChargeHitAnimation)) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + // ignore damages + on (EDamage) : { resume; } + // if user-set reminder expired + on (EReminder) : { + // stop moving + StopMoving(); + resume; + } + // if you touch some entity + on (ETouch etouch) : { + // if it is alive and in front + if ((etouch.penOther->GetFlags()&ENF_ALIVE) && IsInPlaneFrustum(etouch.penOther, CosFast(60.0f))) { + // get your direction + FLOAT3D vSpeed; + GetHeadingDirection(m_fChargeHitAngle, vSpeed); + // damage entity in that direction + InflictDirectDamage(etouch.penOther, this, DMT_CLOSERANGE, m_fChargeHitDamage, FLOAT3D(0, 0, 0), vSpeed); + // push it away + vSpeed = vSpeed * m_fChargeHitSpeed; + KickEntity(etouch.penOther, vSpeed); + // stop waiting + stop; + } + pass; + } + } + // if the anim is not yet finished + if (!GetModelObject()->IsAnimFinished()) { + // wait the rest of time till the anim end + wait(GetModelObject()->GetCurrentAnimLength() - GetModelObject()->GetPassedTime()) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + // if timer expired + on (EReminder) : { + // stop moving + StopMoving(); + resume; + } + } + } + + // return to caller + return EReturn(); + }; + +//********************************************************** +// WOUNDING AND DYING PROCEDURES +//********************************************************** + + // play wounding animation + BeWounded(EDamage eDamage) + { + StopMoving(); + // determine damage anim and play the wounding + autowait(GetModelObject()->GetAnimLength(AnimForDamage(eDamage.fAmount))); + return EReturn(); + }; + + // we get here once the enemy is dead + Die(EDeath eDeath) + { + // not alive anymore + SetFlags(GetFlags()&~ENF_ALIVE); + + // find the one who killed, or other best suitable player + CEntityPointer penKiller = eDeath.eLastDamage.penInflictor; + if (penKiller==NULL || !IsOfClass(penKiller, "Player")) { + penKiller = m_penEnemy; + } + + if (penKiller==NULL || !IsOfClass(penKiller, "Player")) { + penKiller = FixupCausedToPlayer(this, penKiller, /*bWarning=*/FALSE); + } + + // if killed by someone + if (penKiller!=NULL) { + // give him score + EReceiveScore eScore; + eScore.iPoints = m_iScore; + penKiller->SendEvent(eScore); + if( CountAsKill()) + { + penKiller->SendEvent(EKilledEnemy()); + } + // send computer message + EComputerMessage eMsg; + eMsg.fnmMessage = GetComputerMessageName(); + if (eMsg.fnmMessage!="") { + penKiller->SendEvent(eMsg); + } + } + + + // destroy watcher class + GetWatcher()->SendEvent(EStop()); + GetWatcher()->SendEvent(EEnd()); + + // send event to death target + SendToTarget(m_penDeathTarget, m_eetDeathType, penKiller); + // send event to spawner if any + if (m_penSpawnerTarget) { + SendToTarget(m_penSpawnerTarget, EET_TRIGGER, penKiller); + } + + + // wait + wait() { + // initially + on (EBegin) : { + // if should already blow up + if (ShouldBlowUp()) { + // blow up now + BlowUpBase(); + // stop waiting + stop; + // if shouldn't blow up yet + } else { + // invoke death animation sequence + call DeathSequence(); + } + } + // if damaged + on (EDamage) : { + // if should already blow up + if (ShouldBlowUp()) { + // blow up now + BlowUpBase(); + // stop waiting + stop; + } + // otherwise, ignore the damage + resume; + } + // if death sequence is over + on (EEnd) : { + // stop waiting + stop; + } + } + + // stop making fuss + RemoveFromFuss(); + // cease to exist + Destroy(); + + // all is over now, entity will be deleted + return; + }; + + Death(EVoid) + { + StopMoving(); // stop moving + DeathSound(); // death sound + LeaveStain(FALSE); + + // set physic flags + SetPhysicsFlags(EPF_MODEL_CORPSE); + SetCollisionFlags(ECF_CORPSE); + SetFlags(GetFlags() | ENF_SEETHROUGH); + + // stop making fuss + RemoveFromFuss(); + + // death notify (usually change collision box and change body density) + DeathNotify(); + + // start death anim + INDEX iAnim = AnimForDeath(); + autowait(GetModelObject()->GetAnimLength(iAnim)); + + return EEnd(); + }; + + DeathSequence(EVoid) + { + // entity death + autocall Death() EEnd; + + // start bloody stain growing out from beneath the corpse + LeaveStain(TRUE); + autowait(2.0f); + + // start fading out and turning into stardust effect + m_fSpiritStartTime = _pTimer->CurrentTick(); + m_fFadeStartTime = _pTimer->CurrentTick(); + m_fFadeTime = 1.0f, + m_bFadeOut = TRUE; + // become passable even if very large corpse + SetCollisionFlags(ECF_CORPSE&~((ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID)< stop enemy + on (EStop) : { + jump Inactive(); + } + + // warn for all obsolete events + on (EStartAttack) : { + //CPrintF("%s: StartAttack event is obsolete!\n", GetName()); + resume; + } + on (EStopAttack) : { + //CPrintF("%s: StopAttack event is obsolete!\n", GetName()); + resume; + } + } + }; + + // not doing anything, waiting until some player comes close enough to start patroling or similar + Inactive(EVoid) + { + // stop moving + StopMoving(); + StandingAnim(); + // start watching + GetWatcher()->SendEvent(EStart()); + // wait forever + wait() { + on (EBegin) : { resume; } + // if watcher detects that a player is near + on (EStart) : { + // become active (patroling etc.) + jump Active(); + } + // if returned from wounding + on (EReturn) : { + // become active (this will attack the enemy) + jump Active(); + } + // if triggered manually + on (ETrigger eTrigger) : { + CEntity *penCaused = FixupCausedToPlayer(this, eTrigger.penCaused); + // if can set the trigerer as soft target + if (SetTargetSoft(penCaused)) { + // become active (this will attack the player) + jump Active(); + } + } + // if you get damaged by someone + on (EDamage eDamage) : { + // if can set the damager as hard target + if (SetTargetHard(eDamage.penInflictor)) { + // notify wounding to others + WoundedNotify(eDamage); + // make pain sound + WoundSound(); + // play wounding animation + call BeWounded(eDamage); + } + } + } + }; + + // overridable called before main enemy loop actually begins + PreMainLoop(EVoid) + { + return EReturn(); + } + + // main entry point for enemy behavior + MainLoop(EVoid) + { + // setup some model parameters that are global for all enemies + CEnemyBase::StretchModel(); + // check that max health is properly set + ASSERT(m_fMaxHealth==GetHealth() || IsOfClass(this, "Devil")); + // normalize parameters + if (m_tmReflexMin<0) { + m_tmReflexMin = 0.0f; + } + if (m_tmReflexMin>m_tmReflexMax) { + m_tmReflexMax = m_tmReflexMin; + } + + // adjust falldown and step up values + if (m_fStepHeight==-1) { + m_fStepHeight = 2.0f; + } + + // if this is a template + if (m_bTemplate) { + // do nothing at all + return; + } + + // wait for just one tick + // NOTES: + // if spawned, we have to wait a bit after spawning for spawner to teleport us into proper place + // if placed directly, we have to wait for game to start (not to start behaving while in editor) + // IMPORTANT: + // this wait amount has to be lower than the one in music holder, so that the enemies are initialized before + // they get counted + autowait(_pTimer->TickQuantum); + + // spawn your watcher + m_penWatcher = CreateEntity(GetPlacement(), CLASS_WATCHER); + EWatcherInit eInitWatcher; + eInitWatcher.penOwner = this; + GetWatcher()->Initialize(eInitWatcher); + + // switch to next marker (enemies usually point to the marker they stand on) + if (m_penMarker!=NULL && IsOfClass(m_penMarker, "Enemy Marker")) { + CEnemyMarker *pem = (CEnemyMarker *)&*m_penMarker; + m_penMarker = pem->m_penTarget; + } + + + // store starting position + m_vStartPosition = GetPlacement().pl_PositionVector; + + // set sound default parameters + m_soSound.Set3DParameters(80.0f, 5.0f, 1.0f, 1.0f); + + // adjust falldown and step up values + en_fStepUpHeight = m_fStepHeight+0.01f; + en_fStepDnHeight = m_fFallHeight+0.01f; + + // let derived class(es) adjust parameters if needed + EnemyPostInit(); + + // adjust your difficulty + AdjustDifficulty(); + + // check enemy params + ASSERT(m_fStopDistance>=0); + ASSERT(m_fCloseDistance>=0); + ASSERT(m_fAttackDistance>m_fCloseDistance); + ASSERT(m_fIgnoreRange>m_fAttackDistance); + + SetPredictable(TRUE); + + autocall PreMainLoop() EReturn; + + jump StandardBehavior(); + } + + StandardBehavior(EVoid) + { + // this is the main enemy loop + wait() { + // initially + on (EBegin) : { + // start in active or inactive state + if (m_penEnemy!=NULL) { + call Active(); + } else { + call Inactive(); + } + }; + // if dead + on (EDeath eDeath) : { + // die + jump Die(eDeath); + } + // if an entity exits a teleport nearby + on (ETeleport et) : { + // proceed message to watcher (so watcher can quickly recheck for players) + GetWatcher()->SendEvent(et); + resume; + } + // if should stop being blind + on (EStopBlindness) : { + // stop being blind + m_bBlind = FALSE; + resume; + } + // if should stop being deaf + on (EStopDeafness) : { + // stop being deaf + m_bDeaf = FALSE; + resume; + } + // support for jumping using bouncers + on (ETouch eTouch) : { + IfTargetCrushed(eTouch.penOther, (FLOAT3D&)eTouch.plCollision); + if (IsOfClass(eTouch.penOther, "Bouncer")) { + JumpFromBouncer(this, eTouch.penOther); + } + resume; + } + } + }; + + // dummy main - never called + Main(EVoid) { + return; + }; +}; diff --git a/Sources/Entities/EnemyCounter.es b/Sources/Entities/EnemyCounter.es new file mode 100644 index 0000000..049b8fe --- /dev/null +++ b/Sources/Entities/EnemyCounter.es @@ -0,0 +1,105 @@ +339 +%{ +#include "Entities/StdH/StdH.h" +#include +%} + +class CEnemyCounter : CRationalEntity { +name "EnemyCounter"; +thumbnail "Thumbnails\\Counter.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CEntityPointer m_penMainMusicHolder, + 2 CTString m_strName "Name" 'N' ="", + 4 INDEX m_iCountFrom "Count start" 'A' = 100, + 5 INDEX m_iCount = -1, + +components: + 0 sound SOUND_TICK "Sounds\\Menu\\Select.wav", + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + +functions: + class CMusicHolder *GetMusicHolder() + { + if (m_penMainMusicHolder==NULL) { + m_penMainMusicHolder = _pNetwork->GetEntityWithName("MusicHolder", 0); + } + return (CMusicHolder *)&*m_penMainMusicHolder; + } + void StartCounting(void) + { + CMusicHolder *pmh = GetMusicHolder(); + if (pmh==NULL) { + return; + } + pmh->m_penCounter = this; + m_iCount = m_iCountFrom; + } + void CountOne(void) + { + if (m_iCount>0) { + m_iCount-=1; + } + } + void StopCounting(void) + { + CMusicHolder *pmh = GetMusicHolder(); + if (pmh==NULL) { + return; + } + m_iCount = 0; + pmh->m_penCounter = NULL; + } +procedures: + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + autowait(0.1f); + + wait() { + on(EBegin): { + resume; + } + // when started + on (EStart): { + StartCounting(); + resume; + } + // when stopped + on (EStop): { + StopCounting(); + resume; + } + // when triggered + on (ETrigger): { + // if not started yet + if (m_iCount==-1) { + // start + StartCounting(); + } + CountOne(); + // if finished + if (m_iCount==0) { + // stop + StopCounting(); + } + resume; + } + } + + return; + } +}; diff --git a/Sources/Entities/EnemyDive.es b/Sources/Entities/EnemyDive.es new file mode 100644 index 0000000..4254713 --- /dev/null +++ b/Sources/Entities/EnemyDive.es @@ -0,0 +1,250 @@ +313 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Debris"; +uses "Entities/EnemyMarker"; + + +enum EnemyDiveType { + 0 EDT_GROUND_ONLY "Ground only", // can't dive + 1 EDT_DIVE_ONLY "Dive only", // always dive can't walk + 2 EDT_GROUND_DIVE "Ground and dive", // dive and walk +}; + + +class export CEnemyDive : CEnemyBase { +name "Enemy Dive"; +thumbnail ""; + +properties: + 1 enum EnemyDiveType m_EedtType "Type" 'T' = EDT_DIVE_ONLY, // dive type + 2 BOOL m_bInLiquid "In liquid" 'Q' = TRUE, // entity is in liquid + + // moving/attack properties - CAN BE SET + // these following must be ordered exactly like this for GetProp() to function + 10 FLOAT m_fDiveWalkSpeed = 1.0f, // dive walk speed + 11 ANGLE m_aDiveWalkRotateSpeed = AngleDeg(10.0f), // dive walk rotate speed + 12 FLOAT m_fDiveAttackRunSpeed = 1.0f, // dive attack run speed + 13 ANGLE m_aDiveAttackRotateSpeed = AngleDeg(10.0f), // dive attack rotate speed + 14 FLOAT m_fDiveCloseRunSpeed = 1.0f, // dive close run speed + 15 ANGLE m_aDiveCloseRotateSpeed = AngleDeg(10.0f), // dive close rotate speed + 20 FLOAT m_fDiveAttackDistance = 50.0f, // dive attack distance mode + 21 FLOAT m_fDiveCloseDistance = 10.0f, // dive close distance mode + 22 FLOAT m_fDiveAttackFireTime = 2.0f, // dive attack distance fire time + 23 FLOAT m_fDiveCloseFireTime = 1.0f, // dive close distance fire time + 24 FLOAT m_fDiveStopDistance = 0.0f, // dive stop moving toward enemy if closer than stop distance + 25 FLOAT m_fDiveIgnoreRange = 200.0f, // dive cease attack if enemy farther + 26 FLOAT m_fDiveLockOnEnemyTime = 0.0f, // dive time needed to fire + +components: + 1 class CLASS_BASE "Classes\\EnemyBase.ecl", + +functions: + // overridable function for access to different properties of derived classes (flying/diving) + virtual FLOAT &GetProp(FLOAT &m_fBase) + { + if (m_bInLiquid) { + return *((&m_fBase)+(&m_fDiveWalkSpeed-&m_fWalkSpeed)); + } else { + return m_fBase; + } + } + + // diving enemies never use pathfinding + void StartPathFinding(void) + { + m_dtDestination=DT_PLAYERSPOTTED; + m_vPlayerSpotted = PlayerDestinationPos(); + } + + virtual void AdjustDifficulty(void) + { + FLOAT fMoveSpeed = GetSP()->sp_fEnemyMovementSpeed; + FLOAT fAttackSpeed = GetSP()->sp_fEnemyMovementSpeed; +// m_fDiveWalkSpeed *= fMoveSpeed; +// m_aDiveWalkRotateSpeed *= fMoveSpeed; + m_fDiveAttackRunSpeed *= fMoveSpeed; + m_aDiveAttackRotateSpeed *= fMoveSpeed; + m_fDiveCloseRunSpeed *= fMoveSpeed; + m_aDiveCloseRotateSpeed *= fMoveSpeed; + m_fDiveAttackFireTime *= 1/fAttackSpeed; + m_fDiveCloseFireTime *= 1/fAttackSpeed; + m_fDiveLockOnEnemyTime *= 1/fAttackSpeed; + + CEnemyBase::AdjustDifficulty(); + } + // close attack if possible + virtual BOOL CanHitEnemy(CEntity *penTarget, FLOAT fCosAngle) { + if (IsInPlaneFrustum(penTarget, fCosAngle)) { + return IsVisibleCheckAll(penTarget); + } + return FALSE; + }; +/************************************************************ + * POST MOVING * + ************************************************************/ + void PostMoving(void) { + CEnemyBase::PostMoving(); + // change to liquid + if (m_EedtType!=EDT_GROUND_ONLY && !m_bInLiquid && en_fImmersionFactor>0.9f && + (GetWorld()->wo_actContentTypes[en_iDnContent].ct_ulFlags&CTF_SWIMABLE)) { + m_bInLiquid = TRUE; + ChangeCollisionToLiquid(); + SendEvent(ERestartAttack()); + } + // change to ground + if (m_EedtType!=EDT_DIVE_ONLY && m_bInLiquid && (en_fImmersionFactor<0.5f || en_fImmersionFactor==1.0f) && + en_penReference!=NULL && !(GetWorld()->wo_actContentTypes[en_iUpContent].ct_ulFlags&CTF_SWIMABLE)) { + m_bInLiquid = FALSE; + ChangeCollisionToGround(); + SendEvent(ERestartAttack()); + } + }; + + + +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + // set desired rotation and translation to go/orient towards desired position + // and get the resulting movement type + virtual ULONG SetDesiredMovement(void) + { + // if not in air + if (!m_bInLiquid) { + // use base class + return CEnemyBase::SetDesiredMovement(); + } + + // get base rotation from base class + ULONG ulFlags = CEnemyBase::SetDesiredMovement(); + + // if we may move + if (m_fMoveSpeed>0.0f) { + // fix translation for 3d movement + FLOAT3D vTranslation = (m_vDesiredPosition - GetPlacement().pl_PositionVector) * !en_mRotation; + vTranslation(1) = 0.0f; + if (vTranslation(3)>0) { + vTranslation(3) = 0.0f; + } + vTranslation.Normalize(); + vTranslation *= m_fMoveSpeed; + SetDesiredTranslation(vTranslation); + } + + return ulFlags; + } + + // check whether may move while attacking + BOOL MayMoveToAttack(void) + { + return WouldNotLeaveAttackRadius(); + } + +/************************************************************ + * CLASS SUPPORT FUNCTIONS * + ************************************************************/ + // set entity position + void SetEntityPosition() { + switch (m_EedtType) { + case EDT_GROUND_ONLY: // can't dive + m_bInLiquid = FALSE; + break; + case EDT_DIVE_ONLY: // always dive can't walk + m_bInLiquid = TRUE; + break; + case EDT_GROUND_DIVE: // dive and walk + break; + } + + // in liquid + if (m_bInLiquid) { + ChangeCollisionToLiquid(); + } else { + ChangeCollisionToGround(); + } + + StandingAnim(); + }; + + +/************************************************************ + * VIRTUAL FUNCTIONS THAT NEED OVERRIDE * + ************************************************************/ + virtual void ChangeCollisionToLiquid(void) {} + virtual void ChangeCollisionToGround(void) {} + + + +procedures: +/************************************************************ + * PROCEDURES WHEN NO ANY SPECIAL ACTION * + ************************************************************/ +/************************************************************ + * ATTACK ENEMY PROCEDURES * + ************************************************************/ + // this is called to hit the player when near + Hit(EVoid) : CEnemyBase::Hit + { + if (m_bInLiquid) { + jump DiveHit(); + } else { + jump GroundHit(); + } + } + + // this is called to shoot at player when far away or otherwise unreachable + Fire(EVoid) : CEnemyBase::Fire + { + if (m_bInLiquid) { + jump DiveFire(); + } else { + jump GroundFire(); + } + } + +/************************************************************ + * M A I N L O O P * + ************************************************************/ + // main loop + MainLoop(EVoid) : CEnemyBase::MainLoop { + SetEntityPosition(); + jump CEnemyBase::MainLoop(); + }; + + // dummy main + Main(EVoid) { + return; + }; + + + +/************************************************************ + * VIRTUAL PROCEDURES THAT NEED OVERRIDE * + ************************************************************/ + // this is called to hit the player when near and you are on ground + GroundHit(EVoid) + { + return EReturn(); + } + // this is called to shoot at player when far away or otherwise unreachable and you are on ground + GroundFire(EVoid) + { + return EReturn(); + } + + // this is called to hit the player when near and you are in water + DiveHit(EVoid) + { + return EReturn(); + } + + // this is called to shoot at player when far away or otherwise unreachable and you are in water + DiveFire(EVoid) + { + return EReturn(); + } +}; diff --git a/Sources/Entities/EnemyFly.es b/Sources/Entities/EnemyFly.es new file mode 100644 index 0000000..7d09d92 --- /dev/null +++ b/Sources/Entities/EnemyFly.es @@ -0,0 +1,479 @@ +311 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Debris"; +uses "Entities/EnemyMarker"; + + +enum EnemyFlyType { + 0 EFT_GROUND_ONLY "Ground only", // can't fly + 1 EFT_FLY_ONLY "Fly only", // always fly can't land + 2 EFT_FLY_GROUND_GROUND "Fly(ground) - ground attack", // start attack on ground - ground + 3 EFT_FLY_GROUND_AIR "Fly(ground) - air attack", // start attack in air - ground + 4 EFT_FLY_AIR_GROUND "Fly(air) - ground attack", // start attack on ground - air + 5 EFT_FLY_AIR_AIR "Fly(air) - air attack", // start attack in air - air +}; + + +class export CEnemyFly : CEnemyBase { +name "Enemy Fly"; +thumbnail ""; + +properties: + 1 enum EnemyFlyType m_EeftType "Type" 'T' = EFT_FLY_GROUND_AIR, // fly type + 2 BOOL m_bInAir = FALSE, // entity is in air + 3 BOOL m_bAirAttack = FALSE, // start air attack + 4 BOOL m_bStartInAir = FALSE, // initially in air + + // moving/attack properties - CAN BE SET + 16 FLOAT m_fGroundToAirSpeed = 2.0f, // ground to air speed + 17 FLOAT m_fAirToGroundSpeed = 4.0f, // air to ground speed + 18 FLOAT m_fAirToGroundMin = 1.0f, // how long to fly up before attacking + 19 FLOAT m_fAirToGroundMax = 2.0f, + 27 FLOAT m_fFlyHeight = 2.0f, // fly height above player handle + + // these following must be ordered exactly like this for GetProp() to function + 10 FLOAT m_fFlyWalkSpeed = 1.0f, // fly walk speed + 11 ANGLE m_aFlyWalkRotateSpeed = AngleDeg(10.0f), // fly walk rotate speed + 12 FLOAT m_fFlyAttackRunSpeed = 1.0f, // fly attack run speed + 13 ANGLE m_aFlyAttackRotateSpeed = AngleDeg(10.0f), // fly attack rotate speed + 14 FLOAT m_fFlyCloseRunSpeed = 1.0f, // fly close run speed + 15 ANGLE m_aFlyCloseRotateSpeed = AngleDeg(10.0f), // fly close rotate speed + 20 FLOAT m_fFlyAttackDistance = 50.0f, // fly attack distance mode + 21 FLOAT m_fFlyCloseDistance = 10.0f, // fly close distance mode + 22 FLOAT m_fFlyAttackFireTime = 2.0f, // fly attack distance fire time + 23 FLOAT m_fFlyCloseFireTime = 1.0f, // fly close distance fire time + 24 FLOAT m_fFlyStopDistance = 0.0f, // fly stop moving toward enemy if closer than stop distance + 25 FLOAT m_fFlyIgnoreRange = 200.0f, // fly cease attack if enemy farther + 26 FLOAT m_fFlyLockOnEnemyTime = 0.0f, // fly time needed to fire + + // marker variables +100 BOOL m_bFlyToMarker = FALSE, + +components: + 1 class CLASS_BASE "Classes\\EnemyBase.ecl", + +functions: + // overridable function for access to different properties of derived classes (flying/diving) + virtual FLOAT &GetProp(FLOAT &m_fBase) + { + if (m_bInAir) { + return *((&m_fBase)+(&m_fFlyWalkSpeed-&m_fWalkSpeed)); + } else { + return m_fBase; + } + } + + // get position you would like to go to when following player + virtual FLOAT3D PlayerDestinationPos(void) + { + // if not in air + if (!m_bInAir) { + // use base class + return CEnemyBase::PlayerDestinationPos(); + } + + // get distance to player + FLOAT fDist = CalcDist(m_penEnemy); + // determine height above from the distance + FLOAT fHeight; + // if in close attack range + if (fDist<=m_fFlyCloseDistance) { + // go to fixed height above player + fHeight = m_fFlyHeight; + // if in further + } else { + // fly more above if further + fHeight = m_fFlyHeight + fDist/5.0f; + } + + // calculate the position from the height + return + m_penEnemy->GetPlacement().pl_PositionVector + + FLOAT3D(m_penEnemy->en_mRotation(1, 2), m_penEnemy->en_mRotation(2, 2), m_penEnemy->en_mRotation(3, 2)) + * fHeight; + } + + // flying enemies never use pathfinding + void StartPathFinding(void) + { + if (m_bInAir) { + m_dtDestination=DT_PLAYERSPOTTED; + m_vPlayerSpotted = PlayerDestinationPos(); + } else { + CEnemyBase::StartPathFinding(); + } + } + + virtual void AdjustDifficulty(void) + { + FLOAT fMoveSpeed = GetSP()->sp_fEnemyMovementSpeed; + FLOAT fAttackSpeed = GetSP()->sp_fEnemyMovementSpeed; + + m_fFlyAttackFireTime *= 1/fAttackSpeed; + m_fFlyCloseFireTime *= 1/fAttackSpeed; + m_fFlyLockOnEnemyTime *= 1/fAttackSpeed; +// m_fFlyWalkSpeed *= fMoveSpeed; +// m_aFlyWalkRotateSpeed *= fMoveSpeed; + m_fFlyAttackRunSpeed *= fMoveSpeed; + m_aFlyAttackRotateSpeed *= fMoveSpeed; + m_fFlyCloseRunSpeed *= fMoveSpeed; + m_aFlyCloseRotateSpeed *= fMoveSpeed; + m_fGroundToAirSpeed *= fMoveSpeed; + m_fAirToGroundSpeed *= fMoveSpeed; + + CEnemyBase::AdjustDifficulty(); + } + + // close attack if possible + virtual BOOL CanHitEnemy(CEntity *penTarget, FLOAT fCosAngle) { + if (IsInPlaneFrustum(penTarget, fCosAngle)) { + return IsVisibleCheckAll(penTarget); + } + return FALSE; + }; +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + + // set desired rotation and translation to go/orient towards desired position + // and get the resulting movement type + virtual ULONG SetDesiredMovement(void) + { + // if not in air + if (!m_bInAir) { + // use base class + return CEnemyBase::SetDesiredMovement(); + } + + // get base rotation from base class + ULONG ulFlags = CEnemyBase::SetDesiredMovement(); + + // if we may move + if (m_fMoveSpeed>0.0f) { + // fix translation for 3d movement + FLOAT3D vTranslation = (m_vDesiredPosition - GetPlacement().pl_PositionVector) * !en_mRotation; + vTranslation(1) = 0.0f; + if (vTranslation(3)>0) { + vTranslation(3) = 0.0f; + } + vTranslation.Normalize(); + vTranslation *= m_fMoveSpeed; + SetDesiredTranslation(vTranslation); + } + + return ulFlags; + } + +/************************************************************ + * CLASS SUPPORT FUNCTIONS * + ************************************************************/ + // set entity position + void SetEntityPosition() { + switch (m_EeftType) { + case EFT_GROUND_ONLY: // ground only enemy + case EFT_FLY_GROUND_GROUND: // fly, on ground, start attack on ground + m_bAirAttack = FALSE; + m_bStartInAir = m_bInAir = FALSE; + m_bFlyToMarker = FALSE; + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_FLYING) | EPF_MODEL_WALKING); + ChangeCollisionToGround(); + break; + + case EFT_FLY_GROUND_AIR: // fly, on ground, start attack in air + m_bAirAttack = TRUE; + m_bStartInAir = m_bInAir = FALSE; + m_bFlyToMarker = FALSE; + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_FLYING) | EPF_MODEL_WALKING); + ChangeCollisionToGround(); + break; + + case EFT_FLY_AIR_GROUND: // fly, in air, start attack on ground + m_bAirAttack = FALSE; + m_bStartInAir = m_bInAir = TRUE; + m_bFlyToMarker = TRUE; + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_WALKING) | EPF_MODEL_FLYING); + ChangeCollisionToAir(); + break; + + case EFT_FLY_ONLY: // air only enemy + case EFT_FLY_AIR_AIR: // fly, in air, start attack in air + m_bAirAttack = TRUE; + m_bStartInAir = m_bInAir = TRUE; + m_bFlyToMarker = TRUE; + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_WALKING) | EPF_MODEL_FLYING); + ChangeCollisionToAir(); + break; + } + StandingAnim(); + }; + + +/************************************************************ + * VIRTUAL FUNCTIONS THAT NEED OVERRIDE * + ************************************************************/ + virtual FLOAT AirToGroundAnim(void) { return _pTimer->TickQuantum; } + virtual FLOAT GroundToAirAnim(void) { return _pTimer->TickQuantum; } + virtual void ChangeCollisionToAir(void) {} + virtual void ChangeCollisionToGround(void) {} + + + +procedures: +/************************************************************ + * PROCEDURES WHEN NO ANY SPECIAL ACTION * + ************************************************************/ +/* +#### !!!! + MoveToDestinationFlying(EVoid) { + m_fMoveFrequency = 0.25f; + m_fMoveTime = _pTimer->CurrentTick() + 45.0f; + while ((m_vDesiredPosition-GetPlacement().pl_PositionVector).Length()>m_fMoveSpeed*m_fMoveFrequency*2.0f && + m_fMoveTime>_pTimer->CurrentTick()) { + wait (m_fMoveFrequency) { + on (EBegin) : { FlyToPosition(); } + on (ETimer) : { stop; } + } + } + return EReturn(); + } + // Move to destination + MoveToDestination(EVoid) : CEnemyBase::MoveToDestination { + if (m_bFlyToMarker && !m_bInAir) { + autocall GroundToAir() EReturn; + } else if (!m_bFlyToMarker && m_bInAir) { + autocall AirToGround() EReturn; + } + + // animation + if (m_bRunToMarker) { + RunningAnim(); + } else { + WalkingAnim(); + } + // fly to position + if (m_bInAir) { + jump MoveToDestinationFlying(); + // move to position + } else { + jump CEnemyBase::MoveToDestination(); + } + };*/ + + // return to start position + ReturnToStartPosition(EVoid) : CEnemyBase::ReturnToStartPosition + { + jump CEnemyBase::BeIdle(); +/* // if on ground, but can fly + if (!m_bInAir && m_EeftType!=EFT_GROUND_ONLY) { + // fly up + autocall GroundToAir() EReturn; + } + + GetWatcher()->StartPlayers(); // start watching + m_vDesiredPosition = m_vStartPosition-en_vGravityDir*2.0f; + m_vStartDirection = (GetPlacement().pl_PositionVector-m_vStartPosition).Normalize(); + m_fMoveSpeed = m_fAttackRunSpeed; + m_aRotateSpeed = m_aAttackRotateSpeed; + RunningAnim(); + autocall MoveToDestinationFlying() EReturn; + + WalkingAnim(); + m_vDesiredAngle = m_vStartDirection; + StopTranslating(); + + autocall CEnemyBase::RotateToStartDirection() EReturn; + + // if should be on ground + if (m_bInAir && !m_bStartInAir) { + // fly down + autocall AirToGround() EReturn; + } + StopMoving(); + StandingAnim(); + + jump CEnemyBase::BeIdle();*/ + }; + +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + // Play wound animation and falling body part + BeWounded(EDamage eDamage) : CEnemyBase::BeWounded { + // land on ground + if (!(m_EeftType!=EFT_FLY_ONLY && m_bInAir && ((IRnd()&3)==0))) { + jump CEnemyBase::BeWounded(eDamage); + } else if (TRUE) { + m_bAirAttack = FALSE; + autocall AirToGround() EReturn; + } + return EReturn(); + }; + + + +/************************************************************ + * AIR - GROUND PROCEDURES * + ************************************************************/ + // air to ground + AirToGround(EVoid) + { + // land on brush + SetDesiredTranslation(FLOAT3D(0, -m_fAirToGroundSpeed, 0)); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + WalkingAnim(); + wait() { + on (EBegin) : { resume; } + // on brush stop + on (ETouch etouch) : { + if (etouch.penOther->GetRenderType() & RT_BRUSH) { + SetDesiredTranslation(FLOAT3D(0, 0, 0)); + stop; + } + resume; + } + on (EDeath) : { pass; } + otherwise() : { resume; } + } + // on ground + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_FLYING) | EPF_MODEL_WALKING); + m_bInAir = FALSE; + ChangeCollisionToGround(); + // animation + wait(AirToGroundAnim()) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + on (EDeath) : { pass; } + otherwise() : { resume; } + } + return EReturn(); + }; + + // ground to air + GroundToAir(EVoid) + { + // fly in air + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_WALKING) | EPF_MODEL_FLYING); + m_bInAir = TRUE; + SetDesiredTranslation(FLOAT3D(0, m_fGroundToAirSpeed, 0)); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + ChangeCollisionToAir(); + // animation + wait(GroundToAirAnim()) { + on (EBegin) : { resume; } + on (EDeath) : { pass; } + on (ETimer) : { stop; } + otherwise() : { resume; } + } + // move in air further + WalkingAnim(); + wait(Lerp(m_fAirToGroundMin, m_fAirToGroundMax, FRnd())) { + on (EBegin) : { resume; } + on (EDeath) : { pass; } + on (ETimer) : { stop; } + otherwise() : { resume; } + } + SetDesiredTranslation(FLOAT3D(0, 0, 0)); + return EReturn(); + }; + + + +/************************************************************ + * ATTACK ENEMY PROCEDURES * + ************************************************************/ + // initialize attack is overridden to switch fly/walk modes if needed + AttackEnemy() : CEnemyBase::AttackEnemy + { + // air attack + if (m_bAirAttack) { + // ground to air + if (!m_bInAir) { + autocall GroundToAir() EReturn; + } + // ground attack + } else if (TRUE) { + // air to ground + if (m_bInAir) { + autocall AirToGround() EReturn; + } + } + + jump CEnemyBase::AttackEnemy(); + } + + // this is called to hit the player when near + Hit(EVoid) : CEnemyBase::Hit + { + if (m_bInAir) { + jump FlyHit(); + } else { + jump GroundHit(); + } + } + + // this is called to shoot at player when far away or otherwise unreachable + Fire(EVoid) : CEnemyBase::Fire + { + if (m_bInAir) { + jump FlyFire(); + } else { + jump GroundFire(); + } + } + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + // clear fly flag + SetPhysicsFlags((GetPhysicsFlags() & ~EPF_MODEL_FLYING) | EPF_MODEL_WALKING); + ChangeCollisionToGround(); + jump CEnemyBase::Death(); + }; + + + +/************************************************************ + * M A I N L O O P * + ************************************************************/ + // main loop + MainLoop(EVoid) : CEnemyBase::MainLoop { + SetEntityPosition(); + jump CEnemyBase::MainLoop(); + }; + + // dummy main + Main(EVoid) { + return; + }; + +/************************************************************ + * VIRTUAL PROCEDURES THAT NEED OVERRIDE * + ************************************************************/ + // this is called to hit the player when near and you are on ground + GroundHit(EVoid) + { + return EReturn(); + } + // this is called to shoot at player when far away or otherwise unreachable and you are on ground + GroundFire(EVoid) + { + return EReturn(); + } + + // this is called to hit the player when near and you are in air + FlyHit(EVoid) + { + return EReturn(); + } + + // this is called to shoot at player when far away or otherwise unreachable and you are in air + FlyFire(EVoid) + { + return EReturn(); + } +}; diff --git a/Sources/Entities/EnemyMarker.es b/Sources/Entities/EnemyMarker.es new file mode 100644 index 0000000..0779721 --- /dev/null +++ b/Sources/Entities/EnemyMarker.es @@ -0,0 +1,53 @@ +302 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +class CEnemyMarker: CMarker { +name "Enemy Marker"; +thumbnail "Thumbnails\\EnemyMarker.tbn"; + +properties: + 1 FLOAT m_fWaitTime = 0.0f, // time to wait(or do anything) until go to another marker + 3 RANGE m_fMarkerRange "Marker Range" 'M' = 0.0f, // range around marker (marker doesn't have to be hit directly) + + 11 RANGE m_fPatrolAreaInner "Patrol Area Inner" 'R' = 0.0f, // patrol area inner circle + 12 RANGE m_fPatrolAreaOuter "Patrol Area Outer" 'E' = 0.0f, // patrol area outer circle + 13 FLOAT m_fPatrolTime "Patrol Time" 'P' = 0.0f, // time to patrol around + 14 enum BoolEType m_betRunToMarker "Run to marker" 'O' = BET_IGNORE, // run to marker + 15 enum BoolEType m_betFly "Fly" 'F' = BET_IGNORE, // fly if you can + 16 enum BoolEType m_betBlind "Blind" 'B' = BET_IGNORE, + 17 enum BoolEType m_betDeaf "Deaf" 'D' = BET_IGNORE, + +components: + 1 model MODEL_MARKER "Models\\Editor\\EnemyMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\EnemyMarker.tex" + +functions: + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\EnemyMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + +procedures: + Main() { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + return; + } +}; + diff --git a/Sources/Entities/EnemyRunInto.es b/Sources/Entities/EnemyRunInto.es new file mode 100644 index 0000000..e5793fd --- /dev/null +++ b/Sources/Entities/EnemyRunInto.es @@ -0,0 +1,283 @@ +312 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/EnemyBase"; + + +class export CEnemyRunInto : CEnemyBase { +name "Enemy Run Into"; +thumbnail ""; + +properties: + 1 CEntityPointer m_penLastTouched, // last touched live entity + 2 FLOAT m_fLastTouchedTime=0.0f, // last touched live entity time + 3 BOOL m_bWhileLoop=FALSE, // internal for loops + 5 FLOAT m_fMassKicked = 0.0f, // total mass kicked in one attack + + // moving properties - CAN BE SET + 10 ANGLE m_fAttackRotateRunInto = 1.0f, // attack rotate speed before run into enemy + +components: + 1 class CLASS_BASE "Classes\\EnemyBase.ecl", + +functions: + virtual void AdjustDifficulty(void) + { + FLOAT fMoveSpeed = GetSP()->sp_fEnemyMovementSpeed; + m_fAttackRotateRunInto *= fMoveSpeed; + + CEnemyBase::AdjustDifficulty(); + } +/************************************************************ + * ATTACK SPECIFIC * + ************************************************************/ + void IncreaseKickedMass(CEntity *pen) { + EntityInfo *peiTarget = (EntityInfo*) (pen->GetEntityInfo()); + if (peiTarget!=NULL) { + m_fMassKicked += peiTarget->fMass; + } + }; + + + + +/************************************************************ + * VIRTUAL ATTACK FUNCTIONS THAT NEED OVERRIDE * + ************************************************************/ + // touched another live entity + virtual void LiveEntityTouched(ETouch etouch) {}; + // touched entity with higher mass + virtual BOOL HigherMass(void) { return FALSE; } + + + +procedures: +/************************************************************ + * ATTACK ENEMY PROCEDURES * + ************************************************************/ + // attack range -> fire and move toward enemy + Fire() : CEnemyBase::Fire { + m_fMassKicked = 0.0f; + m_penLastTouched = NULL; + + jump RotateToEnemy(); + }; + + + RotateToEnemy() { + // if the enemy not alive or deleted + if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { + SetTargetNone(); + return EReturn(); + } + + // rotate to enemy + m_bWhileLoop = TRUE; + while (m_penEnemy!=NULL && m_bWhileLoop) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + // attack target + on (EBegin) : { + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + // rotate to enemy + if (!IsInPlaneFrustum(m_penEnemy, CosFast(15.0f))) { + m_aRotateSpeed = m_fAttackRotateRunInto; + m_fMoveSpeed = 0.0f; + // adjust direction and speed + ULONG ulFlags = SetDesiredMovement(); + MovementAnimation(ulFlags); + } else { + m_aRotateSpeed = 0.0f; + m_fMoveSpeed = 0.0f; + m_bWhileLoop = FALSE; + } + resume; + } + on (ESound) : { resume; } // ignore all sounds + on (EWatch) : { resume; } // ignore watch + on (ETimer) : { stop; } // timer tick expire + } + } + + jump RunIntoEnemy(); + }; + + +/* WalkToEnemy() { + // if the enemy not alive or deleted + if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { + SetTargetNone(); + return EReturn(); + } + + // walk to enemy if can't be seen + while (!CanAttackEnemy(m_penEnemy, CosFast(30.0f))) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + // move to target + on (EBegin) : { + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + m_fMoveSpeed = m_fWalkSpeed; + m_aRotateSpeed = m_aWalkRotateSpeed; + // adjust direction and speed + ULONG ulFlags = SetDesiredMovement(); + MovementAnimation(ulFlags); + } + on (ESound) : { resume; } // ignore all sounds + on (EWatch) : { resume; } // ignore watch + on (ETimer) : { stop; } // timer tick expire + } + } + + jump StartRunIntoEnemy(); + }; + + StartRunIntoEnemy() { + // if the enemy not alive or deleted + if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { + SetTargetNone(); + return EReturn(); + } + + // run to enemy + m_bWhileLoop = TRUE; + m_fMoveFrequency = 0.5f; + wait(m_fMoveFrequency) { + on (EBegin) : { + // if enemy can't be seen stop running + if (!SeeEntity(m_penEnemy, CosFast(90.0f))) { + m_bWhileLoop = FALSE; + stop; + } + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + // move to enemy + m_fMoveSpeed = m_fAttackRunSpeed; + m_aRotateSpeed = m_aAttackRotateSpeed; + // adjust direction and speed + SetDesiredMovement(); + RunningAnim(); + resume; + } + on (ETouch) : { resume; } + on (ETimer) : { stop; } // timer tick expire + } + + jump RunIntoEnemy(); + }; + */ + + RunIntoEnemy() { + // if the enemy not alive or deleted + if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { + SetTargetNone(); + return EReturn(); + } + + // run to enemy + m_bWhileLoop = TRUE; + while(m_penEnemy!=NULL && m_bWhileLoop) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + on (EBegin) : { + // if enemy can't be seen, or too close + if (!SeeEntity(m_penEnemy, CosFast(90.0f)) || CalcDist(m_penEnemy)<6.75f) { + // continue past it + m_bWhileLoop = FALSE; + stop; + } + // move to enemy + m_fMoveSpeed = m_fAttackRunSpeed; + m_aRotateSpeed = m_fAttackRotateRunInto; + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + SetDesiredMovement(); + RunningAnim(); + // make fuss + AddToFuss(); + resume; + } + // if touch another + on (ETouch etouch) : { + // if the entity is live + if (etouch.penOther->GetFlags()&ENF_ALIVE) { + // react to hitting it + LiveEntityTouched(etouch); + // if hit something bigger than us + if (HigherMass()) { + // stop attack + m_penLastTouched = NULL; + return EReturn(); + } + // if hit the enemy + if (etouch.penOther==m_penEnemy) { + // continue past it + m_bWhileLoop = FALSE; + stop; + } + // if hit wall + } else if (!(etouch.penOther->GetPhysicsFlags()&EPF_MOVABLE) && + (FLOAT3D(etouch.plCollision)% -en_vGravityDir)GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { + SetTargetNone(); + return EReturn(); + } + + // run in direction for 1.3 seconds + StopRotating(); + wait(1.3f) { + on (EBegin) : { resume; } + on (ETouch etouch) : { + // live entity touched + if (etouch.penOther->GetFlags()&ENF_ALIVE) { + LiveEntityTouched(etouch); + // stop moving on higher mass + if (HigherMass()) { + m_penLastTouched = NULL; + return EReturn(); + } + // stop go away from enemy + } else if (!(etouch.penOther->GetPhysicsFlags()&EPF_MOVABLE) && + (FLOAT3D(etouch.plCollision)% -en_vGravityDir)"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s",(const char*) m_penTarget->GetName()); + if (m_penSeriousTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s, %s", + (const char*) m_penTarget->GetName(),(const char*) m_penSeriousTarget->GetName()); + } + } + ((CTString&)m_strDescription) = EnemySpawnerType_enum.NameForValue(INDEX(m_estType)) + + m_strDescription; + return m_strDescription; + } + + // check if one template is valid for this spawner + BOOL CheckTemplateValid(CEntity *pen) + { + if (pen==NULL || !IsDerivedFromClass(pen, "Enemy Base")) { + return FALSE; + } + if (m_estType==EST_TELEPORTER) { + return !(((CEnemyBase&)*pen).m_bTemplate); + } else { + return ((CEnemyBase&)*pen).m_bTemplate; + } + } + + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if( slPropertyOffset == offsetof(CEnemySpawner, m_penTarget)) + { + return CheckTemplateValid(penTarget); + } + else if( slPropertyOffset == offsetof(CEnemySpawner, m_penPatrol)) + { + return (penTarget!=NULL && IsDerivedFromClass(penTarget, "Enemy Marker")); + } + else if( slPropertyOffset == offsetof(CEnemySpawner, m_penSeriousTarget)) + { + return CheckTemplateValid(penTarget); + } + return CEntity::IsTargetValid(slPropertyOffset, penTarget); + } + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + if (m_penTarget==NULL) { return FALSE; } + m_penTarget->FillEntityStatistics(pes); + pes->es_ctCount = m_ctTotal; + pes->es_strName += " (spawned)"; + if (m_penSeriousTarget!=NULL) { + pes->es_strName += " (has serious)"; + } + return TRUE; + } + + // spawn new entity + void SpawnEntity(BOOL bCopy) { + // spawn new entity if of class basic enemy + if (CheckTemplateValid(m_penTarget)) { + + CEntity *pen = NULL; + if (bCopy) { + // copy template entity + pen = GetWorld()->CopyEntityInWorld( *m_penTarget, + CPlacement3D(FLOAT3D(-32000.0f+FRnd()*200.0f, -32000.0f+FRnd()*200.0f, 0), ANGLE3D(0, 0, 0)) ); + + // change needed properties + pen->End(); + CEnemyBase *peb = ((CEnemyBase*)pen); + peb->m_bTemplate = FALSE; + if (m_estType==EST_RESPAWNER || m_estType==EST_RESPAWNERBYONE) { + peb->m_penSpawnerTarget = this; + } + if (m_penPatrol!=NULL) { + peb->m_penMarker = m_penPatrol; + } + pen->Initialize(); + } else { + pen = m_penTarget; + m_penTarget = NULL; + } + + // adjust circle radii to account for enemy size + FLOAT fEntityR = 0; + if (pen->en_pciCollisionInfo!=NULL) { + fEntityR = pen->en_pciCollisionInfo->GetMaxFloorRadius(); + } + FLOAT fOuterCircle = ClampDn(m_fOuterCircle-fEntityR, 0.0f); + FLOAT fInnerCircle = ClampUp(m_fInnerCircle+fEntityR, fOuterCircle); + // calculate new position + FLOAT fR = fInnerCircle + FRnd()*(fOuterCircle-fInnerCircle); + FLOAT fA = FRnd()*360.0f; + CPlacement3D pl(FLOAT3D(CosFast(fA)*fR, 0.05f, SinFast(fA)*fR), ANGLE3D(0, 0, 0)); + pl.RelativeToAbsolute(GetPlacement()); + + // teleport back + pen->Teleport(pl, m_bTelefrag); + + // spawn teleport effect + if (m_bSpawnEffect) { + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_TELEPORT; + ese.vNormal = FLOAT3D(0,1,0); + FLOATaabbox3D box; + pen->GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm()*2; + ese.vStretch = FLOAT3D(fEntitySize, fEntitySize, fEntitySize); + CEntityPointer penEffect = CreateEntity(pl, CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + } + }; + + +procedures: + // spawn one group of entities + SpawnGroup() + { + // no enemies in group yet + m_iInGroup = 0; + // repeat forever + while(TRUE) { + + // spawn one enemy + SpawnEntity(TRUE); + + // count total enemies spawned + m_ctTotal--; + // if no more left + if (m_ctTotal<=0) { + // finish entire spawner + return EEnd(); + } + + // count enemies in group + m_iInGroup++; + // if entire group spawned + if (m_iInGroup>=m_ctGroupSize) { + // finish + return EReturn(); + } + + // wait between two entities in group + wait(m_tmSingleWait) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + otherwise() : { pass; } + } + } + } + + // simple spawner + Simple() + { + // wait to be triggered + wait() { + on (EBegin) : { resume; } + on (ETrigger) : { stop; }; + on (EStart) : { stop; }; + otherwise() : { pass; } + } + + // if should delay + if (m_tmDelay>0) { + // wait delay + autowait(m_tmDelay); + } + + // repeat + while(TRUE) { + // spawn one group + autocall SpawnGroup() EReturn; + // delay between groups + autowait(m_tmGroupWait); + } + } + + // teleports the template + Teleporter() + { + // wait to be triggered + wait() { + on (EBegin) : { resume; } + on (ETrigger) : { stop; }; + on (EStart) : { stop; }; + otherwise() : { pass; } + } + + // if should delay + if (m_tmDelay>0) { + // wait delay + autowait(m_tmDelay); + } + + // teleport it + SpawnEntity(FALSE); + + // end the spawner + return EEnd(); + } + + // respawn enemies when killed + Respawner() + { + // repeat + while(TRUE) { + // wait to be triggered + wait() { + on (EBegin) : { resume; } + on (ETrigger) : { stop; }; + on (EStart) : { stop; }; + otherwise() : { pass; } + } + // if should delay + if (m_tmDelay>0) { + // wait delay + autowait(m_tmDelay); + } + + // spawn one group + autocall SpawnGroup() EReturn; + // if should continue respawning by one + if (m_estType==EST_RESPAWNERBYONE) { + // set group size to 1 + m_ctGroupSize = 1; + } + // wait a bit to recover + autowait(0.1f); + } + } + + DestroyableInactive() + { + waitevent() EActivate; + jump DestroyableActive(); + } + + DestroyableActiveSpawning() + { + // repeat + while(TRUE) { + // spawn one group + autocall SpawnGroup() EReturn; + // delay between groups + autowait(m_tmGroupWait); + } + } + DestroyableActive() + { + autocall DestroyableActiveSpawning() EDeactivate; + jump DestroyableInactive(); + } + + // spawn new entities until you are stopped + Destroyable() + { + // start in inactive state and do until stopped + autocall DestroyableInactive() EStop; + // finish + return EEnd(); + } + + Main() { + // init as nothing + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_ENEMYSPAWNER); + SetModelMainTexture(TEXTURE_ENEMYSPAWNER); + + // set range + if (m_fInnerCircle > m_fOuterCircle) { + m_fInnerCircle = m_fOuterCircle; + } + + // check target + if (m_penTarget!=NULL) { + if (!IsDerivedFromClass(m_penTarget, "Enemy Base")) { + WarningMessage("Target '%s' is of wrong class!", (const char*)m_penTarget->GetName()); + m_penTarget = NULL; + } + } + if (m_penSeriousTarget!=NULL) { + if (!IsDerivedFromClass(m_penSeriousTarget, "Enemy Base")) { + WarningMessage("Target '%s' is of wrong class!", (const char*)m_penSeriousTarget->GetName()); + m_penSeriousTarget = NULL; + } + } + + // never start ai in wed + autowait(_pTimer->TickQuantum); + + if (m_bDoubleInSerious && GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_EXTREME) { + m_ctGroupSize*=2; + m_ctTotal*=2; + } + if (m_penSeriousTarget!=NULL && GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_EXTREME) { + m_penTarget = m_penSeriousTarget; + } + + wait() { + on(EBegin) : { + if(m_estType==EST_SIMPLE) { + call Simple(); + } else if(m_estType==EST_TELEPORTER) { + call Teleporter(); + } else if(m_estType==EST_RESPAWNER || m_estType==EST_RESPAWNERBYONE || m_estType==EST_TRIGGERED) { + call Respawner(); + } else if(m_estType==EST_DESTROYABLE) { + call Destroyable(); + } + } + on(EDeactivate) : { + stop; + } + on(EStop) : { + stop; + } + on(EEnd) : { + stop; + } + } + + Destroy(); + + return; + }; +}; diff --git a/Sources/Entities/Entities.dsp b/Sources/Entities/Entities.dsp new file mode 100644 index 0000000..ed3ee1d --- /dev/null +++ b/Sources/Entities/Entities.dsp @@ -0,0 +1,5430 @@ +# Microsoft Developer Studio Project File - Name="Entities" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Entities - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Entities.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Entities.mak" CFG="Entities - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Entities - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Entities - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Flesh/Classes/Entities", CVAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Entities - Win32 Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /YX /c +# ADD CPP /nologo /G5 /MD /W3 /GX /Zi /Ox /Ot /Og /Oi /Oy- /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Yu"StdH.h" /FD /c +# SUBTRACT CPP /Oa /Ow /Gf /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /map /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Copying $(InputName) binaries to $(ENGINE_DIR)\Bin +InputPath=.\Release\Entities.dll +InputName=Entities +SOURCE="$(InputPath)" + +"$(ENGINE_DIR)\Bin\$(InputName).dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy Release\$(InputName).dll $(ENGINE_DIR)\Bin >nul + copy Release\$(InputName).map $(ENGINE_DIR)\Bin >nul + copy Release\$(InputName).lib $(ENGINE_DIR)\Bin >nul + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /YX /c +# ADD CPP /nologo /G5 /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"StdH.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /map /debug /machine:I386 /out:"Debug/EntitiesD.dll" /pdbtype:sept +# Begin Custom Build - Copying $(InputName) binaries to $(ENGINE_DIR)\Bin\Debug +InputPath=.\Debug\EntitiesD.dll +InputName=EntitiesD +SOURCE="$(InputPath)" + +"$(ENGINE_DIR)\Bin\Debug\$(InputName).dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy Debug\$(InputName).dll $(ENGINE_DIR)\Bin\Debug >nul + copy Debug\$(InputName).map $(ENGINE_DIR)\Bin\Debug >nul + copy Debug\$(InputName).lib $(ENGINE_DIR)\Bin\Debug >nul + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "Entities - Win32 Release" +# Name "Entities - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Group "Common sources" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Common\Common.cpp +# End Source File +# Begin Source File + +SOURCE=.\Common\HUD.cpp +# End Source File +# Begin Source File + +SOURCE=.\Common\Particles.cpp +# End Source File +# Begin Source File + +SOURCE=.\Common\PathFinding.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdH\StdH.cpp +# ADD CPP /Yc"StdH.h" +# End Source File +# End Group +# Begin Source File + +SOURCE=.\AirWave.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\AmmoItem.cpp +# End Source File +# Begin Source File + +SOURCE=.\AmmoPack.cpp +# End Source File +# Begin Source File + +SOURCE=.\AnimationChanger.cpp +# End Source File +# Begin Source File + +SOURCE=.\AnimationHub.cpp +# End Source File +# Begin Source File + +SOURCE=.\ArmorItem.cpp +# End Source File +# Begin Source File + +SOURCE=.\BackgroundViewer.cpp +# End Source File +# Begin Source File + +SOURCE=.\BasicEffects.cpp +# End Source File +# Begin Source File + +SOURCE=.\Beast.cpp +# End Source File +# Begin Source File + +SOURCE=.\BigHead.cpp +# End Source File +# Begin Source File + +SOURCE=.\BlendController.cpp +# End Source File +# Begin Source File + +SOURCE=.\BloodSpray.cpp +# End Source File +# Begin Source File + +SOURCE=.\Boneman.cpp +# End Source File +# Begin Source File + +SOURCE=.\Bouncer.cpp +# End Source File +# Begin Source File + +SOURCE=.\Bullet.cpp +# End Source File +# Begin Source File + +SOURCE=.\Camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\CameraMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\CannonBall.cpp +# End Source File +# Begin Source File + +SOURCE=.\Catman.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Copier.cpp +# End Source File +# Begin Source File + +SOURCE=.\Counter.cpp +# End Source File +# Begin Source File + +SOURCE=.\CrateRider.cpp +# End Source File +# Begin Source File + +SOURCE=.\Cyborg.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\CyborgBike.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Damager.cpp +# End Source File +# Begin Source File + +SOURCE=.\Debris.cpp +# End Source File +# Begin Source File + +SOURCE=.\DestroyableArchitecture.cpp +# End Source File +# Begin Source File + +SOURCE=.\Devil.cpp +# End Source File +# Begin Source File + +SOURCE=.\DevilMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\DevilProjectile.cpp +# End Source File +# Begin Source File + +SOURCE=.\DoorController.cpp +# End Source File +# Begin Source File + +SOURCE=.\Dragonman.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\EffectMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\Effector.cpp +# End Source File +# Begin Source File + +SOURCE=.\Elemental.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemyBase.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemyCounter.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemyDive.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemyFly.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemyMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemyRunInto.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnemySpawner.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentBase.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\Eruptor.cpp +# End Source File +# Begin Source File + +SOURCE=.\Eyeman.cpp +# End Source File +# Begin Source File + +SOURCE=.\Fish.cpp +# End Source File +# Begin Source File + +SOURCE=.\Fishman.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Flame.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\FogMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\GhostBusterRay.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Gizmo.cpp +# End Source File +# Begin Source File + +SOURCE=.\Global.cpp +# End Source File +# Begin Source File + +SOURCE=.\GradientMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\GravityMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\GravityRouter.cpp +# End Source File +# Begin Source File + +SOURCE=.\HazeMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\Headman.cpp +# End Source File +# Begin Source File + +SOURCE=.\HealthItem.cpp +# End Source File +# Begin Source File + +SOURCE=.\Huanman.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Item.cpp +# End Source File +# Begin Source File + +SOURCE=.\KeyItem.cpp +# End Source File +# Begin Source File + +SOURCE=.\Light.cpp +# End Source File +# Begin Source File + +SOURCE=.\Lightning.cpp +# End Source File +# Begin Source File + +SOURCE=.\Mamut.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Mamutman.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Mantaman.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Marker.cpp +# End Source File +# Begin Source File + +SOURCE=.\MessageHolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\MessageItem.cpp +# End Source File +# Begin Source File + +SOURCE=.\MirrorMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\ModelDestruction.cpp +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder2.cpp +# End Source File +# Begin Source File + +SOURCE=.\MovingBrush.cpp +# End Source File +# Begin Source File + +SOURCE=.\MovingBrushMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\MusicChanger.cpp +# End Source File +# Begin Source File + +SOURCE=.\MusicHolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\NavigationMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\ParticlesHolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\Pendulum.cpp +# End Source File +# Begin Source File + +SOURCE=.\Pipebomb.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Player.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerActionMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerAnimator.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerView.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeapons.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeaponsEffects.cpp +# End Source File +# Begin Source File + +SOURCE=.\Projectile.cpp +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShip.cpp +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShipMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\Reminder.cpp +# End Source File +# Begin Source File + +SOURCE=.\RobotDriving.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\RobotFlying.cpp +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\RollingStone.cpp +# End Source File +# Begin Source File + +SOURCE=.\Scorpman.cpp +# End Source File +# Begin Source File + +SOURCE=.\Ship.cpp +# End Source File +# Begin Source File + +SOURCE=.\ShipMarker.cpp +# End Source File +# Begin Source File + +SOURCE=.\SoundHolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\StormController.cpp +# End Source File +# Begin Source File + +SOURCE=.\Switch.cpp +# End Source File +# Begin Source File + +SOURCE=.\Teleport.cpp +# End Source File +# Begin Source File + +SOURCE=.\TouchField.cpp +# End Source File +# Begin Source File + +SOURCE=.\Trigger.cpp +# End Source File +# Begin Source File + +SOURCE=.\Twister.cpp +# End Source File +# Begin Source File + +SOURCE=.\VoiceHolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\Walker.cpp +# End Source File +# Begin Source File + +SOURCE=.\Watcher.cpp +# End Source File +# Begin Source File + +SOURCE=.\WatchPlayers.cpp +# End Source File +# Begin Source File + +SOURCE=.\Water.cpp +# End Source File +# Begin Source File + +SOURCE=.\WeaponItem.cpp +# End Source File +# Begin Source File + +SOURCE=.\Werebull.cpp +# End Source File +# Begin Source File + +SOURCE=.\Woman.cpp +# End Source File +# Begin Source File + +SOURCE=.\WorldBase.cpp +# ADD CPP /Yu"StdH.h" +# End Source File +# Begin Source File + +SOURCE=.\WorldLink.cpp +# End Source File +# Begin Source File + +SOURCE=.\WorldSettingsController.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Group "Common headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=.\Common\Flags.h +# End Source File +# Begin Source File + +SOURCE=.\Common\GameInterface.h +# End Source File +# Begin Source File + +SOURCE=.\Common\Particles.h +# End Source File +# Begin Source File + +SOURCE=.\Common\PathFinding.h +# End Source File +# Begin Source File + +SOURCE=.\StdH\StdH.h +# End Source File +# Begin Source File + +SOURCE=.\Common\WeaponPositions.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\AirWave.h +# End Source File +# Begin Source File + +SOURCE=.\AirWave_tables.h +# End Source File +# Begin Source File + +SOURCE=.\AmmoItem.h +# End Source File +# Begin Source File + +SOURCE=.\AmmoItem_tables.h +# End Source File +# Begin Source File + +SOURCE=.\AmmoPack.h +# End Source File +# Begin Source File + +SOURCE=.\AmmoPack_tables.h +# End Source File +# Begin Source File + +SOURCE=.\AnimationChanger.h +# End Source File +# Begin Source File + +SOURCE=.\AnimationChanger_tables.h +# End Source File +# Begin Source File + +SOURCE=.\AnimationHub.h +# End Source File +# Begin Source File + +SOURCE=.\AnimationHub_tables.h +# End Source File +# Begin Source File + +SOURCE=.\ArmorItem.h +# End Source File +# Begin Source File + +SOURCE=.\ArmorItem_tables.h +# End Source File +# Begin Source File + +SOURCE=.\BackgroundViewer.h +# End Source File +# Begin Source File + +SOURCE=.\BackgroundViewer_tables.h +# End Source File +# Begin Source File + +SOURCE=.\BasicEffects.h +# End Source File +# Begin Source File + +SOURCE=.\BasicEffects_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Beast.h +# End Source File +# Begin Source File + +SOURCE=.\BigHead.h +# End Source File +# Begin Source File + +SOURCE=.\BigHead_tables.h +# End Source File +# Begin Source File + +SOURCE=.\BlendController.h +# End Source File +# Begin Source File + +SOURCE=.\BlendController_tables.h +# End Source File +# Begin Source File + +SOURCE=.\BloodSpray.h +# End Source File +# Begin Source File + +SOURCE=.\Boneman.h +# End Source File +# Begin Source File + +SOURCE=.\Boneman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Bouncer.h +# End Source File +# Begin Source File + +SOURCE=.\Bouncer_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Bullet.h +# End Source File +# Begin Source File + +SOURCE=.\Bullet_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Camera.h +# End Source File +# Begin Source File + +SOURCE=.\Camera_tables.h +# End Source File +# Begin Source File + +SOURCE=.\CameraMarker.h +# End Source File +# Begin Source File + +SOURCE=.\CameraMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\CannonBall.h +# End Source File +# Begin Source File + +SOURCE=.\CannonBall_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Catman.h +# End Source File +# Begin Source File + +SOURCE=.\Catman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Copier.h +# End Source File +# Begin Source File + +SOURCE=.\Copier_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Counter.h +# End Source File +# Begin Source File + +SOURCE=.\Counter_tables.h +# End Source File +# Begin Source File + +SOURCE=.\CrateRider.h +# End Source File +# Begin Source File + +SOURCE=.\CrateRider_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Cyborg.h +# End Source File +# Begin Source File + +SOURCE=.\Cyborg_tables.h +# End Source File +# Begin Source File + +SOURCE=.\CyborgBike.h +# End Source File +# Begin Source File + +SOURCE=.\CyborgBike_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Damager.h +# End Source File +# Begin Source File + +SOURCE=.\Damager_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Debris.h +# End Source File +# Begin Source File + +SOURCE=.\Debris_tables.h +# End Source File +# Begin Source File + +SOURCE=.\DestroyableArchitecture.h +# End Source File +# Begin Source File + +SOURCE=.\DestroyableArchitecture_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Devil.h +# End Source File +# Begin Source File + +SOURCE=.\Devil_tables.h +# End Source File +# Begin Source File + +SOURCE=.\DevilMarker.h +# End Source File +# Begin Source File + +SOURCE=.\DevilMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\DevilProjectile.h +# End Source File +# Begin Source File + +SOURCE=.\DevilProjectile_tables.h +# End Source File +# Begin Source File + +SOURCE=.\DoorController.h +# End Source File +# Begin Source File + +SOURCE=.\DoorController_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Dragonman.h +# End Source File +# Begin Source File + +SOURCE=.\Dragonman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EffectMarker.h +# End Source File +# Begin Source File + +SOURCE=.\EffectMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Effector.h +# End Source File +# Begin Source File + +SOURCE=.\Effector_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Elemental.h +# End Source File +# Begin Source File + +SOURCE=.\Elemental_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyBase.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyBase_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyCounter.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyCounter_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyDive.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyDive_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyFly.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyFly_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyMarker.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyRunInto.h +# End Source File +# Begin Source File + +SOURCE=.\EnemyRunInto_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnemySpawner.h +# End Source File +# Begin Source File + +SOURCE=.\EnemySpawner_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentBase.h +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentBase_tables.h +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentMarker.h +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Eruptor.h +# End Source File +# Begin Source File + +SOURCE=.\Eruptor_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Eyeman.h +# End Source File +# Begin Source File + +SOURCE=.\Eyeman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Fish.h +# End Source File +# Begin Source File + +SOURCE=.\Fisherman.h +# End Source File +# Begin Source File + +SOURCE=.\Fisherman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Fishman.h +# End Source File +# Begin Source File + +SOURCE=.\Fishman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Flame.h +# End Source File +# Begin Source File + +SOURCE=.\Flame_tables.h +# End Source File +# Begin Source File + +SOURCE=.\FogMarker.h +# End Source File +# Begin Source File + +SOURCE=.\FogMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\GhostBusterRay.h +# End Source File +# Begin Source File + +SOURCE=.\GhostBusterRay_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Gizmo.h +# End Source File +# Begin Source File + +SOURCE=.\Global.h +# End Source File +# Begin Source File + +SOURCE=.\Global_tables.h +# End Source File +# Begin Source File + +SOURCE=.\GradientMarker.h +# End Source File +# Begin Source File + +SOURCE=.\GradientMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\GravityMarker.h +# End Source File +# Begin Source File + +SOURCE=.\GravityMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\GravityRouter.h +# End Source File +# Begin Source File + +SOURCE=.\GravityRouter_tables.h +# End Source File +# Begin Source File + +SOURCE=.\HazeMarker.h +# End Source File +# Begin Source File + +SOURCE=.\HazeMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Headman.h +# End Source File +# Begin Source File + +SOURCE=.\Headman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\HealthItem.h +# End Source File +# Begin Source File + +SOURCE=.\HealthItem_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Huanman.h +# End Source File +# Begin Source File + +SOURCE=.\Huanman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Item.h +# End Source File +# Begin Source File + +SOURCE=.\Item_tables.h +# End Source File +# Begin Source File + +SOURCE=.\KeyItem.h +# End Source File +# Begin Source File + +SOURCE=.\KeyItem_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Light.h +# End Source File +# Begin Source File + +SOURCE=.\Light_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Lightning.h +# End Source File +# Begin Source File + +SOURCE=.\Lightning_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Mamut.h +# End Source File +# Begin Source File + +SOURCE=.\Mamut_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Mamutman.h +# End Source File +# Begin Source File + +SOURCE=.\Mamutman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Mantaman.h +# End Source File +# Begin Source File + +SOURCE=.\Mantaman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Marker.h +# End Source File +# Begin Source File + +SOURCE=.\Marker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MessageHolder.h +# End Source File +# Begin Source File + +SOURCE=.\MessageHolder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MessageItem.h +# End Source File +# Begin Source File + +SOURCE=.\MessageItem_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MirrorMarker.h +# End Source File +# Begin Source File + +SOURCE=.\MirrorMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\ModelDestruction.h +# End Source File +# Begin Source File + +SOURCE=.\ModelDestruction_tables.h +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder.h +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder2.h +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder2_tables.h +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MovingBrush.h +# End Source File +# Begin Source File + +SOURCE=.\MovingBrush_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MovingBrushMarker.h +# End Source File +# Begin Source File + +SOURCE=.\MovingBrushMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MusicChanger.h +# End Source File +# Begin Source File + +SOURCE=.\MusicChanger_tables.h +# End Source File +# Begin Source File + +SOURCE=.\MusicHolder.h +# End Source File +# Begin Source File + +SOURCE=.\MusicHolder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\NavigationMarker.h +# End Source File +# Begin Source File + +SOURCE=.\NavigationMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\ParticlesHolder.h +# End Source File +# Begin Source File + +SOURCE=.\ParticlesHolder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Pendulum.h +# End Source File +# Begin Source File + +SOURCE=.\Pendulum_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Pipebomb.h +# End Source File +# Begin Source File + +SOURCE=.\Pipebomb_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Player.h +# End Source File +# Begin Source File + +SOURCE=.\Player_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerActionMarker.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerActionMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerAnimator.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerAnimator_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerMarker.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerView.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerView_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeapons.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeapons_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeaponsEffects.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeaponsEffects_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Projectile.h +# End Source File +# Begin Source File + +SOURCE=.\Projectile_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShip.h +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShip_tables.h +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShipMarker.h +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShipMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Reminder.h +# End Source File +# Begin Source File + +SOURCE=.\Reminder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\RobotDriving.h +# End Source File +# Begin Source File + +SOURCE=.\RobotDriving_tables.h +# End Source File +# Begin Source File + +SOURCE=.\RobotFlying.h +# End Source File +# Begin Source File + +SOURCE=.\RobotFlying_tables.h +# End Source File +# Begin Source File + +SOURCE=.\RollingStone.h +# End Source File +# Begin Source File + +SOURCE=.\RollingStone_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Scorpman.h +# End Source File +# Begin Source File + +SOURCE=.\Scorpman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Ship.h +# End Source File +# Begin Source File + +SOURCE=.\Ship_tables.h +# End Source File +# Begin Source File + +SOURCE=.\ShipMarker.h +# End Source File +# Begin Source File + +SOURCE=.\ShipMarker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\SoundHolder.h +# End Source File +# Begin Source File + +SOURCE=.\SoundHolder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\StormController.h +# End Source File +# Begin Source File + +SOURCE=.\StormController_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Switch.h +# End Source File +# Begin Source File + +SOURCE=.\Switch_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Teleport.h +# End Source File +# Begin Source File + +SOURCE=.\Teleport_tables.h +# End Source File +# Begin Source File + +SOURCE=.\TouchField.h +# End Source File +# Begin Source File + +SOURCE=.\TouchField_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Trigger.h +# End Source File +# Begin Source File + +SOURCE=.\Trigger_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Twister.h +# End Source File +# Begin Source File + +SOURCE=.\Twister_tables.h +# End Source File +# Begin Source File + +SOURCE=.\VoiceHolder.h +# End Source File +# Begin Source File + +SOURCE=.\VoiceHolder_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Walker.h +# End Source File +# Begin Source File + +SOURCE=.\Walker_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Watcher.h +# End Source File +# Begin Source File + +SOURCE=.\Watcher_tables.h +# End Source File +# Begin Source File + +SOURCE=.\WatchPlayers.h +# End Source File +# Begin Source File + +SOURCE=.\WatchPlayers_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Water.h +# End Source File +# Begin Source File + +SOURCE=.\Water_tables.h +# End Source File +# Begin Source File + +SOURCE=.\WeaponItem.h +# End Source File +# Begin Source File + +SOURCE=.\WeaponItem_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Werebull.h +# End Source File +# Begin Source File + +SOURCE=.\Werebull_tables.h +# End Source File +# Begin Source File + +SOURCE=.\Woman.h +# End Source File +# Begin Source File + +SOURCE=.\Woman_tables.h +# End Source File +# Begin Source File + +SOURCE=.\WorldBase.h +# End Source File +# Begin Source File + +SOURCE=.\WorldBase_tables.h +# End Source File +# Begin Source File + +SOURCE=.\WorldLink.h +# End Source File +# Begin Source File + +SOURCE=.\WorldLink_tables.h +# End Source File +# Begin Source File + +SOURCE=.\WorldSettingsController.h +# End Source File +# Begin Source File + +SOURCE=.\WorldSettingsController_tables.h +# End Source File +# End Group +# Begin Group "Class Files" + +# PROP Default_Filter "es" +# Begin Group "AI" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\NavigationMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\NavigationMarker.es +InputName=NavigationMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\NavigationMarker.es +InputName=NavigationMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Reminder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Reminder.es +InputName=Reminder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Reminder.es +InputName=Reminder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Watcher.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Watcher.es +InputName=Watcher + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Watcher.es +InputName=Watcher + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\WatchPlayers.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WatchPlayers.es +InputName=WatchPlayers + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WatchPlayers.es +InputName=WatchPlayers + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Brushes" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\Bouncer.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Bouncer.es +InputName=Bouncer + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Bouncer.es +InputName=Bouncer + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\DestroyableArchitecture.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DestroyableArchitecture.es +InputName=DestroyableArchitecture + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DestroyableArchitecture.es +InputName=DestroyableArchitecture + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MovingBrush.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MovingBrush.es +InputName=MovingBrush + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MovingBrush.es +InputName=MovingBrush + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MovingBrushMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MovingBrushMarker.es +InputName=MovingBrushMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MovingBrushMarker.es +InputName=MovingBrushMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Pendulum.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Pendulum.es +InputName=Pendulum + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Pendulum.es +InputName=Pendulum + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Ship.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Ship.es +InputName=Ship + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Ship.es +InputName=Ship + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ShipMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ShipMarker.es +InputName=ShipMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ShipMarker.es +InputName=ShipMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\WorldBase.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WorldBase.es +InputName=WorldBase + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WorldBase.es +InputName=WorldBase + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Effects" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\BasicEffects.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BasicEffects.es +InputName=BasicEffects + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BasicEffects.es +InputName=BasicEffects + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\BlendController.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BlendController.es +InputName=BlendController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BlendController.es +InputName=BlendController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\BloodSpray.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BloodSpray.es +InputName=BloodSpray + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BloodSpray.es +InputName=BloodSpray + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Debris.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Debris.es +InputName=Debris + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Debris.es +InputName=Debris + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EffectMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EffectMarker.es +InputName=EffectMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EffectMarker.es +InputName=EffectMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Effector.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Effector.es +InputName=Effector + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Effector.es +InputName=Effector + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Lightning.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Lightning.es +InputName=Lightning + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Lightning.es +InputName=Lightning + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShip.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PyramidSpaceShip.es +InputName=PyramidSpaceShip + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PyramidSpaceShip.es +InputName=PyramidSpaceShip + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PyramidSpaceShipMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PyramidSpaceShipMarker.es +InputName=PyramidSpaceShipMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PyramidSpaceShipMarker.es +InputName=PyramidSpaceShipMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\RollingStone.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\RollingStone.es +InputName=RollingStone + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\RollingStone.es +InputName=RollingStone + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\StormController.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\StormController.es +InputName=StormController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\StormController.es +InputName=StormController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\WorldSettingsController.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WorldSettingsController.es +InputName=WorldSettingsController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WorldSettingsController.es +InputName=WorldSettingsController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Enemies" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\Beast.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Beast.es +InputName=Beast + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Beast.es +InputName=Beast + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\BigHead.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BigHead.es +InputName=BigHead + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BigHead.es +InputName=BigHead + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Boneman.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Boneman.es +InputName=Boneman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Boneman.es +InputName=Boneman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Catman.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\CrateRider.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\CrateRider.es +InputName=CrateRider + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\CrateRider.es +InputName=CrateRider + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Cyborg.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\CyborgBike.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Devil.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Devil.es +InputName=Devil + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Devil.es +InputName=Devil + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\DevilMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DevilMarker.es +InputName=DevilMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DevilMarker.es +InputName=DevilMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Dragonman.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Elemental.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Elemental.es +InputName=Elemental + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Elemental.es +InputName=Elemental + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemyBase.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyBase.es +InputName=EnemyBase + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyBase.es +InputName=EnemyBase + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemyCounter.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyCounter.es +InputName=EnemyCounter + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyCounter.es +InputName=EnemyCounter + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemyDive.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyDive.es +InputName=EnemyDive + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyDive.es +InputName=EnemyDive + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemyFly.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyFly.es +InputName=EnemyFly + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyFly.es +InputName=EnemyFly + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemyMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyMarker.es +InputName=EnemyMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyMarker.es +InputName=EnemyMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemyRunInto.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyRunInto.es +InputName=EnemyRunInto + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemyRunInto.es +InputName=EnemyRunInto + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnemySpawner.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemySpawner.es +InputName=EnemySpawner + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnemySpawner.es +InputName=EnemySpawner + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Eyeman.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Eyeman.es +InputName=Eyeman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Eyeman.es +InputName=Eyeman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Fish.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Fish.es +InputName=Fish + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Fish.es +InputName=Fish + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Fishman.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Gizmo.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Gizmo.es +InputName=Gizmo + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Gizmo.es +InputName=Gizmo + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Headman.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Headman.es +InputName=Headman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Headman.es +InputName=Headman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Huanman.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Mamut.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Mamutman.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Mantaman.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\RobotDriving.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\RobotFixed.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\RobotFlying.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Scorpman.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Scorpman.es +InputName=Scorpman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Scorpman.es +InputName=Scorpman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Walker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Walker.es +InputName=Walker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Walker.es +InputName=Walker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Werebull.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Werebull.es +InputName=Werebull + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Werebull.es +InputName=Werebull + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Woman.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Woman.es +InputName=Woman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Woman.es +InputName=Woman + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Environment" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\EnvironmentBase.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnvironmentBase.es +InputName=EnvironmentBase + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnvironmentBase.es +InputName=EnvironmentBase + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\EnvironmentMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnvironmentMarker.es +InputName=EnvironmentMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\EnvironmentMarker.es +InputName=EnvironmentMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Items" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\AmmoItem.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AmmoItem.es +InputName=AmmoItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AmmoItem.es +InputName=AmmoItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\AmmoPack.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AmmoPack.es +InputName=AmmoPack + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AmmoPack.es +InputName=AmmoPack + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ArmorItem.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ArmorItem.es +InputName=ArmorItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ArmorItem.es +InputName=ArmorItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\HealthItem.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\HealthItem.es +InputName=HealthItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\HealthItem.es +InputName=HealthItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Item.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Item.es +InputName=Item + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Item.es +InputName=Item + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\KeyItem.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\KeyItem.es +InputName=KeyItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\KeyItem.es +InputName=KeyItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MessageItem.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MessageItem.es +InputName=MessageItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MessageItem.es +InputName=MessageItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\WeaponItem.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WeaponItem.es +InputName=WeaponItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WeaponItem.es +InputName=WeaponItem + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Players" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\Player.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Player.es +InputName=Player + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Player.es +InputName=Player + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PlayerActionMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerActionMarker.es +InputName=PlayerActionMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerActionMarker.es +InputName=PlayerActionMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PlayerAnimator.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerAnimator.es +InputName=PlayerAnimator + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerAnimator.es +InputName=PlayerAnimator + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PlayerMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerMarker.es +InputName=PlayerMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerMarker.es +InputName=PlayerMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PlayerView.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerView.es +InputName=PlayerView + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerView.es +InputName=PlayerView + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeapons.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerWeapons.es +InputName=PlayerWeapons + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerWeapons.es +InputName=PlayerWeapons + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\PlayerWeaponsEffects.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerWeaponsEffects.es +InputName=PlayerWeaponsEffects + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\PlayerWeaponsEffects.es +InputName=PlayerWeaponsEffects + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Tools" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\AnimationChanger.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AnimationChanger.es +InputName=AnimationChanger + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AnimationChanger.es +InputName=AnimationChanger + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\AnimationHub.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AnimationHub.es +InputName=AnimationHub + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\AnimationHub.es +InputName=AnimationHub + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\BackgroundViewer.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BackgroundViewer.es +InputName=BackgroundViewer + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\BackgroundViewer.es +InputName=BackgroundViewer + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Camera.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Camera.es +InputName=Camera + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Camera.es +InputName=Camera + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\CameraMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\CameraMarker.es +InputName=CameraMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\CameraMarker.es +InputName=CameraMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Copier.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Copier.es +InputName=Copier + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Copier.es +InputName=Copier + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Counter.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Counter.es +InputName=Counter + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Counter.es +InputName=Counter + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Damager.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Damager.es +InputName=Damager + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Damager.es +InputName=Damager + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\DoorController.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DoorController.es +InputName=DoorController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DoorController.es +InputName=DoorController + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Eruptor.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Eruptor.es +InputName=Eruptor + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Eruptor.es +InputName=Eruptor + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\FogMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\FogMarker.es +InputName=FogMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\FogMarker.es +InputName=FogMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\GradientMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\GradientMarker.es +InputName=GradientMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\GradientMarker.es +InputName=GradientMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\GravityMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\GravityMarker.es +InputName=GravityMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\GravityMarker.es +InputName=GravityMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\GravityRouter.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\GravityRouter.es +InputName=GravityRouter + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\GravityRouter.es +InputName=GravityRouter + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\HazeMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\HazeMarker.es +InputName=HazeMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\HazeMarker.es +InputName=HazeMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Light.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Light.es +InputName=Light + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Light.es +InputName=Light + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Marker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Marker.es +InputName=Marker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Marker.es +InputName=Marker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MessageHolder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MessageHolder.es +InputName=MessageHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MessageHolder.es +InputName=MessageHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MirrorMarker.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MirrorMarker.es +InputName=MirrorMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MirrorMarker.es +InputName=MirrorMarker + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ModelDestruction.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ModelDestruction.es +InputName=ModelDestruction + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ModelDestruction.es +InputName=ModelDestruction + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ModelHolder.es +InputName=ModelHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ModelHolder.es +InputName=ModelHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ModelHolder2.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ModelHolder2.es +InputName=ModelHolder2 + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ModelHolder2.es +InputName=ModelHolder2 + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MusicChanger.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MusicChanger.es +InputName=MusicChanger + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MusicChanger.es +InputName=MusicChanger + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\MusicHolder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MusicHolder.es +InputName=MusicHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\MusicHolder.es +InputName=MusicHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ParticlesHolder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ParticlesHolder.es +InputName=ParticlesHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\ParticlesHolder.es +InputName=ParticlesHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\SoundHolder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\SoundHolder.es +InputName=SoundHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\SoundHolder.es +InputName=SoundHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Switch.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Switch.es +InputName=Switch + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Switch.es +InputName=Switch + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Teleport.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Teleport.es +InputName=Teleport + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Teleport.es +InputName=Teleport + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\TouchField.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\TouchField.es +InputName=TouchField + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\TouchField.es +InputName=TouchField + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Trigger.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Trigger.es +InputName=Trigger + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Trigger.es +InputName=Trigger + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\VoiceHolder.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\VoiceHolder.es +InputName=VoiceHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\VoiceHolder.es +InputName=VoiceHolder + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\WorldLink.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WorldLink.es +InputName=WorldLink + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\WorldLink.es +InputName=WorldLink + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Weapons" + +# PROP Default_Filter "es" +# Begin Source File + +SOURCE=.\AirWave.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Bullet.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Bullet.es +InputName=Bullet + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Bullet.es +InputName=Bullet + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\CannonBall.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\CannonBall.es +InputName=CannonBall + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\CannonBall.es +InputName=CannonBall + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\DevilProjectile.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DevilProjectile.es +InputName=DevilProjectile + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\DevilProjectile.es +InputName=DevilProjectile + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Flame.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\GhostBusterRay.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Pipebomb.es +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\Projectile.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Projectile.es +InputName=Projectile + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Projectile.es +InputName=Projectile + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Twister.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Twister.es +InputName=Twister + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Twister.es +InputName=Twister + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Water.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Water.es +InputName=Water + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Water.es +InputName=Water + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Global.es + +!IF "$(CFG)" == "Entities - Win32 Release" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Global.es +InputName=Global + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ELSEIF "$(CFG)" == "Entities - Win32 Debug" + +# Begin Custom Build - Entities/$(InputName).es +InputPath=.\Global.es +InputName=Global + +"$(InputName).cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd ..\ + ecc Entities/$(InputName).es + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\LastFileID.txt +# End Source File +# End Group +# Begin Group "Links To Package" + +# PROP Default_Filter "ecl" +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Acid.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\AirWave.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\AmmoItem.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\AmmoPack.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\AnimationChanger.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\AnimationHub.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\ArmorItem.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\BackgroundViewer.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\BasicEffect.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Beast.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\BigHead.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\BlendController.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\BloodSpray.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Boneman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Bouncer.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Bullet.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Camera.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\FLESH\Classes\CameraMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\CannonBall.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Catman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Copier.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Counter.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\CrateRider.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Cyborg.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\CyborgBike.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Damager.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Debris.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\DestroyableArchitecture.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Devil.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\DevilMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\DevilProjectile.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\DoorController.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Dragonman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EffectMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Effector.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Elemental.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemyBase.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemyCounter.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemyDive.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemyFly.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemyMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemyRunInto.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnemySpawner.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnvironmentBase.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\EnvironmentMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Eruptor.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Eyeman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Fish.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Fishman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Flame.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\FogMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\GhostBusterRay.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Gizmo.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\GradientMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\GravityMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\GravityRouter.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\HazeMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Headman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\HealthItem.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Huanman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Item.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\KeyItem.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Light.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Lightning.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Mamut.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Mamutman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Mantaman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Marker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MessageHolder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MessageItem.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MirrorMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\ModelDestruction.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\ModelHolder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\ModelHolder2.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MovingBrush.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MovingBrushMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MusicChanger.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\MusicHolder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\NavigationMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\ParticlesHolder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Pendulum.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Pipebomb.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Player.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PlayerActionMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PlayerAnimator.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PlayerMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PlayerView.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PlayerWeapons.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PlayerWeaponsEffects.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Projectile.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PyramidSpaceShip.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\PyramidSpaceShipMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Reminder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\RobotDriving.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\RobotFixed.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\RobotFlying.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\RollingStone.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Scorpman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Ship.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\ShipMarker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\SoundHolder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Switch.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Teleport.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\TouchField.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Trigger.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Twister.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\VoiceHolder.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Walker.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Watcher.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\WatchPlayers.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Water.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\WeaponItem.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Werebull.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\Woman.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\WorldBase.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\WorldLink.ecl +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Classes\WorldSettingsController.ecl +# End Source File +# End Group +# Begin Group "Messages" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\BeastBig.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\BeastNormal.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Bomberman.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Boneman.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Bull.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Devil.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\ElementalLava.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\EyemanGreen.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\EyemanPurple.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Firecracker.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Fish.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Gizmo.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Kamikaze.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Rocketman.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\ScorpmanGeneral.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\ScorpmanSoldier.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\WalkerBig.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\WalkerSmall.txt +# End Source File +# Begin Source File + +SOURCE=..\..\Flesh\Data\Messages\Enemies\Woman.txt +# End Source File +# End Group +# End Target +# End Project diff --git a/Sources/Entities/EnvironmentBase.es b/Sources/Entities/EnvironmentBase.es new file mode 100644 index 0000000..82df870 --- /dev/null +++ b/Sources/Entities/EnvironmentBase.es @@ -0,0 +1,416 @@ +900 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/EnvironmentMarker"; +uses "Entities/WatchPlayers"; + +class CEnvironmentBase: CMovableEntity { +name "Environment Base"; +thumbnail "Thumbnails\\EnvironmentBase.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Base Environment", + 2 CTString m_strDescription = "", + 3 RANGE m_fDistance "Range" 'R' = 100.0f, // distance when player is seen + 4 FLOAT m_fStretch "Stretch" 'S' = 1.0f, + + 5 CEntityPointer m_penTarget "Target" 'T', + 6 CEntityPointer m_penWatcher, + 7 FLOAT m_fWatcherFrequency "Watcher frequency" = 2.0f, // watcher will look every x seconds for players + 8 FLOAT3D m_vDesiredPosition = FLOAT3D(0, 0, 0), // desired position for moving + + 10 FLOAT m_fMoveSpeed "Move speed" 'V' = 2.0f, + 11 FLOAT m_fRotateSpeed "Rotate speed" 'B' = 60.0f, + 12 FLOAT m_fMoveFrequency "Move frequency" = 0.5f, + 13 BOOL m_bUseWatcher "Use watcher" = FALSE, // use individual watcher + 14 BOOL m_bFlying "Flying" 'F' = FALSE, // flying model + 16 FLOAT m_fWaitTime = 0.0f, + + 20 CTFileName m_fnMdl "Model" 'M' = CTFILENAME("Models\\Editor\\Axis.mdl"), + 21 CTFileName m_fnTex "Texture" 'X' = CTString(""), + 22 ANIMATION m_iAnim "Animation" =0, + + 25 CTFileName m_fnAtt1Mdl "Attachment 1 Model" = CTString(""), + 26 CTFileName m_fnAtt1Tex "Attachment 1 Texture" = CTString(""), + 27 INDEX m_iAtt1Position "Attachment 1 position"=0, + 28 ANIMATION m_iAtt1Anim "Attachment 1 animation"=0, + + 30 CTFileName m_fnAtt2Mdl "Attachment 2 Model" = CTString(""), + 31 CTFileName m_fnAtt2Tex "Attachment 2 Texture" = CTString(""), + 32 INDEX m_iAtt2Position "Attachment 2 position"=1, + 33 ANIMATION m_iAtt2Anim "Attachment 2 animation"=0, + + 35 CTFileName m_fnAtt3Mdl "Attachment 3 Model" = CTString(""), + 36 CTFileName m_fnAtt3Tex "Attachment 3 Texture" = CTString(""), + 37 INDEX m_iAtt3Position "Attachment 3 position"=1, + 38 ANIMATION m_iAtt3Anim "Attachment 3 animation"=0, + +components: + 1 class CLASS_WATCHPLAYERS "Classes\\WatchPlayers.ecl", + +functions: + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\EnvironmentMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + }; + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s",(const char*) m_penTarget->GetName()); + } + return m_strDescription; + }; + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) { + if(slPropertyOffset==offsetof(CEnvironmentBase, m_iAnim)) { + return GetModelObject()->GetData(); + + } else if(slPropertyOffset==offsetof(CEnvironmentBase, m_iAtt1Anim)) { + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel(m_iAtt1Position); + if( pamo != NULL) { return pamo->amo_moModelObject.GetData(); } + return CEntity::GetAnimData(slPropertyOffset); + + } else if(slPropertyOffset==offsetof(CEnvironmentBase, m_iAtt2Anim)) { + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel(m_iAtt2Position); + if( pamo != NULL) { return pamo->amo_moModelObject.GetData(); } + return CEntity::GetAnimData(slPropertyOffset); + + } else if(slPropertyOffset==offsetof(CEnvironmentBase, m_iAtt3Anim)) { + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel(m_iAtt3Position); + if( pamo != NULL) { return pamo->amo_moModelObject.GetData(); } + return CEntity::GetAnimData(slPropertyOffset); + + } else { + return CEntity::GetAnimData(slPropertyOffset); + } + }; + + + +/************************************************************ + * MOVE FUNCTIONS * + ************************************************************/ + // switch to next marker + BOOL NextMarker(void) { + if (m_penTarget==NULL) { + return FALSE; + } + + // assure valid target + if (m_penTarget!=NULL && !IsOfClass(m_penTarget, "Environment Marker")) { + WarningMessage("Target '%s' is not of Environment Marker class!",(const char*) m_penTarget->GetName()); + m_penTarget = NULL; + return FALSE; + } + + // get next marker + CMarker *penTarget = (CMarker *)(CEntity*)m_penTarget; + CMarker *penNextTarget = (CMarker *)(CEntity*)penTarget->m_penTarget; + + // if got to end + if (penNextTarget==NULL) { + return FALSE; + } + + // remember next marker as current target + m_penTarget = penNextTarget; + + return TRUE; + }; + + // calculate rotation + void CalcRotation(ANGLE aWantedHeadingRelative, ANGLE3D &aRotation) { + // normalize it to [-180,+180] degrees + aWantedHeadingRelative = NormalizeAngle(aWantedHeadingRelative); + + // if desired position is left + if (aWantedHeadingRelative<-m_fRotateSpeed*m_fMoveFrequency) { + // start turning left + aRotation(1) = -m_fRotateSpeed; + // if desired position is right + } else if (aWantedHeadingRelative>m_fRotateSpeed*m_fMoveFrequency) { + // start turning right + aRotation(1) = +m_fRotateSpeed; + // if desired position is more-less ahead + } else { + aRotation(1) = aWantedHeadingRelative/m_fMoveFrequency; + } + }; + + // stop moving + void StopMoving(void) { + SetDesiredRotation(ANGLE3D(0, 0, 0)); + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + }; + + // move to position + void MoveToPosition(void) { + FLOAT3D vDesiredAngle; + + // desired angle vector + vDesiredAngle = (m_vDesiredPosition - GetPlacement().pl_PositionVector).Normalize(); + // find relative heading towards the desired angle + ANGLE3D aRotation(0,0,0); + CalcRotation(GetRelativeHeading(vDesiredAngle), aRotation); + + // determine translation speed + FLOAT3D vTranslation(0.0f, 0.0f, 0.0f); + vTranslation(3) = -m_fMoveSpeed; + + // if flying set y axis translation speed + if (m_bFlying) { + vTranslation(2) = Sgn(vDesiredAngle(2)) * m_fMoveSpeed/10; + } + + // start moving + SetDesiredRotation(aRotation); + SetDesiredTranslation(vTranslation); + }; + + // calc destination + void CalcDestination() { + // new position to walk to + FLOAT fR = FRnd()*((CEnvironmentMarker&)*m_penTarget).m_fMarkerRange; + FLOAT fA = FRnd()*360.0f; + m_vDesiredPosition = m_penTarget->GetPlacement().pl_PositionVector + + FLOAT3D(CosFast(fA)*fR, 0, SinFast(fA)*fR); + }; + + // marker parameters + void MarkerParameters() { + if (m_penTarget != NULL) { + CEnvironmentMarker &em = (CEnvironmentMarker&)*m_penTarget; + if (em.m_fMoveSpeed > 0.0f) { + m_fMoveSpeed = em.m_fMoveSpeed; + } + if (em.m_fRotateSpeed > 0.0f) { + m_fRotateSpeed = em.m_fRotateSpeed; + } + } + }; + + + +/************************************************************ + * INITIALIZE FUNCTIONS * + ************************************************************/ + void Initialize(void) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING&~(EPF_ORIENTEDBYGRAVITY|EPF_TRANSLATEDBYGRAVITY)); + SetCollisionFlags(ECF_MODEL); + + // set model stretch -- MUST BE DONE BEFORE SETTING MODEL! + GetModelObject()->mo_Stretch = FLOAT3D( m_fStretch, m_fStretch, m_fStretch); + + // set appearance + SetModel(m_fnMdl); + GetModelObject()->PlayAnim(m_iAnim, AOF_LOOPING); + if( m_fnTex != CTString("")) { + GetModelObject()->mo_toTexture.SetData_t(m_fnTex); + } + + GetModelObject()->RemoveAllAttachmentModels(); + + AddAttachment( m_iAtt1Position, m_fnAtt1Mdl, m_fnAtt1Tex); + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel( m_iAtt1Position); + if( pamo != NULL) { + pamo->amo_moModelObject.StartAnim( m_iAtt1Anim); + } + + if( (m_iAtt2Position != m_iAtt1Position) && (m_fnAtt1Mdl != m_fnAtt2Mdl) ) { + AddAttachment( m_iAtt2Position, m_fnAtt2Mdl, m_fnAtt2Tex); + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel( m_iAtt2Position); + if( pamo != NULL) { + pamo->amo_moModelObject.StartAnim( m_iAtt2Anim); + } + } + + if( (m_iAtt3Position != m_iAtt1Position) && (m_fnAtt1Mdl != m_fnAtt3Mdl) && + (m_iAtt3Position != m_iAtt2Position) && (m_fnAtt2Mdl != m_fnAtt3Mdl) ) { + AddAttachment( m_iAtt3Position, m_fnAtt3Mdl, m_fnAtt3Tex); + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel( m_iAtt3Position); + if( pamo != NULL) { + pamo->amo_moModelObject.StartAnim( m_iAtt3Anim); + } + } + + // assure valid target + if (m_penTarget!=NULL && !IsOfClass(m_penTarget, "Environment Marker")) { + WarningMessage("Target '%s' is not of Environment Marker class!", (const char*)m_penTarget->GetName()); + m_penTarget = NULL; + } +}; + + +/************************************************************ + * WATCHER FUNCTIONS * + ************************************************************/ + void InitializeWatcher(FLOAT fWaitTime) { + // spawn player watcher + m_penWatcher = CreateEntity(GetPlacement(), CLASS_WATCHPLAYERS); + m_penWatcher->Initialize(EVoid()); + + // setup player watcher + CWatchPlayers &pw = (CWatchPlayers&)*m_penWatcher; + pw.m_penOwner = this; + pw.m_fWaitTime = 2.0f; + pw.m_fDistance = m_fDistance; + pw.m_bRangeWatcher = FALSE; + pw.m_eetEventClose = EET_ENVIRONMENTSTART; + pw.m_eetEventFar = EET_ENVIRONMENTSTOP; + }; + + + +/************************************************************ + * ANIMATION FUCNTIONS * + ************************************************************/ + // play default anim + void PlayDefaultAnim(void) { + GetModelObject()->PlayAnim(m_iAnim, AOF_LOOPING|AOF_NORESTART); + }; + + // play marker animation + void PlayMarkerAnimation(void) { + if (m_penTarget != NULL) { + GetModelObject()->PlayAnim(((CEnvironmentMarker&)*m_penTarget).m_iAnim, AOF_LOOPING|AOF_NORESTART); + } + }; + + // change default anim + void ChangeDefaultAnim(void) { + if (m_penTarget != NULL && ((CEnvironmentMarker&)*m_penTarget).m_bChangeDefaultAnim) { + m_iAnim = ((CEnvironmentMarker&)*m_penTarget).m_iAnim; + } + }; + + // wait on marker + void WaitOnMarker(void) { + if (m_penTarget != NULL) { + CEnvironmentMarker &em = (CEnvironmentMarker&)*m_penTarget; + m_fWaitTime = em.m_fWaitTime; // wait time + m_fWaitTime += FRnd() * em.m_fRandomTime; // random wait time + // fixed anim length + if (em.m_bFixedAnimLength) { + m_fWaitTime = floor(m_fWaitTime + 0.5f); + } + } + }; + + + +procedures: +/************************************************************ + * SUPPORT PROCEDURES * + ************************************************************/ + // move to marker + MoveToMarker(EVoid) { + // if next marker exist + if (NextMarker()) { + // destination + CalcDestination(); + // move to marker + while ((m_vDesiredPosition-GetPlacement().pl_PositionVector).Length() > 5.0f) { + wait(m_fMoveFrequency) { + on (EBegin) : { + MoveToPosition(); + resume; + } + on (ETimer) : { stop; } + } + } + } + // stop moving + StopMoving(); + return EEnd(); + }; + + + +/************************************************************ + * A C T I O N S * + ************************************************************/ + // activate + Activate(EVoid) { + wait() { + on (EBegin) : { call DoAction(); } + on (EEnvironmentStop) : { jump Stop(); } + } + }; + + // just wait + Stop(EVoid) { + StopMoving(); + wait() { + on (EBegin) : { resume; } + on (EEnvironmentStart) : { jump Activate(); } + } + }; + + // do actions + DoAction(EVoid) { + while (TRUE) { + WaitOnMarker(); + if (m_fWaitTime > 0.0f) { + PlayMarkerAnimation(); + autowait(m_fWaitTime); + } + ChangeDefaultAnim(); + + MarkerParameters(); + PlayDefaultAnim(); + autocall MoveToMarker() EEnd; + + // if no more targets wait forever in last anim (if marker anim exist otherwise in default anim) + if (m_penTarget==NULL || ((CEnvironmentMarker&)*m_penTarget).m_penTarget==NULL) { + autowait(); + } + } + }; + + + +/************************************************************ + * M A I N L O O P * + ************************************************************/ + // main loop + MainLoop(EVoid) { + autocall Stop() EEnd; + + // destroy player watcher + m_penWatcher->SendEvent(EEnd()); + + // cease to exist + Destroy(); + + return; + }; + + Main() { + // initialize + Initialize(); + + // wait until game starts + autowait(FRnd()*2.0f+1.0f); + + // initialize watcher + if (m_bUseWatcher) { + InitializeWatcher(m_fWatcherFrequency); + } + + m_strDescription = "Environment base"; + + jump MainLoop(); + }; +}; diff --git a/Sources/Entities/EnvironmentMarker.es b/Sources/Entities/EnvironmentMarker.es new file mode 100644 index 0000000..9aa764b --- /dev/null +++ b/Sources/Entities/EnvironmentMarker.es @@ -0,0 +1,92 @@ +901 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +class CEnvironmentMarker: CMarker { +name "Environment Marker"; +thumbnail "Thumbnails\\EnvironmentMarker.tbn"; + +properties: + 1 FLOAT m_fWaitTime "Wait time" 'W' = 0.0f, // time to wait (or do anything until go to another marker) + 2 FLOAT m_fRandomTime "Random time" 'E' = 0.0f, // random time to wait (or do anything until go to another marker) + 3 RANGE m_fMarkerRange "Marker range" 'R' = 5.0f, // range around marker (marker doesn't have to be hit directly) + 4 BOOL m_bFixedAnimLength "Fixed anim length" 'F' = FALSE, // fixed anim length (like play once) + 5 BOOL m_bChangeDefaultAnim "Change default anim" 'C' = FALSE, // change default anim + 6 FLOAT m_fMoveSpeed "Move speed" 'V' = -1.0f, // moving speed + 7 FLOAT m_fRotateSpeed "Rotate speed" 'B' = -1.0f, // rotate speed + + // for browsing animations on marker for base environment model + 20 CTFileName m_fnMdl "Model" 'M' = CTFILENAME("Models\\Editor\\Axis.mdl"), + 21 ANIMATION m_iAnim "Animation" 'A' =0, + 22 CModelObject m_moAnimData, + +components: + 1 model MODEL_MARKER "Models\\Editor\\EnvironmentMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\EnvironmentMarker.tex" + +functions: + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\EnvironmentMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + }; + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) { + if(slPropertyOffset==offsetof(CEnvironmentMarker, m_iAnim)) { + return m_moAnimData.GetData(); + + } else { + return CEntity::GetAnimData(slPropertyOffset); + } + }; + + // >>> original source from CEntity::SetModel <<< + // set mdoel object + void SetModelObject(void) { + // try to + try { + // load the new model data + m_moAnimData.SetData_t(m_fnMdl); + // if failed + } catch(char *strError) { + strError; + DECLARE_CTFILENAME(fnmDefault, "Models\\Editor\\Axis.mdl"); + // try to + try { + // load the default model data + m_moAnimData.SetData_t(fnmDefault); + // if failed + } catch(char *strErrorDefault) { + FatalError(TRANS("Cannot load default model '%s':\n%s"), + (const char*)(CTString&)fnmDefault, strErrorDefault); + } + } + }; + + +procedures: + Main() { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set model data for anim browser + SetModelObject(); + + return; + } +}; + diff --git a/Sources/Entities/Eruptor.es b/Sources/Entities/Eruptor.es new file mode 100644 index 0000000..e33288f --- /dev/null +++ b/Sources/Entities/Eruptor.es @@ -0,0 +1,264 @@ +213 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelHolder2"; +uses "Entities/Projectile"; + +class CEruptor : CModelHolder2 { +name "Eruptor"; +thumbnail "Thumbnails\\Eruptor.tbn"; +features "HasName", "IsTargetable"; + +properties: + // stretch + 10 FLOAT m_fStretchAll "Er StretchAll" = 1.0f, + 11 FLOAT m_fStretchX "Er StretchX" = 1.0f, + 12 FLOAT m_fStretchY "Er StretchY" = 1.0f, + 13 FLOAT m_fStretchZ "Er StretchZ" = 1.0f, + + // random stretch + 15 BOOL m_bRandomStretch "Er Stretch Random" = FALSE, // random stretch + 16 FLOAT m_fStretchHeight "Er Stretch Height (Y%)" = 0.2f, // stretch height + 17 FLOAT m_fStretchWidth "Er Stretch Width (X%)" = 0.2f, // stretch width + 18 FLOAT m_fStretchDepth "Er Stretch Depth (Z%)" = 0.2f, // strecth depth + + // spawn properties + 20 FLOAT m_fAngle "Er Angle" 'Q' = 45.0f, // spawn spatial angle + 21 FLOAT m_fMaxSpeed "Er Speed max" 'V' = 20.0f, // max speed + 22 FLOAT m_fMinSpeed "Er Speed min" 'B' = 10.0f, // min speed + 23 FLOAT m_fTime "Er Spawn time" 'F' = 1.0f, // spawn every x seconds + 24 FLOAT m_fRandomWait "Er Random wait" 'G' = 0.0f, // wait between two spawns + 25 enum ProjectileType m_ptType "Er Type" 'T' = PRT_LAVA_COMET, + 26 BOOL m_bShootInArc "Er Shoot In Arc" 'S' = TRUE, + +components: + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + +functions: + + /* calculates launch velocity and heading correction for angular launch */ + void CalculateAngularLaunchParams( + CMovableEntity *penTarget, + FLOAT3D vShooting, + FLOAT3D vTarget, FLOAT3D vSpeedDest, + ANGLE aPitch, + ANGLE &aHeading, + FLOAT &fLaunchSpeed) + { + FLOAT3D vNewTarget = vTarget; + FLOAT3D &vGravity = penTarget->en_vGravityDir; + FLOAT fa = TanFast(AngleDeg(aPitch)); + FLOAT3D vd, vyd0; + FLOAT fd, fyd0; + FLOAT fTime = 0.0f; + FLOAT fLastTime = 0.0f; + + INDEX iIterations = 0; + + do + { + iIterations++; + FLOAT3D vDistance = vNewTarget-vShooting; + GetParallelAndNormalComponents(vDistance, vGravity, vyd0, vd); + fd = vd.Length(); + fyd0 = vyd0.Length(); + fLastTime=fTime; + fTime = Sqrt(2.0f)*Sqrt((fa*fd-fyd0)/penTarget->en_fGravityA); + vNewTarget = vTarget+vSpeedDest*fTime; + } + while( Abs(fTime-fLastTime) > _pTimer->TickQuantum && iIterations<10); + + // calculate launch speed + fLaunchSpeed = 0.707108f*fd/ + (Cos(AngleDeg(aPitch))*Sqrt((fa*fd-fyd0)/penTarget->en_fGravityA)); + // calculate heading correction + FLOAT3D vDir = (vNewTarget-vShooting).Normalize(); + ANGLE3D aAngles; + DirectionVectorToAngles(vDir, aAngles); + aHeading = aAngles(1); + } + + // spawn one projectile towards the target + void SpawnShoot(CEntity *penTarget) + { + // if not movable entity + if (penTarget==NULL || !(penTarget->GetPhysicsFlags()&EPF_MOVABLE)) { + // do nothing + return; + } + + CPlacement3D plLava = GetPlacement(); + + FLOAT fSpeed = (m_fMaxSpeed-m_fMinSpeed)*FRnd() + m_fMinSpeed; + + // if shootind with free falling projectile + if (m_bShootInArc) { + // calculate speed for angular launch + FLOAT fPitch = GetPlacement().pl_OrientationAngle(2); + FLOAT fHeading; + CalculateAngularLaunchParams((CMovableEntity*)penTarget, + GetPlacement().pl_PositionVector, + penTarget->GetPlacement().pl_PositionVector, + ((CMovableEntity*)penTarget)->en_vCurrentTranslationAbsolute, + fPitch, fHeading, fSpeed); + + // if the heading is out of range + if (Abs(NormalizeAngle(GetPlacement().pl_OrientationAngle(1)-fHeading)) >m_fAngle) { + // do nothing + return; + } + plLava.pl_OrientationAngle(1) = fHeading; + // if shootind with propelled projectile + } else { + // calculate direction + FLOAT3D vTargetDir = (penTarget->GetPlacement().pl_PositionVector- + GetPlacement().pl_PositionVector).Normalize(); + FLOAT3D vShootDir; + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, vShootDir); + + // if the heading is out of range + if (Abs(vTargetDir%vShootDir) < Cos(m_fAngle)) { + // do nothing + return; + } + + DirectionVectorToAngles(vTargetDir, plLava.pl_OrientationAngle); + } + + // create lava + SpawnProjectile(plLava, fSpeed); + } + + // spawn one projectile in random direction + void SpawnRandom(void) + { + // generate speed + FLOAT fSpeed = (m_fMaxSpeed-m_fMinSpeed)*FRnd() + m_fMinSpeed; + ANGLE3D aAngle((FRnd()*2-1)*m_fAngle, (FRnd()*2-1)*m_fAngle, 0); + // create placement + CPlacement3D plLava(FLOAT3D(0, 0, 0), aAngle); + plLava.RelativeToAbsolute(GetPlacement()); + + SpawnProjectile(plLava, fSpeed); + } + + // fire projectile in given direction with given speed + void SpawnProjectile(const CPlacement3D &pl, FLOAT fSpeed) + { + CEntityPointer penLava = CreateEntity(pl, CLASS_PROJECTILE); + + // launch + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = m_ptType; + eLaunch.fSpeed = fSpeed; + penLava->Initialize(eLaunch); + + // stretch + if (!(penLava->GetFlags()&ENF_DELETED)) { + FLOAT3D fStretchRandom(1, 1, 1); + if (m_bRandomStretch) { + fStretchRandom(1) = (FRnd()*m_fStretchWidth *2 - m_fStretchWidth ) + 1; + fStretchRandom(2) = (FRnd()*m_fStretchHeight*2 - m_fStretchHeight) + 1; + fStretchRandom(3) = (FRnd()*m_fStretchDepth *2 - m_fStretchDepth ) + 1; + } + FLOAT3D vOldStretch = penLava->GetModelObject()->mo_Stretch; + penLava->GetModelObject()->mo_Stretch = FLOAT3D( + m_fStretchAll*m_fStretchX*fStretchRandom(1)*vOldStretch(1), + m_fStretchAll*m_fStretchY*fStretchRandom(2)*vOldStretch(2), + m_fStretchAll*m_fStretchZ*fStretchRandom(3)*vOldStretch(3)); + penLava->ModelChangeNotify(); + } + } +procedures: +/************************************************************ + * A C T I O N S * + ************************************************************/ + // active state + Active(EVoid) + { + wait() { + on (EBegin) : { call AutoSpawns(); } + on (EEnvironmentStop) : { jump Inactive(); } + } + }; + + // inactive state + Inactive(EVoid) + { + wait() { + on (EBegin) : { resume; } + on (EEnvironmentStart) : { jump Active(); } + } + }; + + // spawn projectiles automatically + AutoSpawns(EVoid) + { + while (TRUE) { + // wait before spawn next + autowait(m_fTime); + + // spawn one projectile + SpawnRandom(); + + // random wait + if (m_fRandomWait > 0.0f) { autowait(m_fRandomWait); } + } + }; + + + +/************************************************************ + * M A I N L O O P * + ************************************************************/ + // main loop + MainLoop(EVoid) { + wait() { + on(EBegin) : { + call Inactive(); + }; + on(ETrigger eTrigger) : { + SpawnShoot(eTrigger.penCaused); + } + otherwise() : {resume;}; + } + + // cease to exist + Destroy(); + + return; + }; + + Main(EVoid) { + // init as model + CModelHolder2::InitModelHolder(); + + // limit values + if (m_fTime <= 0.0f) { m_fTime = 0.05f; } + if (m_fMaxSpeed < m_fMinSpeed) { m_fMaxSpeed = m_fMinSpeed; } + if (m_fAngle < 0.0f) { m_fAngle = 0.0f; } + + // stretch factors must not have extreme values + if (Abs(m_fStretchX) < 0.01f) { m_fStretchX = 0.01f; } + if (Abs(m_fStretchY) < 0.01f) { m_fStretchY = 0.01f; } + if (Abs(m_fStretchZ) < 0.01f) { m_fStretchZ = 0.01f; } + if (m_fStretchAll< 0.01f) { m_fStretchAll = 0.01f; } + + if (Abs(m_fStretchX) >100.0f) { m_fStretchX = 100.0f*Sgn(m_fStretchX); } + if (Abs(m_fStretchY) >100.0f) { m_fStretchY = 100.0f*Sgn(m_fStretchY); } + if (Abs(m_fStretchZ) >100.0f) { m_fStretchZ = 100.0f*Sgn(m_fStretchZ); } + if (m_fStretchAll>100.0f) { m_fStretchAll = 100.0f; } + + if (m_fStretchWidth <0.0f) { m_fStretchWidth = 0.0f; }; + if (m_fStretchHeight<0.0f) { m_fStretchHeight = 0.0f; }; + if (m_fStretchDepth <0.0f) { m_fStretchDepth = 0.0f; }; + if (m_fStretchWidth >1.0f) { m_fStretchWidth = 1.0f; }; + if (m_fStretchHeight>1.0f) { m_fStretchHeight = 1.0f; }; + if (m_fStretchDepth >1.0f) { m_fStretchDepth = 1.0f; }; + + jump MainLoop(); + } +}; diff --git a/Sources/Entities/Eyeman.es b/Sources/Entities/Eyeman.es new file mode 100644 index 0000000..6b96af1 --- /dev/null +++ b/Sources/Entities/Eyeman.es @@ -0,0 +1,517 @@ +323 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Eyeman/Eyeman.h" +%} + +uses "Entities/EnemyFly"; + +enum EyemanChar { + 0 EYC_SOLDIER "Soldier", // soldier + 1 EYC_SERGEANT "Sergeant", // sergeant +}; + +enum EyemanEnv { + 0 EYE_NORMAL "Normal", + 1 EYE_LAVA "Lava", +}; + +%{ +// info structure +static EntityInfo eiEyemanBig = { + EIBT_FLESH, 140.0f, + 0.0f, 1.4f, 0.0f, + 0.0f, 1.0f, 0.0f, +}; +static EntityInfo eiEyemanSmall = { + EIBT_FLESH, 120.0f, + 0.0f, 1.4f, 0.0f, + 0.0f, 1.0f, 0.0f, +}; + +#define BITE_AIR 3.0f +#define HIT_GROUND 2.0f +#define FIRE_GROUND FLOAT3D(0.75f, 1.5f, -1.25f) +%} + + +class CEyeman : CEnemyFly { +name "Eyeman"; +thumbnail "Thumbnails\\Eyeman.tbn"; + +properties: + 1 enum EyemanChar m_EecChar "Character" 'C' = EYC_SOLDIER, // character + 2 BOOL m_bInvisible "Invisible" 'I'=FALSE, + 3 enum EyemanEnv m_eeEnv "Environment" 'E' = EYE_NORMAL, + 4 BOOL m_bMumbleSoundPlaying = FALSE, + 5 CSoundObject m_soMumble, + +components: + 0 class CLASS_BASE "Classes\\EnemyFly.ecl", + 1 model MODEL_EYEMAN "Models\\Enemies\\Eyeman\\Eyeman.mdl", + 2 texture TEXTURE_EYEMAN_SOLDIER "Models\\Enemies\\Eyeman\\Eyeman4.tex", + 3 texture TEXTURE_EYEMAN_SERGEANT "Models\\Enemies\\Eyeman\\Eyeman5.tex", + 5 texture TEXTURE_EYEMAN_LAVA "Models\\Enemies\\Eyeman\\Eyeman6.tex", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Eyeman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Eyeman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Eyeman\\Sounds\\Wound.wav", + 53 sound SOUND_BITE "Models\\Enemies\\Eyeman\\Sounds\\Bite.wav", + 54 sound SOUND_PUNCH "Models\\Enemies\\Eyeman\\Sounds\\Punch.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Eyeman\\Sounds\\Death.wav", + 56 sound SOUND_MUMBLE "Models\\Enemies\\Eyeman\\Sounds\\Mumble.wav", + + /* + 60 model MODEL_EYEMAN_BODY "Models\\Enemies\\Eyeman\\Debris\\Torso.mdl", + 61 model MODEL_EYEMAN_HAND "Models\\Enemies\\Eyeman\\Debris\\Arm.mdl", + 62 model MODEL_EYEMAN_LEGS "Models\\Enemies\\Eyeman\\Debris\\Leg.mdl", + */ + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + if (m_bInAir) { + str.PrintF(TRANS("A Gnaar bit %s to death"), (const char*)strPlayerName); + } else { + str.PrintF(TRANS("%s was beaten up by a Gnaar"), (const char*)strPlayerName); + } + return str; + } + void Precache(void) { + CEnemyBase::Precache(); + PrecacheSound(SOUND_IDLE ); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_BITE ); + PrecacheSound(SOUND_PUNCH); + PrecacheSound(SOUND_DEATH); + PrecacheSound(SOUND_MUMBLE); + }; + + /* Entity info */ + void *GetEntityInfo(void) { + if (m_EecChar==EYC_SERGEANT) { + return &eiEyemanBig; + } else { + return &eiEyemanSmall; + } + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // eyeman can't harm eyeman + if (!IsOfClass(penInflictor, "Eyeman")) { + CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + CEnemyBase::FillEntityStatistics(pes); + switch(m_EecChar) { + case EYC_SERGEANT: { pes->es_strName+=" Sergeant"; } break; + case EYC_SOLDIER : { pes->es_strName+=" Soldier"; } break; + } + if (m_bInvisible) { + pes->es_strName+=" Invisible"; + } + return TRUE; + } + + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnmSergeant, "Data\\Messages\\Enemies\\EyemanGreen.txt"); + static DECLARE_CTFILENAME(fnmSoldier , "Data\\Messages\\Enemies\\EyemanPurple.txt"); + switch(m_EecChar) { + default: ASSERT(FALSE); + case EYC_SERGEANT: return fnmSergeant; + case EYC_SOLDIER : return fnmSoldier; + } + }; + /* Adjust model shading parameters if needed. */ + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + // no shadows for invisibles + if (m_bInvisible) { + colAmbient = C_WHITE; + return FALSE; + } else { + return CEnemyBase::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + } + } + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + DeactivateMumblingSound(); + INDEX iAnim; + if (m_bInAir) { + switch (IRnd()%2) { + case 0: iAnim = EYEMAN_ANIM_MORPHWOUND01; break; + case 1: iAnim = EYEMAN_ANIM_MORPHWOUND02; break; + default: ASSERTALWAYS("Eyeman unknown fly damage"); + } + } else { + FLOAT3D vFront; + GetHeadingDirection(0, vFront); + FLOAT fDamageDir = m_vDamage%vFront; + if (Abs(fDamageDir)<=10) { + switch (IRnd()%3) { + case 0: iAnim = EYEMAN_ANIM_WOUND03; break; + case 1: iAnim = EYEMAN_ANIM_WOUND06; break; + case 2: iAnim = EYEMAN_ANIM_WOUND07; break; + } + } else { + if (fDamageDir<0) { + iAnim = EYEMAN_ANIM_FALL01; + } else { + iAnim = EYEMAN_ANIM_FALL02; + } + } + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + DeactivateMumblingSound(); + INDEX iAnim; + if (m_bInAir) { + iAnim = EYEMAN_ANIM_MORPHDEATH; + } else { + FLOAT3D vFront; + GetHeadingDirection(0, vFront); + FLOAT fDamageDir = m_vDamage%vFront; + if (fDamageDir<0) { + iAnim = EYEMAN_ANIM_DEATH02; + } else { + iAnim = EYEMAN_ANIM_DEATH01; + } + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(EYEMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // mumbling sounds + void ActivateMumblingSound(void) + { + if (!m_bMumbleSoundPlaying) { + PlaySound(m_soMumble, SOUND_MUMBLE, SOF_3D|SOF_LOOP); + m_bMumbleSoundPlaying = TRUE; + } + } + void DeactivateMumblingSound(void) + { + m_soMumble.Stop(); + m_bMumbleSoundPlaying = FALSE; + } + + // virtual anim functions + void StandingAnim(void) { + DeactivateMumblingSound(); + if (m_bInAir) { + StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(EYEMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + } + }; + void WalkingAnim(void) { + ActivateMumblingSound(); + if (m_bInAir) { + StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(EYEMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) { + ActivateMumblingSound(); + if (m_bInAir) { + StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(EYEMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + } + }; + void RotatingAnim(void) { + if (m_bInAir) { + StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(EYEMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + } + }; + FLOAT AirToGroundAnim(void) { + StartModelAnim(EYEMAN_ANIM_MORPHUP, 0); + return(GetModelObject()->GetAnimLength(EYEMAN_ANIM_MORPHUP)); + }; + FLOAT GroundToAirAnim(void) { + StartModelAnim(EYEMAN_ANIM_MORPHDOWN, 0); + return(GetModelObject()->GetAnimLength(EYEMAN_ANIM_MORPHDOWN)); + }; + void ChangeCollisionToAir() { + ChangeCollisionBoxIndexWhenPossible(EYEMAN_COLLISION_BOX_AIR); + }; + void ChangeCollisionToGround() { + ChangeCollisionBoxIndexWhenPossible(EYEMAN_COLLISION_BOX_GROUND); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + // spawn body parts + /*void BlowUp(void) + { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + + vNormalizedDamage *= 0.75f; + + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + + // spawn debris + Debris_Begin(EIBT_FLESH, DPT_BLOODTRAIL, BET_BLOODSTAIN, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); + + INDEX iTextureID = TEXTURE_EYEMAN_SOLDIER; + if (m_EecChar==EYC_SERGEANT) + { + iTextureID = TEXTURE_EYEMAN_SERGEANT; + } + + Debris_Spawn(this, this, MODEL_EYEMAN_BODY, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_EYEMAN_HAND, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_EYEMAN_HAND, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_EYEMAN_LEGS, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + };*/ + +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + // check whether may move while attacking + BOOL MayMoveToAttack(void) + { + if (m_bInAir) { + return WouldNotLeaveAttackRadius(); + } else { + return CEnemyBase::MayMoveToAttack(); + } + } + + // must be more relaxed about hitting then usual enemies + BOOL CanHitEnemy(CEntity *penTarget, FLOAT fCosAngle) { + if (IsInPlaneFrustum(penTarget, fCosAngle)) { + return IsVisibleCheckAll(penTarget); + } + return FALSE; + }; +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + + FlyHit(EVoid) : CEnemyFly::FlyHit { + if (CalcDist(m_penEnemy) > BITE_AIR) { + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + } + StartModelAnim(EYEMAN_ANIM_MORPHATTACK, 0); + StopMoving(); + PlaySound(m_soSound, SOUND_BITE, SOF_3D); + // damage enemy + autowait(0.4f); + // damage enemy + if (CalcDist(m_penEnemy) < BITE_AIR) { + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 3.5f, FLOAT3D(0, 0, 0), vDirection); + // spawn blood cloud + ESpawnEffect eSpawnEffect; + eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; + eSpawnEffect.betType = BET_BLOODEXPLODE; + eSpawnEffect.vStretch = FLOAT3D(1,1,1); + CPlacement3D plOne = GetPlacement(); + GetEntityPointRatio( + FLOAT3D(Lerp(-0.2f, +0.2f, FRnd()), Lerp(-0.2f, +0.2f, FRnd()), -1.0f), + plOne.pl_PositionVector); + CEntityPointer penBloodCloud = CreateEntity( plOne, CLASS_BASIC_EFFECT); + penBloodCloud->Initialize( eSpawnEffect); + } + autowait(0.24f); + + StandingAnim(); + return EReturn(); + }; + + GroundHit(EVoid) : CEnemyFly::GroundHit { + if (CalcDist(m_penEnemy) > HIT_GROUND) { + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + } + StartModelAnim(EYEMAN_ANIM_ATTACK02, 0); + StopMoving(); + // damage enemy + autowait(0.2f); + // damage enemy + if (CalcDist(m_penEnemy) < HIT_GROUND) { + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 3.5f, FLOAT3D(0, 0, 0), vDirection); + PlaySound(m_soSound, SOUND_PUNCH, SOF_3D); + } + autowait(0.3f); + // damage enemy + if (CalcDist(m_penEnemy) < HIT_GROUND) { + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 3.5f, FLOAT3D(0, 0, 0), vDirection); + PlaySound(m_soSound, SOUND_PUNCH, SOF_3D); + } + autowait(0.4f); + + StandingAnim(); + return EReturn(); + }; + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + if (m_EecChar==EYC_SERGEANT) { + SetHealth(90.0f); + m_fMaxHealth = 90.0f; + // damage/explode properties + m_fBlowUpAmount = 130.0f; + m_fBodyParts = 5; + m_fBlowUpSize = 2.5f; + m_fDamageWounded = 40.0f; + } else { + SetHealth(60.0f); + m_fMaxHealth = 60.0f; + // damage/explode properties + m_fBlowUpAmount = 100.0f; + m_fBodyParts = 5; + m_fBlowUpSize = 2.0f; + m_fDamageWounded = 25.0f; + } + en_fDensity = 2000.0f; + if (m_EeftType == EFT_GROUND_ONLY) { + en_tmMaxHoldBreath = 5.0f; + } else { + en_tmMaxHoldBreath = 30.0f; + } + + // set your appearance + SetModel(MODEL_EYEMAN); + if (m_EecChar==EYC_SERGEANT) { + SetModelMainTexture(TEXTURE_EYEMAN_SERGEANT); + GetModelObject()->StretchModel(FLOAT3D(1.3f, 1.3f, 1.3f)); + ModelChangeNotify(); + m_iScore = 1000; + } else { + m_iScore = 500; + if (m_eeEnv == EYE_LAVA) { + SetModelMainTexture(TEXTURE_EYEMAN_LAVA); + } else { + SetModelMainTexture(TEXTURE_EYEMAN_SOLDIER); + } + GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)); + ModelChangeNotify(); + } + if (m_bInvisible) { + GetModelObject()->mo_colBlendColor = C_WHITE|0x25; + m_iScore*=2; + } + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = FRnd()*10.0f + 500.0f; + if (m_EecChar==EYC_SERGEANT) { + m_fAttackRunSpeed = FRnd()*2.0f + 10.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 10.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + } else { + m_fAttackRunSpeed = FRnd()*2.0f + 9.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 9.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + } + // setup attack distances + m_fAttackDistance = 100.0f; + m_fCloseDistance = 3.5f; + m_fStopDistance = 1.5f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 0.5f; + m_fIgnoreRange = 200.0f; + // fly moving properties + m_fFlyWalkSpeed = FRnd()*2.0f + 3.0f; + m_aFlyWalkRotateSpeed = FRnd()*20.0f + 600.0f; + if (m_EecChar==EYC_SERGEANT) { + m_fFlyAttackRunSpeed = FRnd()*2.0f + 9.5f; + m_aFlyAttackRotateSpeed = FRnd()*25 + 350.0f; + m_fFlyCloseRunSpeed = FRnd()*2.0f + 9.5f; + m_aFlyCloseRotateSpeed = FRnd()*50 + 400.0f; + } else { + m_fFlyAttackRunSpeed = FRnd()*2.0f + 9.5f; + m_aFlyAttackRotateSpeed = FRnd()*25 + 300.0f; + m_fFlyCloseRunSpeed = FRnd()*2.0f + 9.5f; + m_aFlyCloseRotateSpeed = FRnd()*50 + 300.0f; + } + m_fGroundToAirSpeed = 2.5f; + m_fAirToGroundSpeed = 2.5f; + m_fAirToGroundMin = 0.1f; + m_fAirToGroundMax = 0.1f; + m_fFlyHeight = 1.0f; + // attack properties - CAN BE SET + m_fFlyAttackDistance = 100.0f; + m_fFlyCloseDistance = 10.0f; + m_fFlyStopDistance = 1.5f; + m_fFlyAttackFireTime = 2.0f; + m_fFlyCloseFireTime = 0.5f; + m_fFlyIgnoreRange = 200.0f; + m_soMumble.Set3DParameters(25.0f, 0.0f, 1.0f, 1.0f); + + // continue behavior in base class + jump CEnemyFly::MainLoop(); + }; +}; diff --git a/Sources/Entities/Fish.es b/Sources/Entities/Fish.es new file mode 100644 index 0000000..93d3eb5 --- /dev/null +++ b/Sources/Entities/Fish.es @@ -0,0 +1,335 @@ +337 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Fish/Fish.h" +%} + +uses "Entities/EnemyDive"; + +%{ +static EntityInfo eiFish = { + EIBT_FLESH, 100.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; + +#define DISTANCE_ELECTRICITY 8.0f +%} + +class CFish : CEnemyDive { +name "Fish"; +thumbnail "Thumbnails\\Fish.tbn"; + +properties: + 0 BOOL m_bAttackingByElectricity = FALSE, + 1 FLOAT m_tmElectricityTimeStart = 0.0f, + +components: + 0 class CLASS_BASE "Classes\\EnemyDive.ecl", + 1 model MODEL_FISH "Models\\Enemies\\Fish\\Fish.mdl", + 2 texture TEXTURE_FISH "Models\\Enemies\\Fish\\Fish1.tex", + 3 model MODEL_GLOW "Models\\Enemies\\Fish\\Glow.mdl", + 4 texture TEXTURE_GLOW "Models\\Enemies\\Fish\\Glow.tex", + 5 texture TEXTURE_SPECULAR "Models\\SpecularTextures\\Medium.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Fish\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Fish\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Fish\\Sounds\\Wound.wav", + 53 sound SOUND_DEATH "Models\\Enemies\\Fish\\Sounds\\Death.wav", + 54 sound SOUND_ATTACK "Models\\Enemies\\Fish\\Sounds\\Attack.wav", + 55 sound SOUND_WOUNDAIR "Models\\Enemies\\Fish\\Sounds\\WoundAir.wav", + 56 sound SOUND_DEATHAIR "Models\\Enemies\\Fish\\Sounds\\DeathAir.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("%s was electrocuted by a fish"),(const char*) strPlayerName); + return str; + } + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Fish.txt"); + return fnm; + }; + void Precache(void) { + CEnemyBase::Precache(); + PrecacheModel(MODEL_GLOW ); + PrecacheTexture(TEXTURE_GLOW); + PrecacheSound(SOUND_IDLE); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_DEATH); + PrecacheSound(SOUND_WOUNDAIR); + PrecacheSound(SOUND_DEATHAIR); + PrecacheSound(SOUND_ATTACK); + }; + + /* Entity info */ + void *GetEntityInfo(void) + { + return &eiFish; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + if (dmtType==DMT_DROWNING) { + //en_tmMaxHoldBreath = -5.0f; + fDamageAmmount/=2.0f; + } + // fish can't harm fish + if (!IsOfClass(penInflictor, "Fish")) { + CEnemyDive::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) + { + m_bAttackingByElectricity = FALSE; + INDEX iAnim = FISH_ANIM_WOUND; + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + if (!m_bInLiquid) { + return AnimForDamage(10.0f); + } + INDEX iAnim; + switch (IRnd()%3) { + default: iAnim = FISH_ANIM_DEATH; break; + case 0: iAnim = FISH_ANIM_DEATH; break; + case 1: iAnim = FISH_ANIM_DEATH02; break; + case 2: iAnim = FISH_ANIM_DEATH03; break; + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) + { + m_bAttackingByElectricity = FALSE; + en_fDensity = 500.0f; + }; + + void RenderParticles(void) + { + if( m_bAttackingByElectricity && m_penEnemy!=NULL) + { + // render one lightning toward enemy + FLOAT3D vSource = GetPlacement().pl_PositionVector; + FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; + FLOAT3D vDirection = (vTarget-vSource).Normalize(); + Particles_Ghostbuster(vSource, vTarget, 32, 1.0f); + + // random lightnings arround + for( INDEX i=0; i<4; i++) + { + FLOAT3D vDirection = vSource; + vDirection(1) += ((FLOAT(rand())/RAND_MAX)-0.5f) * DISTANCE_ELECTRICITY/1.0f; + vDirection(2) += ((FLOAT(rand())/RAND_MAX)-0.5f) * DISTANCE_ELECTRICITY/1.0f; + vDirection(3) += ((FLOAT(rand())/RAND_MAX)-0.5f) * DISTANCE_ELECTRICITY/1.0f; + Particles_Ghostbuster(vSource, vDirection, 32, 1.0f); + } + } + CEnemyBase::RenderParticles(); + } + // virtual anim functions + void StandingAnim(void) + { + StartModelAnim(FISH_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) + { + if (m_bInLiquid) { + StartModelAnim(FISH_ANIM_SWIM, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(FISH_ANIM_WOUND, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) + { + WalkingAnim(); + }; + void RotatingAnim(void) + { + WalkingAnim(); + }; + + // virtual sound functions + void IdleSound(void) + { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D|SOF_NOFILTER); + }; + void SightSound(void) + { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D|SOF_NOFILTER); + }; + void WoundSound(void) + { + if (m_bInLiquid) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D|SOF_NOFILTER); + } else { + PlaySound(m_soSound, SOUND_WOUNDAIR, SOF_3D|SOF_NOFILTER); + } + }; + void DeathSound(void) + { + if (m_bInLiquid) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D|SOF_NOFILTER); + } else { + PlaySound(m_soSound, SOUND_DEATHAIR, SOF_3D|SOF_NOFILTER); + } + }; + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + FLOAT fTimePassed = _pTimer->GetLerpedCurrentTick()-m_tmElectricityTimeStart; + if( m_bAttackingByElectricity && (fTimePassed>0)) + { + FLOAT fDieFactor = 1.0f; + if( fTimePassed > 0.25f) + { + // calculate light dying factor + fDieFactor = 1.0-(ClampUp(fTimePassed-0.25f,0.5f)/0.5f); + } + // adjust light fx + FLOAT fR = 0.7f+0.1f*(FLOAT(rand())/RAND_MAX); + FLOAT fG = 0.7f+0.2f*(FLOAT(rand())/RAND_MAX); + FLOAT fB = 0.7f+0.3f*(FLOAT(rand())/RAND_MAX); + colAmbient = RGBToColor( fR*128*fDieFactor, fG*128*fDieFactor, fB*128*fDieFactor); + colLight = C_WHITE; + return CEnemyBase::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + } + return CEnemyBase::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + }; + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + DiveHit(EVoid) : CEnemyDive::DiveHit + { + if (CalcDist(m_penEnemy) > DISTANCE_ELECTRICITY) + { + // swim to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + } + + // wait to allow enemy to go aoutside bite range + autowait(0.6f); + + m_bAttackingByElectricity = TRUE; + m_tmElectricityTimeStart = _pTimer->CurrentTick(); + + AddAttachmentToModel(this, *GetModelObject(), FISH_ATTACHMENT_GLOW, MODEL_GLOW, TEXTURE_GLOW, 0, 0, 0); + CModelObject &moGlow = GetModelObject()->GetAttachmentModel(FISH_ATTACHMENT_GLOW)->amo_moModelObject; + moGlow.StretchModel(FLOAT3D(4.0f, 4.0f, 4.0f)); + + // bite + StartModelAnim(FISH_ANIM_ATTACK, 0); + PlaySound(m_soSound, SOUND_ATTACK, SOF_3D|SOF_NOFILTER); + if (CalcDist(m_penEnemy)RemoveAttachmentModel(FISH_ATTACHMENT_GLOW); + + StandingAnim(); + autowait(0.2f + FRnd()/3); + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit + { + jump DiveHit(); + } + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + // fish must not go upstairs, or it will get out of water + SetPhysicsFlags((EPF_MODEL_WALKING|EPF_HASGILLS)&~EPF_ONBLOCK_CLIMBORSLIDE|EPF_ONBLOCK_SLIDE); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(30.0f); + m_fMaxHealth = 30.0f; + en_tmMaxHoldBreath = 15.0f; + en_fDensity = 1000.0f; + m_EedtType = EDT_GROUND_DIVE; + + // set your appearance + SetModel(MODEL_FISH); + SetModelMainTexture(TEXTURE_FISH); + SetModelSpecularTexture(TEXTURE_SPECULAR); + // rotation speeds + m_fDiveWalkSpeed = 15.0f; + m_fDiveAttackRunSpeed = 20.0f; + m_fDiveCloseRunSpeed = 25.0f; + + m_fWalkSpeed = 15.0f; + m_aWalkRotateSpeed = 900.0f; + m_fAttackRunSpeed = 10.0f; + m_fCloseRunSpeed = 12.0f; + // translation speeds + m_aDiveWalkRotateSpeed = 360.0f; + m_aDiveAttackRotateSpeed = 1800.0f; + m_aDiveCloseRotateSpeed = 3600.0f; + // distances + m_fDiveIgnoreRange = 200.0f; + m_fDiveAttackDistance = 100.0f; + m_fDiveCloseDistance = 15.0f; + m_fDiveStopDistance = 2.0f; + // frequencies + m_fDiveAttackFireTime = 0.0f; + m_fDiveCloseFireTime = 0.0f; + // damage/explode properties + m_fBlowUpAmount = 80.0f; + m_fBodyParts = 2; + m_fDamageWounded = 1.0f; + m_iScore = 500; + + { + // translation speeds + m_aWalkRotateSpeed = 360.0f; + m_aAttackRotateSpeed = 1800.0f; + m_aCloseRotateSpeed = 3600.0f; + // distances + m_fIgnoreRange = 200.0f; + m_fAttackDistance = 100.0f; + m_fCloseDistance = 15.0f; + m_fStopDistance = 2.0f; + // frequencies + m_fAttackFireTime = 0.0f; + m_fCloseFireTime = 0.0f; + } + // set stretch factors for height and width + GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)); + ModelChangeNotify(); + + en_fAcceleration = 200.0f; + en_fDeceleration = 200.0f; + + // continue behavior in base class + jump CEnemyDive::MainLoop(); + }; +}; diff --git a/Sources/Entities/Fishman.es b/Sources/Entities/Fishman.es new file mode 100644 index 0000000..bf8338d --- /dev/null +++ b/Sources/Entities/Fishman.es @@ -0,0 +1,350 @@ +328 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Fishman/fishman.h" +%} + +uses "Entities/EnemyDive"; + +%{ +static EntityInfo eiFishmanGround = { + EIBT_FLESH, 100.0f, + 0.0f, 1.4f, 0.0f, + 0.0f, 1.0f, 0.0f, +}; +static EntityInfo eiFishmanLiquid = { + EIBT_FLESH, 33.3f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; + +#define FIRE_WATER FLOAT3D(0.0f, 0.3f, -1.1f) +#define FIRE_GROUND FLOAT3D(0.0f, 0.8f, -1.25f) +#define SPEAR_HIT 1.75f +%} + + +class CFishman : CEnemyDive { +name "Fishman"; +thumbnail "Thumbnails\\Fishman.tbn"; + +properties: +components: + 0 class CLASS_BASE "Classes\\EnemyDive.ecl", + 1 model MODEL_FISHMAN "Models\\Enemies\\Fishman\\Fishman.mdl", + 2 texture TEXTURE_FISHMAN "Models\\Enemies\\Fishman\\Fishman.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE_WATER "Models\\Enemies\\Fishman\\Sounds\\IdleWater.wav", + 51 sound SOUND_IDLE_GROUND "Models\\Enemies\\Fishman\\Sounds\\IdleGround.wav", + 52 sound SOUND_SIGHT_WATER "Models\\Enemies\\Fishman\\Sounds\\SightWater.wav", + 53 sound SOUND_SIGHT_GROUND "Models\\Enemies\\Fishman\\Sounds\\SightGround.wav", + 54 sound SOUND_WOUND_WATER "Models\\Enemies\\Fishman\\Sounds\\WoundWater.wav", + 55 sound SOUND_WOUND_GROUND "Models\\Enemies\\Fishman\\Sounds\\WoundGround.wav", + 56 sound SOUND_DEATH_WATER "Models\\Enemies\\Fishman\\Sounds\\DeathWater.wav", + 57 sound SOUND_DEATH_GROUND "Models\\Enemies\\Fishman\\Sounds\\DeathGround.wav", + 58 sound SOUND_FIRE "Models\\Enemies\\Fishman\\Sounds\\Fire.wav", + 59 sound SOUND_KICK "Models\\Enemies\\Fishman\\Sounds\\Kick.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + if (m_bInLiquid) { + return &eiFishmanLiquid; + } else { + return &eiFishmanGround; + } + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // fishman can't harm fishman + if (!IsOfClass(penInflictor, "Fishman")) { + CEnemyDive::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + if (m_bInLiquid) { + switch (IRnd()%2) { + case 0: iAnim = FISHMAN_ANIM_WATERWOUND01; break; + case 1: iAnim = FISHMAN_ANIM_WATERWOUND02; break; + default: ASSERTALWAYS("Fishman unknown liquid damage"); + } + } else { + switch (IRnd()%3) { + case 0: iAnim = FISHMAN_ANIM_GROUNDWOUND03; break; + case 1: iAnim = FISHMAN_ANIM_GROUNDWOUND04; break; + case 2: iAnim = FISHMAN_ANIM_GROUNDWOUND05; break; + default: ASSERTALWAYS("Fishman unknown ground damage"); + } + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + if (m_bInLiquid) { + iAnim = FISHMAN_ANIM_WATERDEATH; + } else { + iAnim = FISHMAN_ANIM_GROUNDDEATH; + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + if (m_bInLiquid) { + ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_DEATH_WATER); + } else { + ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_DEATH_GROUND); + } + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + if (m_bInLiquid) { + StartModelAnim(FISHMAN_ANIM_WATERSTAND, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(FISHMAN_ANIM_GROUNDSTAND, AOF_LOOPING|AOF_NORESTART); + } + }; + void WalkingAnim(void) { + if (m_bInLiquid) { + StartModelAnim(FISHMAN_ANIM_WATERSWIM02, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(FISHMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) { + if (m_bInLiquid) { + StartModelAnim(FISHMAN_ANIM_WATERSWIM01, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(FISHMAN_ANIM_GROUNDRUN, AOF_LOOPING|AOF_NORESTART); + } + }; + void RotatingAnim(void) { + if (m_bInLiquid) { + StartModelAnim(FISHMAN_ANIM_WATERSWIM02, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(FISHMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); + } + }; + void ChangeCollisionToLiquid() { + ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_WATER); + }; + void ChangeCollisionToGround() { + ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_GROUND); + }; + + // virtual sound functions + void IdleSound(void) { + if (m_bInLiquid) { + PlaySound(m_soSound, SOUND_IDLE_WATER , SOF_3D); + } else { + PlaySound(m_soSound, SOUND_IDLE_GROUND, SOF_3D); + } + }; + void SightSound(void) { + if (m_bInLiquid) { + PlaySound(m_soSound, SOUND_SIGHT_WATER , SOF_3D); + } else { + PlaySound(m_soSound, SOUND_SIGHT_GROUND, SOF_3D); + } + }; + void WoundSound(void) { + if (m_bInLiquid) { + PlaySound(m_soSound, SOUND_WOUND_WATER , SOF_3D); + } else { + PlaySound(m_soSound, SOUND_WOUND_GROUND, SOF_3D); + } + }; + void DeathSound(void) { + if (m_bInLiquid) { + PlaySound(m_soSound, SOUND_DEATH_WATER , SOF_3D); + } else { + PlaySound(m_soSound, SOUND_DEATH_GROUND, SOF_3D); + } + }; + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + DiveFire(EVoid) : CEnemyDive::DiveFire { + // fire projectile + StartModelAnim(FISHMAN_ANIM_WATERATTACK02, 0); + autowait(0.4f); + ShootProjectile(PRT_FISHMAN_FIRE, FIRE_WATER, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.95f); + StandingAnim(); + autowait(FRnd()/3 + _pTimer->TickQuantum); + + return EReturn(); + }; + + DiveHit(EVoid) : CEnemyDive::DiveHit { + if (CalcDist(m_penEnemy) > SPEAR_HIT) { + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + } + + // attack with spear + StartModelAnim(FISHMAN_ANIM_WATERATTACK01, 0); + + // to left hit + autowait(0.5f); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 5.0f, FLOAT3D(0, 0, 0), vDirection); + // push target away + FLOAT3D vSpeed; + GetHeadingDirection(0.0f, vSpeed); + vSpeed = vSpeed * 5.0f; + KickEntity(m_penEnemy, vSpeed); + } + autowait(0.5f); + + StandingAnim(); + autowait(0.2f + FRnd()/3); + return EReturn(); + }; + + Fire(EVoid) : CEnemyBase::Fire { + // wait anim end + if (!GetModelObject()->IsAnimFinished()) { + autowait(GetModelObject()->GetCurrentAnimLength() - GetModelObject()->GetPassedTime()); + } + + // fire projectile + StartModelAnim(FISHMAN_ANIM_GROUNDATTACK02, 0); + autowait(0.3f); + ShootProjectile(PRT_FISHMAN_FIRE, FIRE_GROUND, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.4f); + StandingAnim(); + autowait(FRnd()/3 + _pTimer->TickQuantum); + + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + if (CalcDist(m_penEnemy) > SPEAR_HIT) { + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + } + + // wait anim end + if (!GetModelObject()->IsAnimFinished()) { + autowait(GetModelObject()->GetCurrentAnimLength() - GetModelObject()->GetPassedTime()); + } + + // attack with spear + StartModelAnim(FISHMAN_ANIM_GROUNDATTACKLOOP, 0); + + // to left hit + autowait(0.5f); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 2.5f, FLOAT3D(0, 0, 0), vDirection); + // push target left + FLOAT3D vSpeed; + GetHeadingDirection(90.0f, vSpeed); + vSpeed = vSpeed * 5.0f; + KickEntity(m_penEnemy, vSpeed); + } + autowait(0.5f); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 2.5f, FLOAT3D(0, 0, 0), vDirection); + // push target right + FLOAT3D vSpeed; + GetHeadingDirection(-90.0f, vSpeed); + vSpeed = vSpeed * 5.0f; + KickEntity(m_penEnemy, vSpeed); + } + autowait(0.6f); + + StandingAnim(); + autowait(0.2f + FRnd()/3); + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS|EPF_HASGILLS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(30.0f); + m_fMaxHealth = 30.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 1000.0f; + + // set your appearance + SetModel(MODEL_FISHMAN); + SetModelMainTexture(TEXTURE_FISHMAN); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = FRnd()*10.0f + 500.0f; + m_fAttackRunSpeed = FRnd()*0.5f + 5.0f; + m_aAttackRotateSpeed = FRnd()*50 + 245.0f; + m_fCloseRunSpeed = FRnd()*0.5f + 5.0f; + m_aCloseRotateSpeed = FRnd()*50 + 245.0f; + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 5.0f; + m_fStopDistance = 0.0f; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 2.0f; + m_fIgnoreRange = 200.0f; + // fly moving properties + m_fDiveWalkSpeed = FRnd() + 3.0f; + m_aDiveWalkRotateSpeed = FRnd()*10.0f + 500.0f; + m_fDiveAttackRunSpeed = FRnd()*4.0f + 14.0f; + m_aDiveAttackRotateSpeed = FRnd()*25 + 500.0f; + m_fDiveCloseRunSpeed = FRnd()*2.0f + 8.0f; + m_aDiveCloseRotateSpeed = FRnd()*50 + 800.0f; + // attack properties + m_fDiveAttackDistance = 50.0f; + m_fDiveCloseDistance = 3.0f; + m_fDiveStopDistance = 0.0f; + m_fDiveAttackFireTime = 3.0f; + m_fDiveCloseFireTime = 2.0f; + m_fDiveIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 60.0f; + m_fBodyParts = 4; + m_fDamageWounded = 15.0f; + m_iScore = 500; + + // continue behavior in base class + jump CEnemyDive::MainLoop(); + }; +}; diff --git a/Sources/Entities/Flame.es b/Sources/Entities/Flame.es new file mode 100644 index 0000000..c66c965 --- /dev/null +++ b/Sources/Entities/Flame.es @@ -0,0 +1,182 @@ +504 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Light"; + +// input parameter for flame +event EFlame { + CEntityPointer penOwner, // entity which owns it + CEntityPointer penAttach, // entity on which flame is attached (his parent) +}; + +%{ +void CFlame_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + pdec->PrecacheModel(MODEL_FLAME); + pdec->PrecacheTexture(TEXTURE_FLAME); + pdec->PrecacheSound(SOUND_FLAME); +} +%} + +class CFlame : CMovableModelEntity { +name "Flame"; +thumbnail ""; +features "ImplementsOnPrecache", "CanBePredictable"; + +properties: + 1 CEntityPointer m_penOwner, // entity which owns it + 2 CEntityPointer m_penAttach, // entity on which flame is attached (his parent) + 5 BOOL m_bLoop = FALSE, // internal for loops + + 10 CSoundObject m_soEffect, // sound channel + +{ + CLightSource m_lsLightSource; +} + +components: + 1 class CLASS_LIGHT "Classes\\Light.ecl", + +// ********* FLAME ********* + 10 model MODEL_FLAME "Models\\Effects\\Flame\\Flame.mdl", + //"Models\\Weapons\\Flamer\\Projectile\\Invisible.mdl", + 11 texture TEXTURE_FLAME "Models\\Effects\\Flame\\Flame.tex", + 12 sound SOUND_FLAME "Sounds\\Fire\\Fire4.wav", + +functions: + // add to prediction any entities that this entity depends on + void AddDependentsToPrediction(void) + { + m_penOwner->AddToPrediction(); + } + // postmoving + void PostMoving(void) { + CMovableModelEntity::PostMoving(); + + // if no air + CContentType &ctDn = GetWorld()->wo_actContentTypes[en_iDnContent]; + // stop existing + if (!(ctDn.ct_ulFlags&CTF_BREATHABLE_LUNGS)) { + SendEvent(EEnd()); + } + + // never remove from list of movers + en_ulFlags &= ~ENF_INRENDERING; + // not moving in fact, only moving with its parent + en_plLastPlacement = en_plPlacement; + }; + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CRationalEntity::Read_t(istr); + SetupLightSource(); + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_colColor = C_dYELLOW; + lsNew.ls_rFallOff = 2.0f; + lsNew.ls_rHotSpot = 0.2f; + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> MAIN + Main(EFlame ef) { + // attach to parent (another entity) + ASSERT(ef.penOwner!=NULL); + ASSERT(ef.penAttach!=NULL); + m_penOwner = ef.penOwner; + m_penAttach = ef.penAttach; + SetParent(ef.penAttach); + + // initialization + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_FLYING); + SetCollisionFlags(ECF_FLAME); + SetFlags(GetFlags() | ENF_SEETHROUGH); + + // if parent is model + if (m_penAttach->GetRenderType()==CEntity::RT_MODEL) { + // stretch to its size + FLOATaabbox3D box; + m_penAttach->GetBoundingBox(box); + GetModelObject()->StretchModel(box.Size()); + } + ModelChangeNotify(); + + SetModel(MODEL_FLAME); + SetModelMainTexture(TEXTURE_FLAME); + // play the burning sound + m_soEffect.Set3DParameters(5.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_FLAME, SOF_3D|SOF_LOOP); + + // setup light source + SetupLightSource(); + + // must always be in movers, to find sector content type + AddToMovers(); + + // burning damage + SpawnReminder(this, 7.5f, 0); + m_bLoop = TRUE; + while(m_bLoop) { + wait(0.25f) { + // damage to parent + on (EBegin) : { + // if parent does not exist anymore + if (m_penAttach==NULL || (m_penAttach->GetFlags()&ENF_DELETED)) { + // stop existing + m_bLoop = FALSE; + stop; + } + // inflict damage to parent + m_penAttach->InflictDirectDamage(m_penAttach, m_penOwner, DMT_BURNING, 1.0f, FLOAT3D(0, 0, 0), -en_vGravityDir); + resume; + } + on (EFlame ef) : { + m_penOwner = ef.penOwner; + resume; + }; + on (ETimer) : { stop; } + on (EReminder) : { + m_bLoop = FALSE; + stop; + } + on (EEnd) : { + m_bLoop = FALSE; + stop; + } + } + } + + // cease to exist + Destroy(); + return; + } +}; diff --git a/Sources/Entities/FogMarker.es b/Sources/Entities/FogMarker.es new file mode 100644 index 0000000..7828000 --- /dev/null +++ b/Sources/Entities/FogMarker.es @@ -0,0 +1,142 @@ +215 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +enum FogAttenuationType { + 0 FA_LINEAR "Linear", + 1 FA_EXP "Exp", + 2 FA_EXP2 "Exp2", +}; +enum FogGraduationType2 { + 0 FG_CONSTANT "Constant", + 1 FG_LINEAR "Linear", + 2 FG_EXP "Exp", +}; + +class CFogMarker: CMarker { +name "Fog Marker"; +thumbnail "Thumbnails\\FogMarker.tbn"; +features "IsImportant"; + +properties: + 1 FLOAT m_fDepth "Depth" 'E' = 10.0f, + 2 FLOAT m_fAbove "Above" 'O' = 20.0f, + 3 FLOAT m_fBelow "Below" 'B' = 20.0f, + 4 FLOAT m_fFar "Far" 'F' = 100.0f, + + 10 enum FogAttenuationType m_faType "Attenuation Type" 'A' =FA_EXP, + 11 FLOAT m_fDensity "Density" 'D' = 0.1f, + 12 enum FogGraduationType2 m_fgType "Graduation Type" 'G' =FG_CONSTANT, + 13 FLOAT m_fGraduation "Graduation" 'R' = 0.1f, + + // for indirect density calculation + 14 BOOL m_bDensityDirect "Density Direct" = TRUE, + 15 FLOAT m_fDensityPercentage "DensityPercentage" = 0.95f, + 16 FLOAT m_fDensityDistance "DensityDistance" = 10.0f, + + // for indirect graduation calculation + 17 BOOL m_bGraduationDirect "Graduation Direct" = TRUE, + 18 FLOAT m_fGraduationPercentage "GraduationPercentage" = 0.95f, + 19 FLOAT m_fGraduationDistance "GraduationDistance" = 10.0f, + + 22 INDEX m_iSizeL "Size Distance" 'S' = 32, + 23 INDEX m_iSizeH "Size Depth" 'I' = 16, + 24 COLOR m_colColor "Color" 'C' = (C_WHITE|CT_OPAQUE), + +components: + 1 model MODEL_MARKER "Models\\Editor\\Fog.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Fog.tex" + +functions: + + /* Get fog type name, return empty string if not used. */ + const CTString &GetFogName(void) + { + return m_strName; + } + /* Get fog. */ + void GetFog(class CFogParameters &fpFog) + { + const FLOATmatrix3D &m = GetRotationMatrix(); + fpFog.fp_vFogDir(1) = m(1,2); + fpFog.fp_vFogDir(2) = m(2,2); + fpFog.fp_vFogDir(3) = m(3,2); + FLOAT fPos = fpFog.fp_vFogDir%GetPlacement().pl_PositionVector; + fpFog.fp_colColor = m_colColor; + fpFog.fp_atType = (AttenuationType) m_faType; + fpFog.fp_fDensity = m_fDensity; + fpFog.fp_fgtType = (FogGraduationType) m_fgType; + fpFog.fp_fGraduation = m_fGraduation; + fpFog.fp_fH0 = fPos-m_fDepth-m_fBelow; + fpFog.fp_fH1 = fPos-m_fDepth; + fpFog.fp_fH2 = fPos; + fpFog.fp_fH3 = fPos+m_fAbove; + fpFog.fp_fFar = m_fFar; + fpFog.fp_iSizeH = m_iSizeH; + fpFog.fp_iSizeL = m_iSizeL; + } +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set name + if (m_strName=="Marker") { + m_strName = "Fog marker"; + } + + // if density is calculated indirectly + if (!m_bDensityDirect) { + // calculate density to have given percentage at given distance + switch(m_faType) { + case FA_LINEAR: + m_fDensity = m_fDensityPercentage/m_fDensityDistance; + break; + case FA_EXP: + m_fDensity = -log(1-m_fDensityPercentage)/m_fDensityDistance; + break; + case FA_EXP2: + m_fDensity = Sqrt(-log(1-m_fDensityPercentage))/m_fDensityDistance; + break; + } + } + + // if graduation is calculated indirectly + if (!m_bGraduationDirect) { + // calculate graduation to have given percentage at given depth + switch(m_fgType) { + case FG_LINEAR: + m_fGraduation = m_fGraduationPercentage/m_fGraduationDistance; + break; + case FG_EXP: + m_fGraduation = -log(1-m_fGraduationPercentage)/m_fGraduationDistance; + break; + } + } + + + // clamp values to valid ranges + m_fDensity = ClampDn(m_fDensity, 1E-6f); + + m_fDepth = ClampDn(m_fDepth , 0.001f); + m_fAbove = ClampDn(m_fAbove , 0.001f); + m_fBelow = ClampDn(m_fBelow , 0.001f); + m_fFar = ClampDn(m_fFar, 0.001f); + + m_iSizeL = 1< +#include +CEntityEvent *EGhostBusterRay::MakeCopy(void) { CEntityEvent *peeCopy = new EGhostBusterRay(*this); return peeCopy;} +EGhostBusterRay::EGhostBusterRay() : CEntityEvent(EVENTCODE_EGhostBusterRay) {; + ClearToDefault(penOwner); +}; +#line 16 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" + +#define HIT_DISTANCE 50.0f // ray hit distance +#define HIT_DAMAGE 15.0f // hit damage for every lerping bullet + +void CGhostBusterRay_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + pdec->PrecacheClass(CLASS_BULLET); + pdec->PrecacheModel(MODEL_RAY); + pdec->PrecacheTexture(TEXTURE_RAY); +} + +void CGhostBusterRay::SetDefaultProperties(void) { + m_penOwner = NULL; + m_bRender = FALSE ; + m_vSrcOld = FLOAT3D(0.0f , 0.0f , 0.0f); + m_vDstOld = FLOAT3D(0.0f , 0.0f , 0.0f); + m_vSrc = FLOAT3D(0.0f , 0.0f , 0.0f); + m_vDst = FLOAT3D(0.0f , 0.0f , 0.0f); + m_iLastBulletPosition = FLOAT3D(32000.0f , 32000.0f , 32000.0f); + m_aoLightAnim.SetData(NULL); + + m_ctPasses = 0; + m_penPrediction = NULL; + CMovableModelEntity::SetDefaultProperties(); +} + +#line 61 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::AddDependentsToPrediction(void) +#line 62 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +{ +#line 63 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_penOwner -> AddToPrediction (); +#line 64 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 66 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::RenderParticles(void) +#line 67 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +{ +#line 68 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +if(m_ctPasses < 2){ +#line 69 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +return ; +#line 70 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} +#line 71 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +FLOAT3D vLerpedSrc = Lerp (m_vSrcOld , m_vSrc , _pTimer -> GetLerpFactor ()); +#line 72 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +FLOAT3D vLerpedDst = Lerp (m_vDstOld , m_vDst , _pTimer -> GetLerpFactor ()); +#line 73 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +Particles_Ghostbuster (vLerpedSrc , vLerpedDst , 32 , 1.0f); +#line 74 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 77 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::Read_t(CTStream * istr) +#line 78 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +{ +#line 79 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CMovableModelEntity :: Read_t (istr ); +#line 80 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetupLightSource (); +#line 81 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 84 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CLightSource * CGhostBusterRay::GetLightSource(void) +#line 85 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +{ +#line 86 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +if(! IsPredictor ()){ +#line 87 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +return & m_lsLightSource ; +#line 88 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +}else { +#line 89 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +return NULL ; +#line 90 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} +#line 91 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 94 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::SetupLightSource(void) +#line 95 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +{ +#line 97 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CLightSource lsNew ; +#line 98 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_ulFlags = LSF_NONPERSISTENT | LSF_DYNAMIC ; +#line 99 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_colColor = RGBToColor (134 , 238 , 255); +#line 100 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_rFallOff = 10.0f; +#line 101 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_rHotSpot = 1.0f; +#line 102 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_plftLensFlare = NULL ; +#line 103 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_ubPolygonalMask = 0; +#line 104 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +lsNew . ls_paoLightAnimation = & m_aoLightAnim ; +#line 106 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_lsLightSource . ls_penEntity = this ; +#line 107 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_lsLightSource . SetLightSource (lsNew ); +#line 108 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 115 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::DoMoving(void) { +#line 116 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +en_plLastPlacement = GetPlacement (); +#line 117 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 119 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::PostMoving(void) { +#line 120 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +if(! IsOfClass (m_penOwner , "Player Weapons")){return ;} +#line 123 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CPlacement3D plSource ; +#line 124 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CPlayerWeapons &) * m_penOwner ) . GetGhostBusterSourcePlacement (plSource ); +#line 125 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +FLOAT3D vDirection , vDesired ; +#line 126 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +AnglesToDirectionVector (plSource . pl_OrientationAngle , vDirection ); +#line 127 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +vDesired = vDirection * HIT_DISTANCE ; +#line 128 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +vDesired = plSource . pl_PositionVector + vDesired ; +#line 131 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CCastRay crRay (((CPlayerWeapons &) * m_penOwner ) . m_penPlayer , plSource . pl_PositionVector , vDesired ); +#line 132 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_vSrcOld = m_vSrc ; +#line 133 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_vSrc = plSource . pl_PositionVector ; +#line 134 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +crRay . cr_bHitTranslucentPortals = FALSE ; +#line 135 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +crRay . cr_ttHitModels = CCastRay :: TT_COLLISIONBOX ; +#line 136 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +GetWorld () -> CastRay (crRay ); +#line 139 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +if(crRay . cr_penHit != NULL ){ +#line 140 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +vDesired = crRay . cr_vHit ; +#line 141 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} +#line 142 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +vDesired -= vDirection / 10.0f; +#line 144 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_vDstOld = m_vDst ; +#line 145 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_vDst = vDesired ; +#line 148 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +FLOAT fStretch = (plSource . pl_PositionVector - vDesired ) . Length (); +#line 150 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +GetModelObject () -> mo_Stretch (3) = 0.001f; +#line 152 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CPlacement3D plSet ; +#line 153 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +plSet . pl_PositionVector = vDesired ; +#line 154 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +plSet . pl_OrientationAngle = plSource . pl_OrientationAngle ; +#line 155 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetPlacement (plSet ); +#line 156 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_ctPasses ++; +#line 157 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 165 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::PrepareBullet(const CPlacement3D & plBullet) { +#line 167 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +penBullet = CreateEntity (plBullet , CLASS_BULLET ); +#line 169 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +EBulletInit eInit ; +#line 170 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +eInit . penOwner = ((CPlayerWeapons &) * m_penOwner ) . m_penPlayer ; +#line 171 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +eInit . fDamage = HIT_DAMAGE ; +#line 172 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +penBullet -> Initialize (eInit ); +#line 173 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CBullet &) * penBullet ) . m_EdtDamage = DMT_BULLET ; +#line 174 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 177 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::Fire(const CPlacement3D & plSource) { +#line 178 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +if(! IsOfClass (m_penOwner , "Player Weapons")){return ;} +#line 181 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +PrepareBullet (plSource ); +#line 182 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CBullet &) * penBullet ) . CalcTarget (HIT_DISTANCE ); +#line 183 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CBullet &) * penBullet ) . m_fBulletSize = 0.5f; +#line 184 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CBullet &) * penBullet ) . CalcJitterTarget (0.02f * HIT_DISTANCE ); +#line 185 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CBullet &) * penBullet ) . LaunchBullet (TRUE , FALSE , TRUE ); +#line 186 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +((CBullet &) * penBullet ) . DestroyBullet (); +#line 187 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} + +#line 190 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void CGhostBusterRay::DestroyGhostBusterRay(void) { +#line 191 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +Destroy (); +#line 192 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} +BOOL CGhostBusterRay:: +#line 201 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +Main(const CEntityEvent &__eeInput) { +#undef STATE_CURRENT +#define STATE_CURRENT STATE_CGhostBusterRay_Main + ASSERTMSG(__eeInput.ee_slEvent==EVENTCODE_EGhostBusterRay, "CGhostBusterRay::Main expects 'EGhostBusterRay' as input!"); const EGhostBusterRay &egbr = (const EGhostBusterRay &)__eeInput; +#line 203 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +ASSERT (egbr . penOwner != NULL ); +#line 204 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_penOwner = egbr . penOwner ; +#line 207 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +InitAsModel (); +#line 208 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetPhysicsFlags (EPF_MODEL_IMMATERIAL ); +#line 209 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetCollisionFlags (ECF_IMMATERIAL ); +#line 210 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetModel (MODEL_RAY ); +#line 211 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetModelMainTexture (TEXTURE_RAY ); +#line 213 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +try { +#line 214 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_aoLightAnim . SetData_t (CTFILENAME ("Animations\\GhostbusterLightning.ani")); +#line 215 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_aoLightAnim . PlayAnim (0 , AOF_LOOPING ); +#line 216 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +}catch (char * strError ){ +#line 217 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CPrintF ("%s" , strError ); +#line 218 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +} +#line 221 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +SetupLightSource (); +#line 224 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +AddToMovers (); +#line 225 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +m_ctPasses = 0; +#line 227 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +Return(STATE_CURRENT,EVoid()); +#line 227 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +return TRUE; ASSERT(FALSE); return TRUE;}; \ No newline at end of file diff --git a/Sources/Entities/GhostBusterRay.es b/Sources/Entities/GhostBusterRay.es new file mode 100644 index 0000000..7839b12 --- /dev/null +++ b/Sources/Entities/GhostBusterRay.es @@ -0,0 +1,229 @@ +505 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Light"; +uses "Entities/Bullet"; +uses "Entities/PlayerWeapons"; +uses "Engine/Classes/MovableEntity"; + +// input parameter for ghost buster ray +event EGhostBusterRay { + CEntityPointer penOwner, // entity which owns it +}; + +%{ +#define HIT_DISTANCE 50.0f // ray hit distance +#define HIT_DAMAGE 15.0f // hit damage for every lerping bullet + +void CGhostBusterRay_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + pdec->PrecacheClass(CLASS_BULLET); + pdec->PrecacheModel(MODEL_RAY); + pdec->PrecacheTexture(TEXTURE_RAY); +} +%} + + +class CGhostBusterRay : CMovableModelEntity { +name "GhostBusterRay"; +thumbnail ""; +features "ImplementsOnPrecache", "CanBePredictable"; + +properties: + 1 CEntityPointer m_penOwner, // entity which owns it + 2 BOOL m_bRender = FALSE, // do not render on startup + 3 FLOAT3D m_vSrcOld = FLOAT3D(0.0f, 0.0f, 0.0f), + 4 FLOAT3D m_vDstOld = FLOAT3D(0.0f, 0.0f, 0.0f), + 5 FLOAT3D m_vSrc = FLOAT3D(0.0f, 0.0f, 0.0f), + 6 FLOAT3D m_vDst = FLOAT3D(0.0f, 0.0f, 0.0f), + 10 FLOAT3D m_iLastBulletPosition = FLOAT3D(32000.0f, 32000.0f, 32000.0f), // for lerping + 11 CAnimObject m_aoLightAnim, + 12 INDEX m_ctPasses = 0, // for lerping initialization + +{ + CLightSource m_lsLightSource; + CEntity *penBullet; + const CPlacement3D *pplSource; +} + +components: + 1 class CLASS_LIGHT "Classes\\Light.ecl", + 2 class CLASS_BULLET "Classes\\Bullet.ecl", + +// ********* RAY ********* + 10 model MODEL_RAY "Models\\Weapons\\GhostBuster\\Projectile\\Ray.mdl", + 11 texture TEXTURE_RAY "Models\\Weapons\\GhostBuster\\Projectile\\Ray.tex", + +functions: + // add to prediction any entities that this entity depends on + void AddDependentsToPrediction(void) + { + m_penOwner->AddToPrediction(); + } + // render particles + void RenderParticles(void) + { + if (m_ctPasses<2) { + return; + } + FLOAT3D vLerpedSrc = Lerp(m_vSrcOld, m_vSrc, _pTimer->GetLerpFactor()); + FLOAT3D vLerpedDst = Lerp(m_vDstOld, m_vDst, _pTimer->GetLerpFactor()); + Particles_Ghostbuster(vLerpedSrc, vLerpedDst, 32, 1.0f); + }; + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CMovableModelEntity::Read_t(istr); + SetupLightSource(); + }; + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + }; + + // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_colColor = RGBToColor(134,238,255); + lsNew.ls_rFallOff = 10.0f; + lsNew.ls_rHotSpot = 1.0f; + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = &m_aoLightAnim; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + }; + + + +/************************************************************ + * DO MOVING * + ************************************************************/ + void DoMoving(void) { + en_plLastPlacement = GetPlacement(); // remember old placement for lerping + }; + + void PostMoving(void) { + if (!IsOfClass(m_penOwner, "Player Weapons")) { return; } + + // from current owner position move away + CPlacement3D plSource; + ((CPlayerWeapons&)*m_penOwner).GetGhostBusterSourcePlacement(plSource); + FLOAT3D vDirection, vDesired; + AnglesToDirectionVector(plSource.pl_OrientationAngle, vDirection); + vDesired = vDirection*HIT_DISTANCE; + vDesired = plSource.pl_PositionVector + vDesired; + + // cast a ray to find if any brush is hit + CCastRay crRay( ((CPlayerWeapons&)*m_penOwner).m_penPlayer, plSource.pl_PositionVector, vDesired); + m_vSrcOld = m_vSrc; + m_vSrc = plSource.pl_PositionVector; + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + GetWorld()->CastRay(crRay); + + // if hit anything set new position + if (crRay.cr_penHit!=NULL) { + vDesired = crRay.cr_vHit; + } + vDesired -= vDirection/10.0f; + + m_vDstOld = m_vDst; + m_vDst = vDesired; + + // stretch model + FLOAT fStretch = (plSource.pl_PositionVector - vDesired).Length(); + //GetModelObject()->mo_Stretch(3) = fStretch; + GetModelObject()->mo_Stretch(3) = 0.001f; + // set your new placement + CPlacement3D plSet; + plSet.pl_PositionVector = vDesired; + plSet.pl_OrientationAngle = plSource.pl_OrientationAngle; + SetPlacement(plSet); + m_ctPasses++; + }; + + + +/************************************************************ + * FIRE FUNCTIONS * + ************************************************************/ + // prepare Bullet + void PrepareBullet(const CPlacement3D &plBullet) { + // create bullet + penBullet = CreateEntity(plBullet, CLASS_BULLET); + // init bullet + EBulletInit eInit; + eInit.penOwner = ((CPlayerWeapons&)*m_penOwner).m_penPlayer; + eInit.fDamage = HIT_DAMAGE; + penBullet->Initialize(eInit); + ((CBullet&)*penBullet).m_EdtDamage = DMT_BULLET; + }; + + // fire + void Fire(const CPlacement3D &plSource) { + if (!IsOfClass(m_penOwner, "Player Weapons")) { return; } + + // fire lerped bullets + PrepareBullet(plSource); + ((CBullet&)*penBullet).CalcTarget(HIT_DISTANCE); + ((CBullet&)*penBullet).m_fBulletSize = 0.5f; + ((CBullet&)*penBullet).CalcJitterTarget(0.02f*HIT_DISTANCE); + ((CBullet&)*penBullet).LaunchBullet(TRUE, FALSE, TRUE); + ((CBullet&)*penBullet).DestroyBullet(); + }; + + // destroy yourself + void DestroyGhostBusterRay(void) { + Destroy(); + }; + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> MAIN + Main(EGhostBusterRay egbr) { + // store owner + ASSERT(egbr.penOwner!=NULL); + m_penOwner = egbr.penOwner; + + // initialization + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + SetModel(MODEL_RAY); + SetModelMainTexture(TEXTURE_RAY); + + try { + m_aoLightAnim.SetData_t(CTFILENAME("Animations\\GhostbusterLightning.ani")); + m_aoLightAnim.PlayAnim(0,AOF_LOOPING); + } catch (char *strError) { + CPrintF("%s", strError); + } + + // setup light source + SetupLightSource(); + + // add to movers list + AddToMovers(); + m_ctPasses = 0; + + return; + } +}; diff --git a/Sources/Entities/GhostBusterRay.h b/Sources/Entities/GhostBusterRay.h new file mode 100644 index 0000000..77ae4a6 --- /dev/null +++ b/Sources/Entities/GhostBusterRay.h @@ -0,0 +1,73 @@ +/* + * This file is generated by Entity Class Compiler, (c) CroTeam 1997-98 + */ + +#ifndef _Entities_GhostBusterRay_INCLUDED +#define _Entities_GhostBusterRay_INCLUDED 1 +#include +#include +#include +#include +#define EVENTCODE_EGhostBusterRay 0x01f90000 +class DECL_DLL EGhostBusterRay : public CEntityEvent { +public: +EGhostBusterRay(); +CEntityEvent *MakeCopy(void); +CEntityPointer penOwner; +}; +DECL_DLL inline void ClearToDefault(EGhostBusterRay &e) { e = EGhostBusterRay(); } ; +extern "C" DECL_DLL CDLLEntityClass CGhostBusterRay_DLLClass; +class CGhostBusterRay : public CMovableModelEntity { +public: +virtual CEntity *GetPredictionPair(void) { return m_penPrediction; }; +virtual void SetPredictionPair(CEntity *penPair) { m_penPrediction = penPair; }; + DECL_DLL virtual void SetDefaultProperties(void); + CEntityPointer m_penOwner; + BOOL m_bRender; + FLOAT3D m_vSrcOld; + FLOAT3D m_vDstOld; + FLOAT3D m_vSrc; + FLOAT3D m_vDst; + FLOAT3D m_iLastBulletPosition; + CAnimObject m_aoLightAnim; + INDEX m_ctPasses; + CEntityPointer m_penPrediction; +CLightSource m_lsLightSource; +CEntity * penBullet; +const CPlacement3D * pplSource; + +#line 61 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void AddDependentsToPrediction(void); + +#line 66 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void RenderParticles(void); + +#line 77 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void Read_t(CTStream * istr); + +#line 84 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +CLightSource * GetLightSource(void); + +#line 94 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void SetupLightSource(void); + +#line 115 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void DoMoving(void); + +#line 119 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void PostMoving(void); + +#line 165 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void PrepareBullet(const CPlacement3D & plBullet); + +#line 177 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void Fire(const CPlacement3D & plSource); + +#line 190 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +void DestroyGhostBusterRay(void); +#define STATE_CGhostBusterRay_Main 1 + BOOL +#line 201 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +Main(const CEntityEvent &__eeInput); +}; +#endif // _Entities_GhostBusterRay_INCLUDED diff --git a/Sources/Entities/GhostBusterRay_tables.h b/Sources/Entities/GhostBusterRay_tables.h new file mode 100644 index 0000000..fe1645c --- /dev/null +++ b/Sources/Entities/GhostBusterRay_tables.h @@ -0,0 +1,49 @@ +/* + * This file is generated by Entity Class Compiler, (c) CroTeam 1997-98 + */ + +#define ENTITYCLASS CGhostBusterRay + +CEntityProperty CGhostBusterRay_properties[] = { + CEntityProperty(CEntityProperty::EPT_ENTITYPTR, NULL, (0x000001f9<<8)+1, _offsetof(CGhostBusterRay, m_penOwner), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_BOOL, NULL, (0x000001f9<<8)+2, _offsetof(CGhostBusterRay, m_bRender), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_FLOAT3D, NULL, (0x000001f9<<8)+3, _offsetof(CGhostBusterRay, m_vSrcOld), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_FLOAT3D, NULL, (0x000001f9<<8)+4, _offsetof(CGhostBusterRay, m_vDstOld), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_FLOAT3D, NULL, (0x000001f9<<8)+5, _offsetof(CGhostBusterRay, m_vSrc), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_FLOAT3D, NULL, (0x000001f9<<8)+6, _offsetof(CGhostBusterRay, m_vDst), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_FLOAT3D, NULL, (0x000001f9<<8)+10, _offsetof(CGhostBusterRay, m_iLastBulletPosition), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_ANIMOBJECT, NULL, (0x000001f9<<8)+11, _offsetof(CGhostBusterRay, m_aoLightAnim), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_INDEX, NULL, (0x000001f9<<8)+12, _offsetof(CGhostBusterRay, m_ctPasses), "", 0, 0, 0), + CEntityProperty(CEntityProperty::EPT_ENTITYPTR, NULL, (0x000001f9<<8)+255, _offsetof(CGhostBusterRay, m_penPrediction), "", 0, 0, 0), +}; +#define CGhostBusterRay_propertiesct ARRAYCOUNT(CGhostBusterRay_properties) + +CEntityComponent CGhostBusterRay_components[] = { +#define CLASS_LIGHT ((0x000001f9<<8)+1) + CEntityComponent(ECT_CLASS, CLASS_LIGHT, "EFNM" "Classes\\Light.ecl"), +#define CLASS_BULLET ((0x000001f9<<8)+2) + CEntityComponent(ECT_CLASS, CLASS_BULLET, "EFNM" "Classes\\Bullet.ecl"), +#define MODEL_RAY ((0x000001f9<<8)+10) + CEntityComponent(ECT_MODEL, MODEL_RAY, "EFNM" "Models\\Weapons\\GhostBuster\\Projectile\\Ray.mdl"), +#define TEXTURE_RAY ((0x000001f9<<8)+11) + CEntityComponent(ECT_TEXTURE, TEXTURE_RAY, "EFNM" "Models\\Weapons\\GhostBuster\\Projectile\\Ray.tex"), +}; +#define CGhostBusterRay_componentsct ARRAYCOUNT(CGhostBusterRay_components) + +CEventHandlerEntry CGhostBusterRay_handlers[] = { + {1, -1, CEntity::pEventHandler(&CGhostBusterRay:: +#line 201 "/home/seb/git/Serious-Seb/Sources/Entities/GhostBusterRay.es" +Main),DEBUGSTRING("CGhostBusterRay::Main")}, +}; +#define CGhostBusterRay_handlersct ARRAYCOUNT(CGhostBusterRay_handlers) + +CEntity *CGhostBusterRay_New(void) { return new CGhostBusterRay; }; +void CGhostBusterRay_OnInitClass(void) {}; +void CGhostBusterRay_OnEndClass(void) {}; +void CGhostBusterRay_OnPrecache(CDLLEntityClass *pdec, INDEX iUser); +void CGhostBusterRay_OnWorldEnd(CWorld *pwo) {}; +void CGhostBusterRay_OnWorldInit(CWorld *pwo) {}; +void CGhostBusterRay_OnWorldTick(CWorld *pwo) {}; +void CGhostBusterRay_OnWorldRender(CWorld *pwo) {}; +ENTITY_CLASSDEFINITION(CGhostBusterRay, CMovableModelEntity, "GhostBusterRay", "", 0x000001f9); +DECLARE_CTFILENAME(_fnmCGhostBusterRay_tbn, ""); diff --git a/Sources/Entities/Gizmo.es b/Sources/Entities/Gizmo.es new file mode 100644 index 0000000..b985db7 --- /dev/null +++ b/Sources/Entities/Gizmo.es @@ -0,0 +1,341 @@ +335 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Gizmo/Gizmo.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/BasicEffects"; + +%{ +// info structure +static EntityInfo eiGizmo = { + EIBT_FLESH, 100.0f, + 0.0f, 1.3f, 0.0f, // source (eyes) + 0.0f, 1.0f, 0.0f, // target (body) +}; + +#define EXPLODE_GIZMO 2.5f +%} + +class CGizmo: CEnemyBase { +name "Gizmo"; +thumbnail "Thumbnails\\Gizmo.tbn"; + +properties: + // class internal + 1 BOOL m_bExploded = FALSE, + +components: + 1 class CLASS_BASE "Classes\\EnemyBase.ecl", + 2 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + 3 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +// ************** DATA ************** + 10 model MODEL_GIZMO "Models\\Enemies\\Gizmo\\Gizmo.mdl", + 20 texture TEXTURE_GIZMO "Models\\Enemies\\Gizmo\\Gizmo.tex", + + 50 sound SOUND_IDLE "Models\\Enemies\\Gizmo\\Sounds\\Idle.wav", + 51 sound SOUND_JUMP "Models\\Enemies\\Gizmo\\Sounds\\Jump.wav", + 52 sound SOUND_DEATH_JUMP "Models\\Enemies\\Gizmo\\Sounds\\JumpDeath.wav", + 53 sound SOUND_SIGHT "Models\\Enemies\\Gizmo\\Sounds\\Sight.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("%s ate a marsh hopper"), (const char*)strPlayerName); + return str; + } + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Gizmo.txt"); + return fnm; + }; + /* Entity info */ + void *GetEntityInfo(void) + { + return &eiGizmo; + }; + + void Precache(void) + { + CEnemyBase::Precache(); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_IDLE); + PrecacheSound(SOUND_JUMP); + PrecacheSound(SOUND_DEATH_JUMP); + PrecacheClass(CLASS_BASIC_EFFECT, BET_GIZMO_SPLASH_FX); + PrecacheClass(CLASS_BLOOD_SPRAY); + }; + + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + + void RunningAnim(void) + { + StartModelAnim(GIZMO_ANIM_RUN, 0); + }; + + void MortalJumpAnim(void) + { + StartModelAnim(GIZMO_ANIM_RUN, 0); + }; + + void StandAnim(void) + { + StartModelAnim(GIZMO_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + void BlowUpNotify(void) { + Explode(); + }; + + // explode only once + void Explode(void) + { + if (!m_bExploded) + { + m_bExploded = TRUE; + // spawn blood spray + CPlacement3D plSpray = GetPlacement(); + CEntity *penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 2.0f; + eSpawnSpray.fSizeMultiplier = 1.0f; + eSpawnSpray.sptType = SPT_SLIME; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/8.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); + + // spawn splash fx (sound) + CPlacement3D plSplash = GetPlacement(); + CEntityPointer penSplash = CreateEntity(plSplash, CLASS_BASIC_EFFECT); + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_GIZMO_SPLASH_FX; + penSplash->Initialize(ese); + } + }; + + + // gizmo should always blow up + BOOL ShouldBlowUp(void) + { + return TRUE; + } + + + // leave stain + virtual void LeaveStain(BOOL bGrow) + { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + + // on plane + if( GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) + { + // if near to polygon and away from last stain point + if( (vPoint-GetPlacement().pl_PositionVector).Length()<0.5f ) + { + FLOAT fStretch = box.Size().Length(); + // stain + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_GIZMOSTAIN; + ese.vStretch = FLOAT3D( fStretch*0.75f, fStretch*0.75f, 1.0f); + ese.vNormal = FLOAT3D( vPlaneNormal); + ese.vDirection = FLOAT3D( 0, 0, 0); + FLOAT3D vPos = vPoint+ese.vNormal/50.0f*(FRnd()+0.5f); + CEntityPointer penEffect = CreateEntity( CPlacement3D(vPos, ANGLE3D(0,0,0)), CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + } + }; + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + // close range -> move toward enemy and try to jump onto it + PerformAttack(EVoid) : CEnemyBase::PerformAttack + { + while (TRUE) + { + // ------------ Exit close attack if out of range or enemy is dead + // if attacking is futile + if (ShouldCeaseAttack()) + { + SetTargetNone(); + return EReturn(); + } + + // stop moving + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + + // ------------ Wait for some time on the ground + FLOAT fWaitTime = 0.25f+FRnd()*0.4f; + wait( fWaitTime) + { + on (EBegin) : { resume; }; + on (ESound) : { resume; } // ignore all sounds + on (EWatch) : { resume; } // ignore watch + on (ETimer) : { stop; } // timer tick expire + } + + autocall JumpOnce() EReturn; + } + } + + JumpOnce(EVoid) + { + // ------------ Jump either in slightly randomized direction or mortal, streight and fast toward enemy + // we are always going for enemy + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + m_fMoveFrequency = 0.1f; + // if we are close enough for mortal jump + if( CalcPlaneDist(m_penEnemy) < 10.0f) + { + // set mortal jump parameters (no random) + m_fMoveSpeed = m_fCloseRunSpeed*1.5f; + m_aRotateSpeed = m_aCloseRotateSpeed*0.5f; + FLOAT fSpeedX = 0.0f; + FLOAT fSpeedY = 10.0f; + FLOAT fSpeedZ = -m_fMoveSpeed; + // if can't see enemy + if( !IsInFrustum(m_penEnemy, CosFast(30.0f))) + { + // rotate a lot + m_aRotateSpeed = m_aCloseRotateSpeed*1.5f; + // but don't jump too much + fSpeedY /= 2.0f; + fSpeedZ /= 4.0f; + PlaySound(m_soSound, SOUND_JUMP, SOF_3D); + } + else + { + PlaySound(m_soSound, SOUND_DEATH_JUMP, SOF_3D); + } + FLOAT3D vTranslation(fSpeedX, fSpeedY, fSpeedZ); + SetDesiredTranslation(vTranslation); + MortalJumpAnim(); + } + // start slightly randomized jump + else + { + m_fMoveSpeed = m_fCloseRunSpeed; + m_aRotateSpeed = m_aCloseRotateSpeed; + // set random jump parameters + FLOAT fSpeedX = (FRnd()-0.5f)*10.0f; + FLOAT fSpeedY = FRnd()*5.0f+5.0f; + FLOAT fSpeedZ = -m_fMoveSpeed-FRnd()*2.5f; + FLOAT3D vTranslation(fSpeedX, fSpeedY, fSpeedZ); + SetDesiredTranslation(vTranslation); + RunningAnim(); + PlaySound(m_soSound, SOUND_JUMP, SOF_3D); + } + + // ------------ While in air, adjust directions, on touch start new jump or explode + while (TRUE) + { + // adjust direction and speed + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = m_aCloseRotateSpeed; + FLOAT3D vTranslation = GetDesiredTranslation(); + SetDesiredMovement(); + SetDesiredTranslation(vTranslation); + + wait(m_fMoveFrequency) + { + on (EBegin) : { resume; }; + on (ESound) : { resume; } // ignore all sounds + on (EWatch) : { resume; } // ignore watch + on (ETimer) : { stop; } // timer tick expire + on (ETouch etouch) : + { + // if we touched ground + if( etouch.penOther->GetRenderType() & RT_BRUSH) + { + return EReturn(); + } + // we touched player, explode + else if ( IsDerivedFromClass( etouch.penOther, "Player")) + { + InflictDirectDamage(etouch.penOther, this, DMT_IMPACT, 10.0f, + GetPlacement().pl_PositionVector, -en_vGravityDir); + SetHealth(-10000.0f); + m_vDamage = FLOAT3D(0,10000,0); + SendEvent(EDeath()); + } + // we didn't touch ground nor player, ignore + resume; + } + } + } + }; + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(9.5f); + m_fMaxHealth = 9.5f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 2000.0f; + m_fBlowUpSize = 2.0f; + + // set your appearance + SetModel(MODEL_GIZMO); + SetModelMainTexture(TEXTURE_GIZMO); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd()*5.0f + 15.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + m_fCloseRunSpeed = FRnd()*5.0f + 15.0f; + m_aCloseRotateSpeed = AngleDeg(360.0f); + // setup attack distances + m_fAttackDistance = 400.0f; + m_fCloseDistance = 250.0f; + m_fStopDistance = 0.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 0.5f; + m_fIgnoreRange = 500.0f; + // damage/explode properties + m_fBlowUpAmount = 0.0f; + m_fBodyParts = 0; + m_fDamageWounded = 0.0f; + m_iScore = 500; + m_sptType = SPT_SLIME; + + en_fDeceleration = 150.0f; + + // set stretch factors for height and width + GetModelObject()->StretchModel(FLOAT3D(1.25f, 1.25f, 1.25f)); + ModelChangeNotify(); + StandingAnim(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Global.es b/Sources/Entities/Global.es new file mode 100644 index 0000000..3b016c7 --- /dev/null +++ b/Sources/Entities/Global.es @@ -0,0 +1,155 @@ +0 +%{ +#include "Entities/StdH/StdH.h" +%} + +/* + * + * --->>> DON'T INSTANTIATE THIS CLASS <<<--- + * + */ + +event EStop { // stop your actions +}; +event EStart { // start your actions + CEntityPointer penCaused, // who caused the trigger (transitive) +}; +event EActivate { // activate class (usually touch field) +}; +event EDeactivate { // deactivate class (usually touch field) +}; +event EEnvironmentStart { // activate environment classes +}; +event EEnvironmentStop { // deactivate environment classes +}; +event EEnd { // general purpose end of procedure event +}; +event ETrigger { // sent by trigger class + CEntityPointer penCaused, // who caused the trigger (transitive) +}; +event ETeleportMovingBrush { // teleport moving brush +}; +event EReminder { // reminder event + INDEX iValue, // value for return +}; +event EStartAttack { // OBSOLETE! +}; +event EStopAttack { // OBSOLETE! +}; +event EStopBlindness { // make enemy not blind any more +}; +event EStopDeafness { // make enemy not blind any more +}; +event EReceiveScore { // sent to player when enemy is killed + INDEX iPoints +}; +event EKilledEnemy { // sent to player when enemy is killed +}; +event ESecretFound { // sent to player secret is found +}; + +enum BoolEType { + 0 BET_TRUE "True", // true + 1 BET_FALSE "False", // false + 2 BET_IGNORE "Ignore", // ignore +}; + +enum EventEType { + 0 EET_START "Start event", // start event + 1 EET_STOP "Stop event", // stop event + 2 EET_TRIGGER "Trigger event", // trigger event + 3 EET_IGNORE "Don't send event", // don't send event (ignore) + 4 EET_ACTIVATE "Activate event", // activate event + 5 EET_DEACTIVATE "Deactivate event", // deactivate event + 6 EET_ENVIRONMENTSTART "Start environment event", // start environment event + 7 EET_ENVIRONMENTSTOP "Stop environment event", // stop environment event + 8 EET_STARTATTACK "OBSOLETE! - Start attack event", // start attack enemy + 9 EET_STOPATTACK "OBSOLETE! - Stop attack event", // stop attack enemy + 10 EET_STOPBLINDNESS "Stop blindness event", // enemy stop being blind + 11 EET_STOPDEAFNESS "Stop deafness event", // enemy stop being deaf + 12 EET_TELEPORTMOVINGBRUSH "Teleport moving brush", // moving brush teleporting event +}; + + +// entity info structure enums +enum EntityInfoBodyType { + 1 EIBT_FLESH "Flesh", + 2 EIBT_WATER "Water", + 3 EIBT_ROCK "Rock ", + 4 EIBT_FIRE "Fire ", + 5 EIBT_AIR "Air ", + 6 EIBT_BONES "Bones", + 7 EIBT_WOOD "Wood ", + 8 EIBT_METAL "Metal", + 9 EIBT_ROBOT "Robot", + 10 EIBT_ICE "Ice", +}; + +enum MessageSound { + 0 MSS_NONE "None", // no sound + 1 MSS_INFO "Info", // just simple info +}; + +enum ParticleTexture { + 1 PT_STAR01 "Star01", + 2 PT_STAR02 "Star02", + 3 PT_STAR03 "Star03", + 4 PT_STAR04 "Star04", + 5 PT_STAR05 "Star05", + 6 PT_STAR06 "Star06", + 7 PT_STAR07 "Star07", + 8 PT_STAR08 "Star08", + 9 PT_BOUBBLE01 "Boubble01", + 10 PT_BOUBBLE02 "Boubble02", + 11 PT_WATER01 "Water01", + 12 PT_WATER02 "Water02", + 13 PT_SANDFLOW "Sand flow", + 14 PT_WATERFLOW "Water flow", + 15 PT_LAVAFLOW "Lava flow", +}; + +enum SoundType { + 0 SNDT_NONE "", // internal + 1 SNDT_SHOUT "", // enemy shout when see player + 2 SNDT_YELL "", // enemy is wounded (or death) + 3 SNDT_EXPLOSION "", // explosion of rocket or grenade (or similar) + 4 SNDT_PLAYER "", // sound from player weapon or player is wounded +}; + +event ESound { + enum SoundType EsndtSound, + CEntityPointer penTarget, +}; + +// event for printing centered message +event ECenterMessage { + CTString strMessage, // the message + TIME tmLength, // how long to keep it + enum MessageSound mssSound, // sound to play +}; + +// event for sending computer message to a player +event EComputerMessage { + CTFileName fnmMessage, // the message file +}; + +// event for voice message to a player +event EVoiceMessage { + CTFileName fnmMessage, // the message file +}; + +event EHitBySpaceShipBeam { +}; + +class CGlobal : CEntity { +name ""; +thumbnail ""; + +properties: +components: +functions: +procedures: + Main(EVoid) { + ASSERTALWAYS("DON'T INSTANTIATE THIS CLASS"); + } +}; \ No newline at end of file diff --git a/Sources/Entities/GradientMarker.es b/Sources/Entities/GradientMarker.es new file mode 100644 index 0000000..7c6a88e --- /dev/null +++ b/Sources/Entities/GradientMarker.es @@ -0,0 +1,93 @@ +230 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; +uses "Entities/WorldBase"; + +class CGradientMarker: CMarker { +name "Gradient Marker"; +thumbnail "Thumbnails\\GradientMarker.tbn"; +features "IsImportant"; + +properties: + 1 FLOAT m_fHeight "Height" 'H' = -10.0f, + 2 BOOL m_bDarkLight "Dark light" 'D' = TRUE, + 3 COLOR m_colColor0 "Color 0" 'C' = (C_GRAY|CT_OPAQUE), + 4 COLOR m_colColor1 "Color 1" 'A' = (C_WHITE|CT_OPAQUE), + +components: + 1 model MODEL_MARKER "Models\\Editor\\GradientMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\GradientMarker.tex" + +functions: + + /* Get gradient type name, return empty string if not used. */ + const CTString &GetGradientName(void) + { + return m_strName; + } + /* Get gradient. */ + BOOL GetGradient(INDEX iGradient, class CGradientParameters &gpGradient) + { + const FLOATmatrix3D &m = GetRotationMatrix(); + gpGradient.gp_vGradientDir(1) = m(1,2); + gpGradient.gp_vGradientDir(2) = m(2,2); + gpGradient.gp_vGradientDir(3) = m(3,2); + FLOAT fPos = gpGradient.gp_vGradientDir%GetPlacement().pl_PositionVector; + gpGradient.gp_bDark = m_bDarkLight; + if( m_fHeight>=0 && m_fHeight<+0.001f) { m_fHeight = +0.001f; } + if( m_fHeight<=0 && m_fHeight>-0.001f) { m_fHeight = -0.001f; } + gpGradient.gp_fH0 = fPos; + gpGradient.gp_fH1 = fPos+m_fHeight; + gpGradient.gp_col0 = m_colColor0; + gpGradient.gp_col1 = m_colColor1; + return TRUE; + } + + void UncacheShadowsForGradient(void) + { + // for all entities in world + FOREACHINDYNAMICCONTAINER(GetWorld()->wo_cenEntities, CEntity, iten) { + // if it is world base entity + if( IsOfClass(&*iten, "WorldBase")) { + // uncache shadows for gradient + ((CWorldBase *)&*iten)->UncacheShadowsForGradient(this); + } + } + } + + void SetPlacement_internal(const CPlacement3D &plNew, const FLOATmatrix3D &mRotation, BOOL bNear) + { + CEntity::SetPlacement_internal(plNew, mRotation, bNear); + UncacheShadowsForGradient(); + } + + void OnEnd(void) + { + UncacheShadowsForGradient(); + CEntity::OnEnd(); + } + +procedures: + + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set name + if( m_strName=="Marker") { + m_strName = "Gradient marker"; + } + + UncacheShadowsForGradient(); + return; + } +}; diff --git a/Sources/Entities/GravityMarker.es b/Sources/Entities/GravityMarker.es new file mode 100644 index 0000000..5a57be0 --- /dev/null +++ b/Sources/Entities/GravityMarker.es @@ -0,0 +1,162 @@ +212 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; +uses "Entities/GravityRouter"; + +enum GravityType { + 0 LT_PARALLEL "Parallel", + 1 LT_CENTRAL "Central", + 2 LT_CYLINDRICAL "Cylindirical", + 3 LT_TORUS "Torus", +}; + +class CGravityMarker: CMarker { +name "Gravity Marker"; +thumbnail "Thumbnails\\GravityMarker.tbn"; +features "IsImportant"; + +properties: + 1 enum GravityType m_gtType "Type" 'Y' =LT_PARALLEL, + 2 FLOAT m_fStrength "Strength" 'S' = 1, + 3 RANGE m_rFallOff "FallOff" 'F' = 50, + 4 RANGE m_rHotSpot "HotSpot" 'H' = 50, + 5 RANGE m_rTorusR "Torus Radius" 'R' = 100, + + 10 FLOAT m_fAcc = 0, + 11 FLOAT m_fSign = 1, + 12 FLOAT m_fStep = 0, + + 20 ANGLE3D m_aForceDir "Forcefield Direction" 'F' = ANGLE3D(0,0,0), + 21 FLOAT m_fForceA "Forcefield Acceleration" = 0.0f, + 22 FLOAT m_fForceV "Forcefield Velocity" = 0.0f, + 23 FLOAT3D m_vForceDir = FLOAT3D(1,0,0), + +components: + 1 model MODEL_MARKER "Models\\Editor\\GravityMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\GravityMarker.tex" + +functions: + // find strength at given distance + inline FLOAT StrengthAtDistance(FLOAT fDistance) + { + FLOAT fStrength = (m_rFallOff-fDistance)*m_fStep; + return Clamp(fStrength, 0.0f, m_fAcc); + } + + /* Get force type name, return empty string if not used. */ + const CTString &GetForceName(INDEX i) + { + return m_strName; + } + /* Get force in given point. */ + void GetForce(INDEX i, const FLOAT3D &vPoint, + CForceStrength &fsGravity, CForceStrength &fsField) + { + const FLOATmatrix3D &m = GetRotationMatrix(); + switch (m_gtType) { + case LT_PARALLEL: { + fsGravity.fs_vDirection(1) = -m(1,2) * m_fSign; + fsGravity.fs_vDirection(2) = -m(2,2) * m_fSign; + fsGravity.fs_vDirection(3) = -m(3,2) * m_fSign; + FLOAT fDistance = (vPoint-GetPlacement().pl_PositionVector)%fsGravity.fs_vDirection; + fsGravity.fs_fAcceleration = StrengthAtDistance(fDistance); + fsGravity.fs_fVelocity = 70; + } break; + case LT_CENTRAL: { + fsGravity.fs_vDirection = (GetPlacement().pl_PositionVector-vPoint)*m_fSign; + FLOAT fDistance = fsGravity.fs_vDirection.Length(); + if (fDistance>0.01f) { + fsGravity.fs_vDirection/=fDistance; + } + fsGravity.fs_fAcceleration = StrengthAtDistance(fDistance); + fsGravity.fs_fVelocity = 70; + } break; + case LT_CYLINDRICAL: { + FLOAT3D vDelta = GetPlacement().pl_PositionVector-vPoint; + FLOAT3D vAxis; + vAxis(1) = m(1,2); + vAxis(2) = m(2,2); + vAxis(3) = m(3,2); + GetNormalComponent(vDelta, vAxis, fsGravity.fs_vDirection); + fsGravity.fs_vDirection*=m_fSign; + FLOAT fDistance = fsGravity.fs_vDirection.Length(); + if (fDistance>0.01f) { + fsGravity.fs_vDirection/=fDistance; + } + fsGravity.fs_fAcceleration = StrengthAtDistance(fDistance); + fsGravity.fs_fVelocity = 70; + } break; + case LT_TORUS: { + // get referent point + FLOAT3D vDelta = vPoint-GetPlacement().pl_PositionVector; + FLOAT3D vAxis; + vAxis(1) = m(1,2); + vAxis(2) = m(2,2); + vAxis(3) = m(3,2); + FLOAT3D vR; + GetNormalComponent(vDelta, vAxis, vR); + vR.Normalize(); + fsGravity.fs_vDirection = (vDelta-vR*m_rTorusR)*m_fSign; + FLOAT fDistance = fsGravity.fs_vDirection.Length(); + if (fDistance>0.01f) { + fsGravity.fs_vDirection/=fDistance; + } + fsGravity.fs_fAcceleration = StrengthAtDistance(fDistance); + fsGravity.fs_fVelocity = 70; + + } break; + default: + fsGravity.fs_fAcceleration = m_fAcc; + fsGravity.fs_fVelocity = 70; + fsGravity.fs_vDirection = FLOAT3D(0,-1,0); + } + + // calculate forcefield influence + fsField.fs_fAcceleration = m_fForceA; + fsField.fs_fVelocity = m_fForceV; + fsField.fs_vDirection = m_vForceDir; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if( ee.ee_slEvent==EVENTCODE_ETrigger) + { + EChangeGravity eChangeGravity; + eChangeGravity.penNewGravity = this; + m_penTarget->SendEvent( eChangeGravity); + return TRUE; + } + return FALSE; + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set name + if (m_strName=="Marker") { + m_strName = "Gravity Marker"; + } + + // precalc fast gravity parameters + m_fAcc = Abs(30*m_fStrength), + m_fSign = SgnNZ(m_fStrength), + m_fStep = m_fAcc/(m_rFallOff-m_rHotSpot); + + AnglesToDirectionVector(m_aForceDir, m_vForceDir); + + return; + } +}; + diff --git a/Sources/Entities/GravityRouter.es b/Sources/Entities/GravityRouter.es new file mode 100644 index 0000000..34e785a --- /dev/null +++ b/Sources/Entities/GravityRouter.es @@ -0,0 +1,83 @@ +227 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +event EChangeGravity { + CEntityPointer penNewGravity, +}; + +class CGravityRouter: CMarker { +name "Gravity Router"; +thumbnail "Thumbnails\\GravityRouter.tbn"; +features "IsImportant"; + +properties: + +components: + 1 model MODEL_MARKER "Models\\Editor\\GravityRouter.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\GravityRouter.tex" + +functions: + + /* Get force type name, return empty string if not used. */ + const CTString &GetForceName(INDEX i) + { + return m_strName; + } + + /* Get force in given point. */ + void GetForce(INDEX i, const FLOAT3D &vPoint, + CForceStrength &fsGravity, CForceStrength &fsField) + { + if( (m_penTarget != NULL) && (IsOfClass( m_penTarget, "Gravity Marker"))) + { + m_penTarget->GetForce(i, vPoint, fsGravity, fsField); + } + } + /* Get entity that controls the force, used for change notification checking. */ + CEntity *GetForceController(INDEX iForce) + { + return this; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if( ((EChangeGravity &) ee).ee_slEvent==EVENTCODE_EChangeGravity) + { + m_penTarget = ((EChangeGravity &) ee).penNewGravity; + // notify engine that gravity defined by this entity has changed + NotifyGravityChanged(); + return TRUE; + } + return FALSE; + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set name + if (m_strName=="Marker") { + m_strName = "Gravity Router"; + } + + if( m_penTarget!=NULL && !IsOfClass( m_penTarget, "Gravity Marker")) { + WarningMessage( "Entity '%s' is not of Gravity Marker class!", (const char*)m_penTarget->GetName()); + m_penTarget = NULL; + } + + return; + } +}; + diff --git a/Sources/Entities/HazeMarker.es b/Sources/Entities/HazeMarker.es new file mode 100644 index 0000000..23edcdb --- /dev/null +++ b/Sources/Entities/HazeMarker.es @@ -0,0 +1,126 @@ +216 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; +uses "Entities/FogMarker"; + + +class CHazeMarker: CMarker { +name "Haze Marker"; +thumbnail "Thumbnails\\HazeMarker.tbn"; +features "IsImportant"; + +properties: + 10 enum FogAttenuationType m_faType "Attenuation Type" 'A' =FA_EXP, + 11 FLOAT m_fDensity "Density" 'D' = 0.1f, + 12 FLOAT m_fNear "Near" = 100.0f, + 13 FLOAT m_fFar "Far" = 1000.0f, + 14 BOOL m_bVisibleFromOutside "Visible from outside" = FALSE, + + 22 INDEX m_iSize "Size" = 32, + 23 COLOR m_colBase "Base Color" 'C' = (C_WHITE|CT_OPAQUE), + 24 COLOR m_colUp "Color (up)" = (C_BLACK|CT_TRANSPARENT), + 25 COLOR m_colDown "Color (down)" = (C_BLACK|CT_TRANSPARENT), + 26 COLOR m_colNorth "Color (north)" = (C_BLACK|CT_TRANSPARENT), + 27 COLOR m_colSouth "Color (south)" = (C_BLACK|CT_TRANSPARENT), + 28 COLOR m_colEast "Color (east)" = (C_BLACK|CT_TRANSPARENT), + 29 COLOR m_colWest "Color (west)" = (C_BLACK|CT_TRANSPARENT), + +components: + 1 model MODEL_MARKER "Models\\Editor\\Haze.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Haze.tex" + +functions: + + /* Get haze type name, return empty string if not used. */ + const CTString &GetHazeName(void) + { + return m_strName; + } + + /* Get haze. */ + void GetHaze(class CHazeParameters &hpHaze, FLOAT3D &vViewDir) + { + // calculate directional haze color + COLOR colDir=C_BLACK, colMul; + FLOAT fR=0.0f, fG=0.0f, fB=0.0f, fA=0.0f; + FLOAT fSum = 255.0f / (Abs(vViewDir(1))+Abs(vViewDir(2))+Abs(vViewDir(3))); + + if( vViewDir(1) < 0.0f) { + colMul = (COLOR)(-vViewDir(1)*fSum); + colMul = (colMul< 0.0f) { + colMul = (COLOR)(+vViewDir(1)*fSum); + colMul = (colMul< 0.0f) { + colMul = (COLOR)(+vViewDir(2)*fSum); + colMul = (colMul< 0.0f) { + colMul = (COLOR)(+vViewDir(3)*fSum); + colMul = (colMul<=0 && m_fNeares_strName+=" Firecracker"; } break; + case HDT_ROCKETMAN: { pes->es_strName+=" Rocketman"; } break; + case HDT_BOMBERMAN: { pes->es_strName+=" Bomberman"; } break; + case HDT_KAMIKAZE: { pes->es_strName+=" Kamikaze"; } break; + } + return TRUE; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // firecracker and rocketman can't harm headman + if (!IsOfClass(penInflictor, "Headman") || + !(((CHeadman*)penInflictor)->m_hdtType==HDT_FIRECRACKER || + ((CHeadman*)penInflictor)->m_hdtType==HDT_ROCKETMAN)) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + if (IRnd()%2) { + iAnim = HEADMAN_ANIM_WOUND1; + } else { + iAnim = HEADMAN_ANIM_WOUND2; + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + FLOAT3D vFront; + GetHeadingDirection(0, vFront); + FLOAT fDamageDir = m_vDamage%vFront; + if (fDamageDir<0) { + if (Abs(fDamageDir)<10.0f) { + iAnim = HEADMAN_ANIM_DEATH_EASY_FALL_BACK; + } else { + iAnim = HEADMAN_ANIM_DEATH_FALL_BACK; + } + } else { + if (Abs(fDamageDir)<10.0f) { + iAnim = HEADMAN_ANIM_DEATH_EASY_FALL_FORWARD; + } else { + iAnim = HEADMAN_ANIM_DEATH_FALL_ON_KNEES; + } + } + + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // should this enemy blow up (spawn debris) + BOOL ShouldBlowUp(void) + { + if (m_hdtType==HDT_KAMIKAZE && GetHealth()<=0) { + return TRUE; + } else { + return CEnemyBase::ShouldBlowUp(); + } + } + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(HEADMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(HEADMAN_ANIM_IDLE_PATROL, AOF_LOOPING|AOF_NORESTART); + if (m_hdtType==HDT_KAMIKAZE) { + KamikazeSoundOff(); + } + }; + void StandingAnimFight(void) + { + StartModelAnim(HEADMAN_ANIM_IDLE_FIGHT, AOF_LOOPING|AOF_NORESTART); + if (m_hdtType==HDT_KAMIKAZE) { + KamikazeSoundOff(); + } + } + void WalkingAnim(void) { + StartModelAnim(HEADMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { + if (m_hdtType==HDT_KAMIKAZE) { + KamikazeSoundOn(); + StartModelAnim(HEADMAN_ANIM_KAMIKAZE_ATTACK, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(HEADMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + } + }; + void RotatingAnim(void) { + RunningAnim(); + }; + + // virtual sound functions + void IdleSound(void) { + if (m_bAttackSound) { + return; + } + if (m_hdtType==HDT_KAMIKAZE) { + PlaySound(m_soSound, SOUND_IDLEKAMIKAZE, SOF_3D); + } else { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + } + }; + void SightSound(void) { + if (m_bAttackSound) { + return; + } + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + if (m_bAttackSound) { + return; + } + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + if (m_bAttackSound) { + return; + } + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + void KamikazeSoundOn(void) { + if (!m_bAttackSound) { + m_bAttackSound = TRUE; + PlaySound(m_soSound, SOUND_ATTACKKAMIKAZE, SOF_3D|SOF_LOOP); + } + } + void KamikazeSoundOff(void) { + if (m_bAttackSound) { + m_soSound.Stop(); + m_bAttackSound = FALSE; + } + } + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + void BlowUpNotify(void) { + // kamikaze and bomberman explode if is not already exploded + if (m_hdtType==HDT_KAMIKAZE || m_hdtType==HDT_BOMBERMAN) { + Explode(); + } + }; + + // spawn body parts + /*void BlowUp(void) + { + if( m_hdtType==HDT_FIRECRACKER || m_hdtType==HDT_ROCKETMAN) + { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + + vNormalizedDamage *= 0.75f; + + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + + // spawn debris + Debris_Begin(EIBT_FLESH, DPT_BLOODTRAIL, BET_BLOODSTAIN, fEntitySize, vNormalizedDamage, vBodySpeed, 5.0f, 2.0f); + + INDEX iTextureID = TEXTURE_ROCKETMAN; + if( m_hdtType==HDT_FIRECRACKER) + { + iTextureID = TEXTURE_FIRECRACKER; + } + + Debris_Spawn(this, this, MODEL_HEADMAN_BODY, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_HEADMAN_HAND, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_HEADMAN_HAND, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_HEADMAN_LEGS, iTextureID, 0, 0, 0, 0, 0.0f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + } + else + { + CEnemyBase::BlowUp(); + } + };*/ + + // bomberman and kamikaze explode only once + void Explode(void) { + if (!m_bExploded) { + m_bExploded = TRUE; + + // inflict damage + FLOAT3D vSource; + GetEntityInfoPosition(this, eiHeadman.vTargetCenter, vSource); + if (m_hdtType==HDT_BOMBERMAN) { + InflictDirectDamage(this, this, DMT_EXPLOSION, 100.0f, vSource, + -en_vGravityDir); + InflictRangeDamage(this, DMT_EXPLOSION, 15.0f, vSource, 1.0f, 6.0f); + } else { + InflictDirectDamage(this, this, DMT_CLOSERANGE, 100.0f, vSource, + -en_vGravityDir); + InflictRangeDamage(this, DMT_EXPLOSION, 30.0f, vSource, 2.75f, 8.0f); + } + + // spawn explosion + CPlacement3D plExplosion = GetPlacement(); + CEntityPointer penExplosion = CreateEntity(plExplosion, CLASS_BASIC_EFFECT); + ESpawnEffect eSpawnEffect; + eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE; + eSpawnEffect.betType = BET_BOMB; + eSpawnEffect.vStretch = FLOAT3D(1.0f,1.0f,1.0f); + penExplosion->Initialize(eSpawnEffect); + } + }; + +// ****** +// overrides from CEnemyBase to provide exploding on close range + + // set speeds for movement towards desired position + void SetSpeedsToDesiredPosition(const FLOAT3D &vPosDelta, FLOAT fPosDistance, BOOL bGoingToPlayer) + { + // if very close to player + if (m_hdtType==HDT_KAMIKAZE && CalcDist(m_penEnemy) < EXPLODE_KAMIKAZE) { + // explode + SetHealth(-10000.0f); + m_vDamage = FLOAT3D(0,10000,0); + SendEvent(EDeath()); + + // if not close + } else { + // behave as usual + CEnemyBase::SetSpeedsToDesiredPosition(vPosDelta, fPosDistance, bGoingToPlayer); + } + } + + // get movement frequency for attack + virtual FLOAT GetAttackMoveFrequency(FLOAT fEnemyDistance) + { + // kamikaze must have sharp reflexes when close + if (m_hdtType==HDT_KAMIKAZE && fEnemyDistance < m_fCloseDistance) { + return 0.1f; + } else { + return CEnemyBase::GetAttackMoveFrequency(fEnemyDistance); + } + } + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + InitializeAttack(EVoid) : CEnemyBase::InitializeAttack { + if (m_hdtType==HDT_KAMIKAZE) { + KamikazeSoundOn(); + } + jump CEnemyBase::InitializeAttack(); + }; + + StopAttack(EVoid) : CEnemyBase::StopAttack { + KamikazeSoundOff(); + jump CEnemyBase::StopAttack(); + }; + + Fire(EVoid) : CEnemyBase::Fire { + // firecracker + if (m_hdtType == HDT_FIRECRACKER) { + autocall FirecrackerAttack() EEnd; + // rocketman + } else if (m_hdtType == HDT_ROCKETMAN) { + autocall RocketmanAttack() EEnd; + // bomber + } else if (m_hdtType == HDT_BOMBERMAN) { + autocall BombermanAttack() EEnd; + // kamikaze + } else if (m_hdtType == HDT_KAMIKAZE) { + } + + return EReturn(); + }; + + // Bomberman attack + BombermanAttack(EVoid) { + // don't shoot if enemy above or below you too much + if ( !IsInFrustum(m_penEnemy, CosFast(80.0f)) ) { + return EEnd(); + } + + autowait(0.2f + FRnd()/4); + + StartModelAnim(HEADMAN_ANIM_BOMBERMAN_ATTACK, 0); + PlaySound(m_soSound, SOUND_FIREBOMBERMAN, SOF_3D); + autowait(0.15f); + + AddAttachment(HEADMAN_ATTACHMENT_BOMB_RIGHT_HAND, MODEL_BOMB, TEXTURE_BOMB); + autowait(0.30f); + RemoveAttachment(HEADMAN_ATTACHMENT_BOMB_RIGHT_HAND); + + // hit bomb + // calculate launch velocity and heading correction for angular launch + FLOAT fLaunchSpeed; + FLOAT fRelativeHdg; + CalculateAngularLaunchParams( + GetPlacement().pl_PositionVector, BOMBERMAN_LAUNCH(2)-1.5f, + m_penEnemy->GetPlacement().pl_PositionVector, FLOAT3D(0,0,0), + BOMBERMAN_ANGLE, + fLaunchSpeed, + fRelativeHdg); + + // target enemy body + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + // launch + CPlacement3D pl; + PrepareFreeFlyingProjectile(pl, vShootTarget, BOMBERMAN_LAUNCH, ANGLE3D(0, BOMBERMAN_ANGLE, 0)); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_HEADMAN_BOMBERMAN; + eLaunch.fSpeed = fLaunchSpeed; + penProjectile->Initialize(eLaunch); + + // safety remove - if hitted (EWounded) while have bomb in his hand, bomb will never be removed + RemoveAttachment(HEADMAN_ATTACHMENT_BOMB_RIGHT_HAND); + + autowait(0.45f + FRnd()/2); + return EEnd(); + }; + + // Firecraker attack + FirecrackerAttack(EVoid) { + // don't shoot if enemy above you more than quare of two far from you + if (-en_vGravityDir%CalcDelta(m_penEnemy) > CalcDist(m_penEnemy)/1.41421f) { + return EEnd(); + } + + autowait(0.2f + FRnd()/4); + + StartModelAnim(HEADMAN_ANIM_FIRECRACKER_ATTACK, 0); + autowait(0.15f); + PlaySound(m_soSound, SOUND_FIREFIRECRACKER, SOF_3D); + autowait(0.52f); + ShootProjectile(PRT_HEADMAN_FIRECRACKER, FLOAT3D(0.0f, 0.5f, 0.0f), ANGLE3D(-16.0f, 0, 0)); + + autowait(0.05f); + ShootProjectile(PRT_HEADMAN_FIRECRACKER, FLOAT3D(0.0f, 0.5f, 0.0f), ANGLE3D(-8, 0, 0)); + + autowait(0.05f); + ShootProjectile(PRT_HEADMAN_FIRECRACKER, FLOAT3D(0.0f, 0.5f, 0.0f), ANGLE3D(0.0f, 0, 0)); + + autowait(0.05f); + ShootProjectile(PRT_HEADMAN_FIRECRACKER, FLOAT3D(0.0f, 0.5f, 0.0f), ANGLE3D(8.0f, 0, 0)); + + autowait(0.05f); + ShootProjectile(PRT_HEADMAN_FIRECRACKER, FLOAT3D(0.0f, 0.5f, 0.0f), ANGLE3D(16.0f, 0, 0)); + + autowait(0.5f + FRnd()/3); + return EEnd(); + }; + + // Rocketman attack + RocketmanAttack(EVoid) { + StandingAnimFight(); //StartModelAnim(_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + autowait(0.2f + FRnd()/4); + + StartModelAnim(HEADMAN_ANIM_ROCKETMAN_ATTACK, 0); + ShootProjectile(PRT_HEADMAN_ROCKETMAN, FLOAT3D(0.0f, 1.0f, 0.0f), ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIREROCKETMAN, SOF_3D); + + autowait(1.0f + FRnd()/3); + return EEnd(); + }; + + + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + ASSERT(m_hdtType!=HDT_KAMIKAZE); + // death + autocall CEnemyBase::Death() EEnd; + // bomberman explode + if (m_hdtType==HDT_BOMBERMAN) { + Explode(); + } + return EEnd(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(19.5f); + m_fMaxHealth = 19.5f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 2000.0f; + m_fBlowUpSize = 2.0f; + + // set your appearance + SetModel(MODEL_HEADMAN); + switch (m_hdtType) { + case HDT_FIRECRACKER: + // set your texture + SetModelMainTexture(TEXTURE_FIRECRACKER); + AddAttachment(HEADMAN_ATTACHMENT_HEAD, MODEL_FIRECRACKERHEAD, TEXTURE_FIRECRACKERHEAD); + AddAttachment(HEADMAN_ATTACHMENT_CHAINSAW, MODEL_CHAINSAW, TEXTURE_CHAINSAW); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd() + 5.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd() + 5.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 8.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 65.0f; + m_fBodyParts = 4; + m_fDamageWounded = 0.0f; + m_iScore = 200; + break; + + case HDT_ROCKETMAN: + // set your texture + SetModelMainTexture(TEXTURE_ROCKETMAN); + AddAttachment(HEADMAN_ATTACHMENT_HEAD, MODEL_HEAD, TEXTURE_HEAD); + AddAttachment(HEADMAN_ATTACHMENT_ROCKET_LAUNCHER, MODEL_ROCKETLAUNCHER, TEXTURE_ROCKETLAUNCHER); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd()*2.0f + 6.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 6.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 8.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 65.0f; + m_fBodyParts = 4; + m_fDamageWounded = 0.0f; + m_iScore = 100; + break; + + case HDT_BOMBERMAN: + // set your texture + SetModelMainTexture(TEXTURE_BOMBERMAN); + AddAttachment(HEADMAN_ATTACHMENT_HEAD, MODEL_HEAD, TEXTURE_HEAD); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd() + 4.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd() + 4.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 45.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 20.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.5f; + m_fIgnoreRange = 150.0f; + // damage/explode properties + m_fBlowUpAmount = 65.0f; + m_fBodyParts = 4; + m_fDamageWounded = 0.0f; + m_iScore = 500; + break; + + case HDT_KAMIKAZE: + // set your texture + SetModelMainTexture(TEXTURE_KAMIKAZE); + AddAttachment(HEADMAN_ATTACHMENT_BOMB_RIGHT_HAND, MODEL_BOMB, TEXTURE_BOMB); + AddAttachment(HEADMAN_ATTACHMENT_BOMB_LEFT_HAND, MODEL_BOMB, TEXTURE_BOMB); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd()*2.0f + 10.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 10.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 600.0f); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 10.0f; + m_fStopDistance = 0.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 0.5f; + m_fIgnoreRange = 250.0f; + // damage/explode properties + m_fBlowUpAmount = 0.0f; + m_fBodyParts = 4; + m_fDamageWounded = 0.0f; + m_iScore = 2500; + break; + } + + // set stretch factors for height and width + GetModelObject()->StretchModel(FLOAT3D(1.25f, 1.25f, 1.25f)); + ModelChangeNotify(); + StandingAnim(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/HealthItem.es b/Sources/Entities/HealthItem.es new file mode 100644 index 0000000..71bd4aa --- /dev/null +++ b/Sources/Entities/HealthItem.es @@ -0,0 +1,263 @@ +801 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +%} + +uses "Entities/Item"; + +// health type +enum HealthItemType { + 0 HIT_PILL "Pill", // pill health + 1 HIT_SMALL "Small", // small health + 2 HIT_MEDIUM "Medium", // medium health + 3 HIT_LARGE "Large", // large health + 4 HIT_SUPER "Super", // super health +}; + +// event for sending through receive item +event EHealth { + FLOAT fHealth, // health to receive + BOOL bOverTopHealth, // can be received over top health +}; + +class CHealthItem : CItem { +name "Health Item"; +thumbnail "Thumbnails\\HealthItem.tbn"; + +properties: + 1 enum HealthItemType m_EhitType "Type" 'Y' = HIT_SMALL, // health type + 2 BOOL m_bOverTopHealth = FALSE, // can be received over top health + 3 INDEX m_iSoundComponent = 0, + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + +// ********* PILL HEALTH ********* + 1 model MODEL_PILL "Models\\Items\\Health\\Pill\\Pill.mdl", + 2 texture TEXTURE_PILL "Models\\Items\\Health\\Pill\\Pill.tex", + 3 texture TEXTURE_PILL_BUMP "Models\\Items\\Health\\Pill\\PillBump.tex", + +// ********* SMALL HEALTH ********* + 10 model MODEL_SMALL "Models\\Items\\Health\\Small\\Small.mdl", + 11 texture TEXTURE_SMALL "Models\\Items\\Health\\Small\\Small.tex", + +// ********* MEDIUM HEALTH ********* + 20 model MODEL_MEDIUM "Models\\Items\\Health\\Medium\\Medium.mdl", + 21 texture TEXTURE_MEDIUM "Models\\Items\\Health\\Medium\\Medium.tex", + +// ********* LARGE HEALTH ********* + 30 model MODEL_LARGE "Models\\Items\\Health\\Large\\Large.mdl", + 31 texture TEXTURE_LARGE "Models\\Items\\Health\\Large\\Large.tex", + +// ********* SUPER HEALTH ********* + 40 model MODEL_SUPER "Models\\Items\\Health\\Super\\Super.mdl", + 41 texture TEXTURE_SUPER "Models\\Items\\Health\\Super\\Super.tex", + +// ********* MISC ********* + 50 texture TEXTURE_SPECULAR_STRONG "Models\\SpecularTextures\\Strong.tex", + 51 texture TEXTURE_SPECULAR_MEDIUM "Models\\SpecularTextures\\Medium.tex", + 52 texture TEXTURE_REFLECTION_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", + 53 texture TEXTURE_REFLECTION_GOLD01 "Models\\ReflectionTextures\\Gold01.tex", + 54 texture TEXTURE_REFLECTION_PUPLE01 "Models\\ReflectionTextures\\Purple01.tex", + 55 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", + 56 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", + +// ************** SOUNDS ************** +301 sound SOUND_PILL "Sounds\\Items\\HealthPill.wav", +302 sound SOUND_SMALL "Sounds\\Items\\HealthSmall.wav", +303 sound SOUND_MEDIUM "Sounds\\Items\\HealthMedium.wav", +304 sound SOUND_LARGE "Sounds\\Items\\HealthLarge.wav", +305 sound SOUND_SUPER "Sounds\\Items\\HealthSuper.wav", + +functions: + void Precache(void) { + switch (m_EhitType) { + case HIT_PILL: PrecacheSound(SOUND_PILL ); break; + case HIT_SMALL: PrecacheSound(SOUND_SMALL ); break; + case HIT_MEDIUM: PrecacheSound(SOUND_MEDIUM); break; + case HIT_LARGE: PrecacheSound(SOUND_LARGE ); break; + case HIT_SUPER: PrecacheSound(SOUND_SUPER ); break; + } + } + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = "Health"; + pes->es_ctCount = 1; + pes->es_ctAmmount = m_fValue; + pes->es_fValue = m_fValue; + pes->es_iScore = 0;//m_iScore; + + switch (m_EhitType) { + case HIT_PILL: pes->es_strName+=" pill"; break; + case HIT_SMALL: pes->es_strName+=" small"; break; + case HIT_MEDIUM:pes->es_strName+=" medium"; break; + case HIT_LARGE: pes->es_strName+=" large"; break; + case HIT_SUPER: pes->es_strName+=" super"; break; + } + + return TRUE; + } + + // render particles + void RenderParticles(void) { + // no particles when not existing or in DM modes + if (GetRenderType()!=CEntity::RT_MODEL || GetSP()->sp_gmGameMode>CSessionProperties::GM_COOPERATIVE + || !ShowItemParticles()) + { + return; + } + switch (m_EhitType) { + case HIT_PILL: + Particles_Stardust(this, 0.9f*0.75f, 0.70f*0.75f, PT_STAR08, 32); + break; + case HIT_SMALL: + Particles_Stardust(this, 1.0f*0.75f, 0.75f*0.75f, PT_STAR08, 128); + break; + case HIT_MEDIUM: + Particles_Stardust(this, 1.0f*0.75f, 0.75f*0.75f, PT_STAR08, 128); + break; + case HIT_LARGE: + Particles_Stardust(this, 2.0f*0.75f, 1.0f*0.75f, PT_STAR08, 192); + break; + case HIT_SUPER: + Particles_Stardust(this, 2.3f*0.75f, 1.5f*0.75f, PT_STAR08, 320); + break; + } + } + + // set health properties depending on health type + void SetProperties(void) { + switch (m_EhitType) { + case HIT_PILL: + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_SMALL); + m_fValue = 1.0f; + m_bOverTopHealth = TRUE; + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Pill - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_PILL, TEXTURE_PILL, 0, TEXTURE_SPECULAR_STRONG, TEXTURE_PILL_BUMP); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + m_iSoundComponent = SOUND_PILL; + break; + case HIT_SMALL: + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 10.0f; + m_bOverTopHealth = FALSE; + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Small - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_SMALL, TEXTURE_SMALL, TEXTURE_REFLECTION_LIGHTMETAL01, TEXTURE_SPECULAR_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.4f,0), FLOAT3D(2,2,0.4f) ); + StretchItem(FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + m_iSoundComponent = SOUND_SMALL; + break; // add flare + + case HIT_MEDIUM: + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 25.0f; + m_bOverTopHealth = FALSE; + m_fRespawnTime = 25.0f; + m_strDescription.PrintF("Medium - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_MEDIUM, TEXTURE_MEDIUM, TEXTURE_REFLECTION_LIGHTMETAL01, TEXTURE_SPECULAR_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(2.5f,2.5f,0.5f) ); + StretchItem(FLOAT3D(1.5f*0.75f, 1.5f*0.75f, 1.5f*0.75)); + m_iSoundComponent = SOUND_MEDIUM; + break; + case HIT_LARGE: + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 50.0f; + m_bOverTopHealth = FALSE; + m_fRespawnTime = 60.0f; + m_strDescription.PrintF("Large - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_LARGE, TEXTURE_LARGE, TEXTURE_REFLECTION_GOLD01, TEXTURE_SPECULAR_STRONG, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.8f,0), FLOAT3D(2.8f,2.8f,1.0f) ); + StretchItem(FLOAT3D(1.2f*0.75f, 1.2f*0.75f, 1.2f*0.75)); + m_iSoundComponent = SOUND_LARGE; + break; + case HIT_SUPER: + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_MEDIUM); + m_fValue = 100.0f; + m_bOverTopHealth = TRUE; + m_fRespawnTime = 120.0f; + m_strDescription.PrintF("Super - H:%g T:%g", m_fValue, m_fRespawnTime); + // set appearance + AddItem(MODEL_SUPER, TEXTURE_SUPER, 0, TEXTURE_SPECULAR_MEDIUM, 0); + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,1.0f,0), FLOAT3D(3,3,1.0f) ); + StretchItem(FLOAT3D(1.0f*0.75f, 1.0f*0.75f, 1.0f*0.75)); + CModelObject &mo = GetModelObject()->GetAttachmentModel(ITEMHOLDER_ATTACHMENT_ITEM)->amo_moModelObject; + mo.PlayAnim(0, AOF_LOOPING); + + m_iSoundComponent = SOUND_SUPER; + break; + } + }; + + void AdjustDifficulty(void) + { + if (!GetSP()->sp_bAllowHealth && m_penTarget==NULL) { + Destroy(); + } + } +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected { + ASSERT(epass.penOther!=NULL); + + // if health stays + if (GetSP()->sp_bHealthArmorStays && !m_bPickupOnce) { + // if already picked by this player + BOOL bWasPicked = MarkPickedBy(epass.penOther); + if (bWasPicked) { + // don't pick again + return; + } + } + + // send health to entity + EHealth eHealth; + eHealth.fHealth = m_fValue; + eHealth.bOverTopHealth = m_bOverTopHealth; + + // if health is received + if (epass.penOther->ReceiveItem(eHealth)) { + + if(_pNetwork->IsPlayerLocal(epass.penOther)) + { + switch (m_EhitType) + { + case HIT_PILL: IFeel_PlayEffect("PU_HealthPill"); break; + case HIT_SMALL: IFeel_PlayEffect("PU_HealthSmall"); break; + case HIT_MEDIUM:IFeel_PlayEffect("PU_HealthMedium"); break; + case HIT_LARGE: IFeel_PlayEffect("PU_HealthLarge"); break; + case HIT_SUPER: IFeel_PlayEffect("PU_HealthSuper"); break; + } + } + + // play the pickup sound + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soPick, m_iSoundComponent, SOF_3D); + m_fPickSoundLen = GetSoundLength(m_iSoundComponent); + if (!GetSP()->sp_bHealthArmorStays || m_bPickupOnce) { + jump CItem::ItemReceived(); + } + } + return; + }; + + Main() { + Initialize(); // initialize base class + SetProperties(); // set properties + + jump CItem::ItemLoop(); + }; +}; diff --git a/Sources/Entities/Huanman.es b/Sources/Entities/Huanman.es new file mode 100644 index 0000000..559aa79 --- /dev/null +++ b/Sources/Entities/Huanman.es @@ -0,0 +1,180 @@ +325 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/HuanMan/Huanman.h" +%} + +uses "Entities/EnemyBase"; + +%{ +// info structure +static EntityInfo eiHuanman = { + EIBT_FLESH, 125.0f, + 0.0f, 2.1f, 0.0f, + 0.0f, 1.1f, 0.0f, +}; + +#define CLOSE_HIT 2.0f +#define FIRE FLOAT3D( 0.45f, 2.0f, -1.25f) +%} + + +class CHuanman : CEnemyBase { +name "Huanman"; +thumbnail "Thumbnails\\Huanman.tbn"; + +properties: +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + + 10 model MODEL_HUANMAN "Models\\Enemies\\Huanman\\Huanman.mdl", + 11 texture TEXTURE_HUANMAN "Models\\Enemies\\Huanman\\Huanman.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Huanman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Huanman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Huanman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Huanman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Huanman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Huanman\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiHuanman; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // huanman can't harm huanman + if (!IsOfClass(penInflictor, "Huanman")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + StartModelAnim(HUANMAN_ANIM_WOUND, 0); + return HUANMAN_ANIM_WOUND; + }; + + // death + INDEX AnimForDeath(void) { + StartModelAnim(HUANMAN_ANIM_DEATH, 0); + return HUANMAN_ANIM_DEATH; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(HUANMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(HUANMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { + StartModelAnim(HUANMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { + StartModelAnim(HUANMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + StartModelAnim(HUANMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire { + // fire projectile + StartModelAnim(HUANMAN_ANIM_ATTACK, 0); + autowait(0.4f); + ShootProjectile(PRT_HUANMAN_FIRE, FIRE, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.6f); + StandingAnim(); + autowait(FRnd()/2 + _pTimer->TickQuantum); + + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + // attack with spear + StartModelAnim(HUANMAN_ANIM_ATTACK, 0); + autowait(0.4f); + if (CalcDist(m_penEnemy) < CLOSE_HIT) { + // damage enemy + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 7.5f, FLOAT3D(0, 0, 0), vDirection); + } + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + autowait(0.6f); + StandingAnim(); + autowait(FRnd()/2 + _pTimer->TickQuantum); + + return EReturn(); + }; + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(100.0f); + m_fMaxHealth = 100.0f; + en_fDensity = 1100.0f; + + // set your appearance + SetModel(MODEL_HUANMAN); + SetModelMainTexture(TEXTURE_HUANMAN); + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd() + 3.0f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*20.0f + 50.0f); + m_fAttackRunSpeed = FRnd() + 5.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 600.0f); + m_fCloseRunSpeed = FRnd() + 5.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 600.0f); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 2.0f; + m_fStopDistance = 1.7f; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 3.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 80.0f; + m_fBodyParts = 4; + m_fDamageWounded = 20.0f; + m_iScore = 500; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Item.es b/Sources/Entities/Item.es new file mode 100644 index 0000000..fe88424 --- /dev/null +++ b/Sources/Entities/Item.es @@ -0,0 +1,279 @@ +800 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +%} + +%{ +// used to render certain entities only for certain players (like picked items, etc.) +extern ULONG _ulPlayerRenderingMask; +%} + +class export CItem : CMovableModelEntity { +name "Item"; +thumbnail ""; +features "HasName", "HasDescription", "IsTargetable", "CanBePredictable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Item", + 2 CTString m_strDescription = "", + + // class properties + 5 FLOAT m_fValue = 0.0f, // value + 6 FLOAT m_fRespawnTime = 0.0f, // respawn time + 7 BOOL m_bRespawn "Respawn" 'R' = FALSE, // respawn item + 8 CEntityPointer m_penTarget "Target" 'T' COLOR(C_dGRAY|0xFF), // target to trigger when crossed over + 9 BOOL m_bPickupOnce "PickupOnce" 'P' = FALSE, // can be picked by only one player, triggers only when really picked + 10 CSoundObject m_soPick, // sound channel + 12 FLOAT m_fPickSoundLen = 0.0f, + 14 BOOL m_bDropped = FALSE, // dropped by a player during a deathmatch game + 15 INDEX m_ulPickedMask = 0, // mask for which players picked this item + +components: + 1 model MODEL_ITEM "Models\\Items\\ItemHolder\\ItemHolder.mdl", + +functions: + virtual void AdjustDifficulty(void) + { + } + + /* Adjust model mip factor if needed. */ + void AdjustMipFactor(FLOAT &fMipFactor) + { + // adjust flare glow, to decrease power with how you get closer + CAttachmentModelObject *pamo = GetModelObject()->GetAttachmentModel(ITEMHOLDER_ATTACHMENT_FLARE); + if( pamo != NULL) + { + FLOAT fRatio = (Clamp( fMipFactor, 5.0f, 7.0f)-5.0f)/2.0f; + UBYTE ubRatio = UBYTE(255*fRatio); + COLOR colMutiply = RGBToColor(ubRatio,ubRatio,ubRatio)|CT_OPAQUE; + pamo->amo_moModelObject.mo_colBlendColor = colMutiply; + } + + // if never picked + if (m_ulPickedMask==0) { + // don't bother testing + return; + } + + BOOL bFlare = TRUE; + // if current player has already picked this item + if (_ulPlayerRenderingMask&m_ulPickedMask) { + // if picked items are not rendered + extern INDEX plr_bRenderPicked; + if (!plr_bRenderPicked) { + // kill mip factor + fMipFactor = UpperLimit(0.0f); + } + // if picked item particles are not rendered + extern INDEX plr_bRenderPickedParticles; + if (!plr_bRenderPickedParticles) { + // kill flare + bFlare = FALSE; + } + } + + // implement flare on/off ? + } + + // check whether should render particles for this item + BOOL ShowItemParticles(void) + { + // if current player has already picked this item + if (_ulPlayerRenderingMask&m_ulPickedMask) { + // if picked item particles are not rendered + extern INDEX plr_bRenderPickedParticles; + if (!plr_bRenderPickedParticles) { + // don't render + return FALSE; + } + } + // otherwise, render + return TRUE; + } + + // check if given player already picked this item, and mark if not + BOOL MarkPickedBy(CEntity *pen) + { + if (!IsOfClass(pen, "Player")) { + return FALSE; + } + INDEX iPlayer = ((CPlayerEntity*)pen)->GetMyPlayerIndex(); + BOOL bPickedAlready = (1<GetAttachmentModel(ITEMHOLDER_ATTACHMENT_ITEM)->amo_moModelObject; + AddAttachmentToModel(this, mo, iAttachment, ulIDModel, ulIDTexture, + ulIDReflectionTexture, ulIDSpecularTexture, ulIDBumpTexture); + }; + // set animation of attachment + void SetItemAttachmentAnim(INDEX iAttachment, INDEX iAnim) + { + CModelObject &mo = + GetModelObject()->GetAttachmentModel(ITEMHOLDER_ATTACHMENT_ITEM)->amo_moModelObject. + GetAttachmentModel(iAttachment)->amo_moModelObject; + mo.PlayAnim(iAnim, 0); + } + + // Add flare + void AddFlare(ULONG ulIDModel, ULONG ulIDTexture, + const FLOAT3D &vPos, const FLOAT3D &vStretch) + { + // add flare to items if not respawn + if( !m_bRespawn && !m_bDropped) + { + AddAttachmentToModel(this, *GetModelObject(), + ITEMHOLDER_ATTACHMENT_FLARE, ulIDModel, ulIDTexture, 0,0,0); + CAttachmentModelObject &amo = *GetModelObject()->GetAttachmentModel(ITEMHOLDER_ATTACHMENT_FLARE); + amo.amo_moModelObject.StretchModel(vStretch); + amo.amo_plRelative.pl_PositionVector = vPos; + } + }; + + // Stretch item + void StretchItem(const FLOAT3D &vStretch) { + CModelObject &mo = GetModelObject()->GetAttachmentModel(ITEMHOLDER_ATTACHMENT_ITEM)->amo_moModelObject; + mo.StretchModel(vStretch); + ModelChangeNotify(); + }; + +procedures: +/************************************************************ + * VIRTUAL PROCEDURES THAT NEED OVERRIDE * + ************************************************************/ + ItemCollected(EPass epass) { return; }; + + + +/************************************************************ + * I T E M L O O P * + ************************************************************/ + ItemLoop(EVoid) { + autowait(0.1f); + + SetPredictable(TRUE); + AdjustDifficulty(); + + wait() { + on (EBegin) : { resume; } + on (EPass epass) : { + if (!IsOfClass(epass.penOther, "Player")) { + pass; + } + if (!m_bPickupOnce) { + SendToTarget(m_penTarget, EET_TRIGGER, epass.penOther); + m_penTarget = NULL; + } + call ItemCollected(epass); + } + on (EEnd) : { stop; } + } + // wait for sound to end + autowait(m_fPickSoundLen+0.5f); + // cease to exist + Destroy(); + return; + }; + + ItemReceived(EVoid) { + // hide yourself + SwitchToEditorModel(); + if (m_bPickupOnce) { + SendToTarget(m_penTarget, EET_TRIGGER, NULL); + } + + // respawn item + if (m_bRespawn) { + ASSERT(m_fRespawnTime>0.0f); + + // wait to respawn + wait(m_fRespawnTime) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + otherwise() : { resume; } + } + // show yourself + SwitchToModel(); + + // cease to exist + } else { + return EEnd(); + } + return; + }; +}; + diff --git a/Sources/Entities/KeyItem.es b/Sources/Entities/KeyItem.es new file mode 100644 index 0000000..5269cc4 --- /dev/null +++ b/Sources/Entities/KeyItem.es @@ -0,0 +1,350 @@ +805 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +%} + +uses "Entities/Item"; + +// key type +enum KeyItemType { + 0 KIT_ANKHWOOD "Wooden ankh", + 1 KIT_ANKHROCK "Stone ankh", + 2 KIT_ANKHGOLD "Gold ankh", + 3 KIT_AMONGOLD "Gold amon", + 4 KIT_ANKHGOLDDUMMY "Gold ankh dummy key", + 5 KIT_ELEMENTEARTH "Element - Earth", + 6 KIT_ELEMENTWATER "Element - Water", + 7 KIT_ELEMENTAIR "Element - Air", + 8 KIT_ELEMENTFIRE "Element - Fire", + 9 KIT_RAKEY "Ra Key", + 10 KIT_MOONKEY "Moon Key", + 12 KIT_EYEOFRA "Eye of Ra", + 13 KIT_SCARAB "Scarab", + 14 KIT_COBRA "Cobra", + 15 KIT_SCARABDUMMY "Scarab dummy", + 16 KIT_HEART "Gold Heart", + 17 KIT_FEATHER "Feather of Truth", + 18 KIT_SPHINX1 "Sphinx 1", + 19 KIT_SPHINX2 "Sphinx 2", +}; + +// event for sending through receive item +event EKey { + enum KeyItemType kitType, +}; + +%{ + +const char *GetKeyName(enum KeyItemType kit) +{ + switch(kit) { + case KIT_ANKHWOOD : return TRANS("Wooden ankh"); break; + case KIT_ANKHROCK: return TRANS("Stone ankh"); break; + case KIT_ANKHGOLD : + case KIT_ANKHGOLDDUMMY : return TRANS("Gold ankh"); break; + case KIT_AMONGOLD : return TRANS("Gold Amon statue"); break; + case KIT_ELEMENTEARTH : return TRANS("Earth element"); break; + case KIT_ELEMENTWATER : return TRANS("Water element"); break; + case KIT_ELEMENTAIR : return TRANS("Air element"); break; + case KIT_ELEMENTFIRE : return TRANS("Fire element"); break; + case KIT_RAKEY : return TRANS("Ra key"); break; + case KIT_MOONKEY : return TRANS("Moon key"); break; + case KIT_EYEOFRA : return TRANS("Eye of Ra"); break; + case KIT_SCARAB : + case KIT_SCARABDUMMY : return TRANS("Scarab"); break; + case KIT_COBRA : return TRANS("Cobra"); break; + case KIT_HEART : return TRANS("Gold Heart"); break; + case KIT_FEATHER : return TRANS("Feather of Truth"); break; + case KIT_SPHINX1 : + case KIT_SPHINX2 : return TRANS("Gold Sphinx"); break; + default: return TRANS("unknown item"); break; + }; +} + +%} + +class CKeyItem : CItem { +name "KeyItem"; +thumbnail "Thumbnails\\KeyItem.tbn"; +features "IsImportant"; + +properties: + 1 enum KeyItemType m_kitType "Type" 'Y' = KIT_ANKHWOOD, // key type + 3 INDEX m_iSoundComponent = 0, + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + +// ********* ANKH KEY ********* + 1 model MODEL_ANKHWOOD "Models\\Items\\Keys\\AnkhWood\\Ankh.mdl", + 2 texture TEXTURE_ANKHWOOD "Models\\Ages\\Egypt\\Vehicles\\BigBoat\\OldWood.tex", + + 3 model MODEL_ANKHROCK "Models\\Items\\Keys\\AnkhStone\\Ankh.mdl", + 4 texture TEXTURE_ANKHROCK "Models\\Items\\Keys\\AnkhStone\\Stone.tex", + + 5 model MODEL_ANKHGOLD "Models\\Items\\Keys\\AnkhGold\\Ankh.mdl", + 6 texture TEXTURE_ANKHGOLD "Models\\Items\\Keys\\AnkhGold\\Ankh.tex", + + 7 model MODEL_AMONGOLD "Models\\Ages\\Egypt\\Gods\\Amon\\AmonGold.mdl", + 8 texture TEXTURE_AMONGOLD "Models\\Ages\\Egypt\\Gods\\Amon\\AmonGold.tex", + + 10 model MODEL_ELEMENTAIR "Models\\Items\\Keys\\Elements\\Air.mdl", + 11 texture TEXTURE_ELEMENTAIR "Models\\Items\\Keys\\Elements\\Air.tex", + + 20 model MODEL_ELEMENTWATER "Models\\Items\\Keys\\Elements\\Water.mdl", + 21 texture TEXTURE_ELEMENTWATER "Models\\Items\\Keys\\Elements\\Water.tex", + + 30 model MODEL_ELEMENTFIRE "Models\\Items\\Keys\\Elements\\Fire.mdl", + 31 texture TEXTURE_ELEMENTFIRE "Models\\Items\\Keys\\Elements\\Fire.tex", + + 40 model MODEL_ELEMENTEARTH "Models\\Items\\Keys\\Elements\\Earth.mdl", + 41 texture TEXTURE_ELEMENTEARTH "Models\\Items\\Keys\\Elements\\Texture.tex", + + 50 model MODEL_RAKEY "Models\\Items\\Keys\\RaKey\\Key.mdl", + 51 texture TEXTURE_RAKEY "Models\\Items\\Keys\\RaKey\\Key.tex", + + 60 model MODEL_MOONKEY "Models\\Items\\Keys\\RaSign\\Sign.mdl", + 61 texture TEXTURE_MOONKEY "Models\\Items\\Keys\\RaSign\\Sign.tex", + + 70 model MODEL_EYEOFRA "Models\\Items\\Keys\\EyeOfRa\\EyeOfRa.mdl", + 71 texture TEXTURE_EYEOFRA "Models\\Items\\Keys\\EyeOfRa\\EyeOfRa.tex", + + 80 model MODEL_SCARAB "Models\\Items\\Keys\\Scarab\\Scarab.mdl", + 81 texture TEXTURE_SCARAB "Models\\Items\\Keys\\Scarab\\Scarab.tex", + + 90 model MODEL_COBRA "Models\\Items\\Keys\\Uaset\\Uaset.mdl", + 91 texture TEXTURE_COBRA "Models\\Items\\Keys\\Uaset\\Uaset.tex", + + 92 model MODEL_FEATHER "Models\\Items\\Keys\\Luxor\\FeatherOfTruth.mdl", + 93 texture TEXTURE_FEATHER "Models\\Items\\Keys\\Luxor\\FeatherOfTruth.tex", + 94 model MODEL_HEART "Models\\Items\\Keys\\Luxor\\GoldHeart.mdl", + 95 texture TEXTURE_HEART "Models\\Items\\Keys\\Luxor\\GoldHeart.tex", + + 96 model MODEL_SPHINXGOLD "Models\\Items\\Keys\\GoldSphinx\\GoldSphinx.mdl", + 97 texture TEXTURE_SPHINXGOLD "Models\\Items\\Keys\\GoldSphinx\\Sphinx.tex", + + // ********* MISC ********* +255 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", +256 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", +257 texture TEX_REFL_GOLD01 "Models\\ReflectionTextures\\Gold01.tex", +258 texture TEX_REFL_METAL01 "Models\\ReflectionTextures\\LightMetal01.tex", +259 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +260 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + +// ************** SOUNDS ************** +301 sound SOUND_KEY "Sounds\\Items\\Key.wav", + +functions: + void Precache(void) { + PrecacheSound(SOUND_KEY); + } + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = GetKeyName(m_kitType); + pes->es_ctCount = 1; + pes->es_ctAmmount = 1; + pes->es_fValue = 1; + pes->es_iScore = 0;//m_iScore; + return TRUE; + } + // render particles + void RenderParticles(void) { + // no particles when not existing + if (GetRenderType()!=CEntity::RT_MODEL) { + return; + } + switch (m_kitType) { + case KIT_ANKHWOOD: + case KIT_ANKHROCK: + case KIT_ANKHGOLD: + case KIT_ANKHGOLDDUMMY: + default: + Particles_Stardust(this, 0.9f, 0.70f, PT_STAR08, 32); + break; + case KIT_AMONGOLD: + Particles_Stardust(this, 1.6f, 1.00f, PT_STAR08, 32); + break; + } + } + + // set health properties depending on type + void SetProperties(void) { + m_fRespawnTime = 10.0f; + m_strDescription = GetKeyName(m_kitType); + + switch (m_kitType) { + case KIT_ANKHWOOD: + // set appearance + AddItem(MODEL_ANKHWOOD, TEXTURE_ANKHWOOD, 0, 0, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + case KIT_ANKHROCK: + // set appearance + AddItem(MODEL_ANKHROCK, TEXTURE_ANKHROCK, 0, 0, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + case KIT_ANKHGOLD: + case KIT_ANKHGOLDDUMMY: + // set appearance + AddItem(MODEL_ANKHGOLD, TEXTURE_ANKHGOLD, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_SPHINX1: + case KIT_SPHINX2: + // set appearance + AddItem(MODEL_SPHINXGOLD, TEXTURE_SPHINXGOLD, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(2.0f, 2.0f, 2.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_AMONGOLD: + // set appearance + AddItem(MODEL_AMONGOLD, TEXTURE_AMONGOLD, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.5f,0), FLOAT3D(2,2,0.3f) ); + StretchItem(FLOAT3D(2.0f, 2.0f, 2.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_ELEMENTEARTH: + // set appearance + AddItem(MODEL_ELEMENTEARTH, TEXTURE_ELEMENTEARTH, TEX_REFL_METAL01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_ELEMENTAIR: + // set appearance + AddItem(MODEL_ELEMENTAIR, TEXTURE_ELEMENTAIR, TEX_REFL_METAL01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_ELEMENTWATER: + // set appearance + AddItem(MODEL_ELEMENTWATER, TEXTURE_ELEMENTWATER, TEX_REFL_METAL01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_ELEMENTFIRE: + // set appearance + AddItem(MODEL_ELEMENTFIRE, TEXTURE_ELEMENTFIRE, TEX_REFL_METAL01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_RAKEY: + // set appearance + AddItem(MODEL_RAKEY, TEXTURE_RAKEY, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + case KIT_MOONKEY: + // set appearance + AddItem(MODEL_MOONKEY, TEXTURE_MOONKEY, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_EYEOFRA: + // set appearance + AddItem(MODEL_EYEOFRA, TEXTURE_EYEOFRA, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_SCARAB: + case KIT_SCARABDUMMY: + // set appearance + AddItem(MODEL_SCARAB, TEXTURE_SCARAB, TEX_REFL_METAL01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_COBRA: + // set appearance + AddItem(MODEL_COBRA, TEXTURE_COBRA, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + + case KIT_FEATHER: + // set appearance + AddItem(MODEL_FEATHER, TEXTURE_FEATHER, 0, 0, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + case KIT_HEART: + // set appearance + AddItem(MODEL_HEART, TEXTURE_HEART, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + break; + } + }; + +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected { + ASSERT(epass.penOther!=NULL); + + // send key to entity + EKey eKey; + eKey.kitType = m_kitType; + // if health is received + if (epass.penOther->ReceiveItem(eKey)) { + if(_pNetwork->IsPlayerLocal(epass.penOther)) {IFeel_PlayEffect("PU_Key");} + // play the pickup sound + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soPick, m_iSoundComponent, SOF_3D); + m_fPickSoundLen = GetSoundLength(m_iSoundComponent); + jump CItem::ItemReceived(); + } + return; + }; + + Main() { + Initialize(); // initialize base class + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_SMALL); + SetProperties(); // set properties + + jump CItem::ItemLoop(); + }; +}; diff --git a/Sources/Entities/LastFileID.txt b/Sources/Entities/LastFileID.txt new file mode 100644 index 0000000..7aa7161 --- /dev/null +++ b/Sources/Entities/LastFileID.txt @@ -0,0 +1,5 @@ +Last ES ID number: + +Enemies: 341 (CreateRider) +Tools: 232 (Counter) +Items: 807 (MessageItem) \ No newline at end of file diff --git a/Sources/Entities/Light.es b/Sources/Entities/Light.es new file mode 100644 index 0000000..0d57440 --- /dev/null +++ b/Sources/Entities/Light.es @@ -0,0 +1,454 @@ +200 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelDestruction"; +uses "Entities/AnimationChanger"; + +enum LightType { + 0 LT_POINT "Point light", + 1 LT_AMBIENT "Ambient light", + 2 LT_STRONG_AMBIENT "Strong ambient light", + 3 LT_DIRECTIONAL "Directional light", + 4 LT_STRONG_POINT "Strong point light", +}; + +enum LensFlareType { + 0 LFT_NONE "None", + 1 LFT_STANDARD "Standard", + 2 LFT_STANDARD_REFLECTIONS "Standard reflections", + 3 LFT_YELLOW_STAR_RED_RING "Yellow star with red ring", + 4 LFT_WHITE_GLOW_STAR_RED_RING "White glow star with red ring", + 5 LFT_WHITE_GLOW_STAR "White glow star", + 6 LFT_WHITE_STAR_RED_RING_STREAKS "White star with red ring and streaks", + 7 LFT_WHITE_STAR_RED_REFLECTIONS "White star with red reflections", + 8 LFT_BLUE_STAR_BLUE_REFLECTIONS "Blue star with blue reflections", + 9 LFT_PV_SPACE_SHIP_WINDOW_FLARE "Pyramid valley space ship window flare", + 10 LFT_WHITE_GLOW_STAR_RED_RING_FAR "Yellow star with red ring far", + 11 LFT_WHITE_GLOW_FAR "White glow far", + 12 LFT_WHITE_GLOW_STAR_NG "White glow star no glare", +}; + +%{ + +void CLight_OnInitClass(void) +{ + // init lens flares effects + InitLensFlares(); +} + +void CLight_OnEndClass(void) +{ + // close lens flares effects + CloseLensFlares(); +} + +%} + +class CLight : CEntity { +name "Light"; +thumbnail "Thumbnails\\Light.tbn"; +features "HasName", "HasDescription", "ImplementsOnInitClass", "ImplementsOnEndClass"; +properties: + 2 COLOR m_colColor "Color" 'C' =C_GRAY, + 9 COLOR m_colAmbient "Directional ambient" 'E' =C_BLACK, + 1 RANGE m_rFallOffRange "Fall-off" 'F' =8.0f features(EPROPF_HIDEINPERSPECTIVE), + 4 RANGE m_rHotSpotRange "Hot-spot" 'H' =0.0f features(EPROPF_HIDEINPERSPECTIVE), + 7 ILLUMINATIONTYPE m_itIllumination "Polygon illumination" 'I' =0, + 8 enum LightType m_ltType "Type" 'Y' =LT_POINT, + 10 CTString m_strDescription = "", + 11 CTString m_strName "Name" 'N' = "Light", + 12 BOOL m_bDarkLight "Dark light" 'A' = FALSE, + 13 FLOAT m_fNearClip "Clip near" = 0.1f, + 14 FLOAT m_fFarClip "Clip far" = 0.01f, + 15 BOOL m_bSubstractSectorAmbient "Substract sector ambient" 'S' = FALSE, + 16 BOOL m_bRenderAsSmallLight "Render as small" 'R' = FALSE, + 17 enum LensFlareType m_lftLensFlare "Lens flare" 'L' = LFT_NONE, + 18 BOOL m_bBackground "Background" 'B' = FALSE, + 19 BOOL m_bLensFlareOnly "Lens flare only" 'O' = FALSE, + 20 CTFileName m_fnmLightAnimation "Light animation file" = CTString(""), + 21 ANIMATION m_iLightAnimation "Light animation" = 0, + 25 FLOAT m_tmOffsetPhase "Light animation offset" = 0.0f, + 22 CAnimObject m_aoLightAnimation, + 24 BOOL m_bTargetable "Targetable" = FALSE, + 26 BOOL m_bDynamic "Dynamic" = FALSE, + 27 BOOL m_bDiffusion "Diffusion" 'D' = TRUE, + 30 CTFileName m_fnmAmbientLightAnimation "Ambient light animation file" = CTString(""), + 31 ANIMATION m_iAmbientLightAnimation "Ambient light animation" = 0, + 32 CAnimObject m_aoAmbientLightAnimation, +{ + CLightSource m_lsLightSource; + CBoolDefaultFalse m_bdfInitialized; // set if already initialized once +} +components: + 1 model MODEL_LIGHT_SOURCE "Models\\Editor\\LightSource.mdl", + 2 texture TEXTURE_POINT_LIGHT "Models\\Editor\\PointLight.tex", + 3 texture TEXTURE_AMBIENT_LIGHT "Models\\Editor\\AmbientLight.tex", + 4 texture TEXTURE_REAL_AMBIENT_LIGHT "Models\\Editor\\RealAmbientLight.tex", + 5 model MODEL_SPOT_LIGHT "Models\\Editor\\SpotLight.mdl", + 6 texture TEXTURE_SPOT_LIGHT "Models\\Editor\\SpotLight.tex", + +functions: + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + if (slPropertyOffset==offsetof(CLight, m_iLightAnimation)) + { + return m_aoLightAnimation.GetData(); + } + else if (slPropertyOffset==offsetof(CLight, m_iAmbientLightAnimation)) + { + return m_aoAmbientLightAnimation.GetData(); + } + else + { + return CEntity::GetAnimData(slPropertyOffset); + } + }; + + BOOL IsTargetable(void) const + { + return m_bTargetable; + } + + BOOL IsImportant(void) const + { + return(m_ltType==LT_DIRECTIONAL); + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + // when someone in range is destroyed + if (ee.ee_slEvent==EVENTCODE_ERangeModelDestruction) + { + // fade out completely + m_colColor = C_BLACK; + m_colAmbient = C_BLACK; + CLightSource lsNew; + SetupLightSource(lsNew); + m_lsLightSource.SetLightSource(lsNew); + return TRUE; + // when animation should be changed + } + else if (ee.ee_slEvent==EVENTCODE_EChangeAnim) + { + EChangeAnim &eChange = (EChangeAnim &)ee; + + // for diffuse component of light + m_iLightAnimation = eChange.iLightAnim; + if (m_aoLightAnimation.GetData()!=NULL) + { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, eChange.bLightLoop?AOF_LOOPING:0); + } + + // for ambient component of light + m_iAmbientLightAnimation = eChange.iAmbientLightAnim; + if (m_aoAmbientLightAnimation.GetData()!=NULL) + { + m_aoAmbientLightAnimation.PlayAnim(m_iAmbientLightAnimation, eChange.bAmbientLightLoop?AOF_LOOPING:0); + } + + // if neither ambient nor difuse animation is set, apply direct color change + if( (m_aoLightAnimation.GetData()==NULL) && (m_aoAmbientLightAnimation.GetData()==NULL) ) + { + m_colColor = eChange.colDiffuse; + m_colAmbient = eChange.colAmbient; + CLightSource lsNew; + SetupLightSource(lsNew); + m_lsLightSource.SetLightSource(lsNew); + return TRUE; + } + } + return FALSE; + } + + // apply mirror and stretch to the entity + void MirrorAndStretch(FLOAT fStretch, BOOL bMirrorX) + { + // stretch its ranges + m_rFallOffRange*=fStretch; + m_rHotSpotRange*=fStretch; + m_fNearClip *=fStretch; + m_fFarClip *=fStretch; + //(void)bMirrorX; // no mirror for lights + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + // if never initialized before (happens after loading) + if (!m_bdfInitialized.bdf_bValue) { + // initialize now + CLightSource lsNew; + SetupLightSource(lsNew); + m_lsLightSource.SetLightSourceWithNoDiscarding(lsNew); + m_bdfInitialized.bdf_bValue = TRUE; + } + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + // prepare and transfer light source variables + void SetupLightSource( CLightSource &lsNew) + { + switch( m_ltType) { + case LT_POINT: + case LT_STRONG_POINT: + lsNew.ls_ulFlags = LSF_CASTSHADOWS; + break; + case LT_DIRECTIONAL: + lsNew.ls_ulFlags = LSF_DIRECTIONAL|LSF_CASTSHADOWS; + break; + case LT_STRONG_AMBIENT: + case LT_AMBIENT: + lsNew.ls_ulFlags = 0; + break; + } + if( m_bSubstractSectorAmbient) { lsNew.ls_ulFlags |= LSF_SUBSTRACTSECTORAMBIENT; } + if( m_bLensFlareOnly) { lsNew.ls_ulFlags |= LSF_LENSFLAREONLY; } + if( m_bDynamic) { lsNew.ls_ulFlags |= LSF_DYNAMIC; } + // directional light cannot be dark + if( m_bDarkLight) { + if( m_ltType==LT_DIRECTIONAL) { + lsNew.ls_ulFlags &= ~LSF_DARKLIGHT; + m_bDarkLight = FALSE; + } else { + lsNew.ls_ulFlags |= LSF_DARKLIGHT; + } + } + // ambient and directional lights doesn't support diffusion + if( m_bDiffusion) { + if( m_bDynamic || m_ltType==LT_AMBIENT || m_ltType==LT_STRONG_AMBIENT) { + lsNew.ls_ulFlags &= ~LSF_DIFFUSION; + m_bDiffusion = FALSE; + } else { + lsNew.ls_ulFlags |= LSF_DIFFUSION; + } + } + + lsNew.ls_rHotSpot = m_rHotSpotRange; + lsNew.ls_rFallOff = m_rFallOffRange; + lsNew.ls_fNearClipDistance = m_fNearClip; + lsNew.ls_fFarClipDistance = m_fFarClip; + // hot spot for strong lights is 90% of light range + if( m_ltType == LT_STRONG_AMBIENT || m_ltType == LT_STRONG_POINT) { + lsNew.ls_rHotSpot = lsNew.ls_rFallOff*0.9f; + } + + lsNew.ls_colColor = m_colColor; + lsNew.ls_colAmbient = C_BLACK; // only directional lights are allowed to have ambient component + if( lsNew.ls_ulFlags&LSF_DIRECTIONAL) { lsNew.ls_colAmbient = m_colAmbient; } + lsNew.ls_ubPolygonalMask = (UBYTE) m_itIllumination; + + switch(m_lftLensFlare) + { + case LFT_NONE: + lsNew.ls_plftLensFlare = NULL; + break; + case LFT_STANDARD: + lsNew.ls_plftLensFlare = &_lftStandard; + break; + case LFT_STANDARD_REFLECTIONS: + lsNew.ls_plftLensFlare = &_lftStandardReflections; + break; + case LFT_YELLOW_STAR_RED_RING: + lsNew.ls_plftLensFlare = &_lftYellowStarRedRing; + break; + case LFT_WHITE_GLOW_STAR_RED_RING: + lsNew.ls_plftLensFlare = &_lftWhiteGlowStarRedRing; + break; + case LFT_WHITE_GLOW_STAR: + lsNew.ls_plftLensFlare = &_lftWhiteGlowStar; + break; + case LFT_WHITE_STAR_RED_RING_STREAKS: + lsNew.ls_plftLensFlare = &_lftWhiteStarRedRingStreaks; + break; + case LFT_WHITE_STAR_RED_REFLECTIONS: + lsNew.ls_plftLensFlare = &_lftWhiteStarRedReflections; + break; + case LFT_BLUE_STAR_BLUE_REFLECTIONS: + lsNew.ls_plftLensFlare = &_lftBlueStarBlueReflections; + break; + case LFT_PV_SPACE_SHIP_WINDOW_FLARE: + lsNew.ls_plftLensFlare = &_lftPVSpaceShipWindowFlare; + break; + case LFT_WHITE_GLOW_STAR_RED_RING_FAR: + lsNew.ls_plftLensFlare = &_lftYellowStarRedRingFar; + break; + case LFT_WHITE_GLOW_FAR: + lsNew.ls_plftLensFlare = &_lftWhiteGlowFar; + break; + case LFT_WHITE_GLOW_STAR_NG: + lsNew.ls_plftLensFlare = &_lftWhiteGlowStarNG; + break; + } + + // --------- Setup light animations + // diffuse + lsNew.ls_paoLightAnimation = NULL; + if (m_aoLightAnimation.GetData()!=NULL) { + lsNew.ls_paoLightAnimation = &m_aoLightAnimation; + } + + // ambient + lsNew.ls_paoAmbientLightAnimation = NULL; + if (m_aoAmbientLightAnimation.GetData()!=NULL) { + lsNew.ls_paoAmbientLightAnimation = &m_aoAmbientLightAnimation; + } + } + + +procedures: + Main() + { + // fall off and hot spot must be positive values + if (m_rFallOffRange<0) { + m_rFallOffRange = 0.0f; + } + if (m_rHotSpotRange<0) { + m_rHotSpotRange = 0.0f; + } + // hot spot must be less or equal falloff + if (m_rHotSpotRange>m_rFallOffRange) { + m_rHotSpotRange = m_rFallOffRange; + } + + // near clip must not be too small relatively to falloff + // (crashes on shadow rendering otherwise!) + //if (m_fNearClipmo_Stretch = FLOAT3D( 0.25f, 0.25f, 0.25f); + } + else + { + // set stretch factor of the light (directional lights don't have stretch) + if ( m_ltType != LT_DIRECTIONAL) { + const float LIGHT_MINSIZE=0.5f; + FLOAT fFactor = Log2(m_rFallOffRange)*LIGHT_MINSIZE; + if (fFactormo_Stretch = FLOAT3D( fFactor, fFactor, fFactor); + } + } + + CTString strType; + if( m_ltType == LT_POINT || m_ltType == LT_STRONG_POINT) + { + strType = "point"; + // set model to light source + SetModel(MODEL_LIGHT_SOURCE); + // set texture of point light model + SetModelMainTexture(TEXTURE_POINT_LIGHT); + } + // initialize ambient light + else if( m_ltType == LT_AMBIENT) + { + strType = "ambient"; + // set model to light source + SetModel(MODEL_LIGHT_SOURCE); + // set texture of ambient light model + SetModelMainTexture(TEXTURE_AMBIENT_LIGHT); + } + // initialize real ambient light + else if( m_ltType == LT_STRONG_AMBIENT) + { + strType = "ambient"; + // set model to light source + SetModel(MODEL_LIGHT_SOURCE); + // set texture of real ambient light model + SetModelMainTexture(TEXTURE_REAL_AMBIENT_LIGHT); + } + // initialize spot light + else if( m_ltType == LT_DIRECTIONAL) + { + strType = "directional"; + // set model to spot light + SetModel(MODEL_SPOT_LIGHT); + // set texture of spot light model + SetModelMainTexture(TEXTURE_SPOT_LIGHT); + } + + if( m_bDarkLight) + { + strType = strType+", dark"; + } + + // set diffuse light animation if available + try { + m_aoLightAnimation.SetData_t(m_fnmLightAnimation); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load '%s': %s"), (const char*)(CTString&)m_fnmLightAnimation,(const char*) strError); + m_fnmLightAnimation = ""; + } + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, AOF_LOOPING); + m_aoLightAnimation.OffsetPhase(m_tmOffsetPhase*m_aoLightAnimation.GetCurrentAnimLength()); + } + + // set ambient light animation if available + try { + m_aoAmbientLightAnimation.SetData_t(m_fnmAmbientLightAnimation); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load '%s': %s"), (const char*)(CTString&)m_fnmAmbientLightAnimation, (const char*) strError); + m_fnmAmbientLightAnimation = ""; + } + if (m_aoAmbientLightAnimation.GetData()!=NULL) { + m_aoAmbientLightAnimation.PlayAnim(m_iAmbientLightAnimation, AOF_LOOPING); + m_aoAmbientLightAnimation.OffsetPhase(m_tmOffsetPhase*m_aoAmbientLightAnimation.GetCurrentAnimLength()); + } + + // set a new light source with light properties + CLightSource lsNew; + SetupLightSource(lsNew); + + // setup background rendering flag + if (m_bBackground) { + SetFlags(GetFlags()|ENF_BACKGROUND); + } else { + SetFlags(GetFlags()&~ENF_BACKGROUND); + } + + // set up this light source from the new properties + m_lsLightSource.ls_penEntity = this; + if (!m_bdfInitialized.bdf_bValue) { + m_lsLightSource.SetLightSourceWithNoDiscarding(lsNew); + m_bdfInitialized.bdf_bValue = TRUE; + } else { + m_lsLightSource.SetLightSource(lsNew); + } + + m_strDescription.PrintF("%s:%g-%g", + (const char*)strType, m_rHotSpotRange, m_rFallOffRange); + + return; + }; +}; diff --git a/Sources/Entities/LightStyle.es b/Sources/Entities/LightStyle.es new file mode 100644 index 0000000..03b8041 --- /dev/null +++ b/Sources/Entities/LightStyle.es @@ -0,0 +1,33 @@ +201 +%{ +#include "Entities/StdH/StdH.h" +%} + +class CLightStyle : CEntity { +name "Light"; +thumbnail "Models\\Editor\\LightStyle.tbn"; +features "HasName", "IsTargetable"; + +properties: + 2 CTString m_strName "Name" 'N' = "", +// 1 LIGHTANIMATION m_iLightAnimation "Light animation" 'A' + +components: + 1 model MODEL_LIGHTSTYLE "Models\\Editor\\LightSource.mdl", + 2 texture TEXTURE_LIGHTSTYLE "Models\\Editor\\LightStyle.tex" + +functions: +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_LIGHTSTYLE); + SetModelMainTexture(TEXTURE_LIGHTSTYLE); + + return; + } +}; diff --git a/Sources/Entities/Lightning.es b/Sources/Entities/Lightning.es new file mode 100644 index 0000000..a16ba51 --- /dev/null +++ b/Sources/Entities/Lightning.es @@ -0,0 +1,258 @@ +607 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/BackgroundViewer.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/Light.h" +%} + +%{ + struct ThunderInfo + { + INDEX ti_iSound; + FLOAT ti_fThunderStrikeDelay; + }; + + struct ThunderInfo _atiThunderSounds[3] = + { + { SOUND_THUNDER1, 0.6f}, + { SOUND_THUNDER2, 0.0f}, + { SOUND_THUNDER3, 0.0f}, + }; +%} + +class CLightning: CMovableModelEntity { +name "Lightning"; +thumbnail "Thumbnails\\Lightning.tbn"; +features "IsTargetable", "HasName"; + +properties: + 1 CEntityPointer m_penTarget "Target" 'T' COLOR(C_BLUE|0xFF), // ptr to lightninig target + 2 CEntityPointer m_penwsc, // ptr to world settings controller + 3 CTString m_strName "Name" 'N' = "Lightning", // class name + 4 FLOAT m_tmLightningStart = -1.0f, // lightning start time + 5 CSoundObject m_soThunder, // sound channel + 6 BOOL m_bBackground "Background" 'B' =FALSE, + 7 CEntityPointer m_penLight "Light" 'L' COLOR(C_CYAN|0xFF), // ptr to light + 8 ANIMATION m_iLightAnim "Light Animation" 'A' = 0, + 9 INDEX m_iSoundPlaying = 0, + 10 FLOAT m_fLightningPower "Lightning power" 'P' = 1.0f, // lightning's ligting power + 11 FLOAT m_fSoundDelay "Sound delay" 'D' = 0.0f, // thunder's delay + +components: + 1 model MODEL_TELEPORT "Models\\Editor\\Teleport.mdl", + 2 texture TEXTURE_TELEPORT "Models\\Editor\\BoundingBox.tex", + 3 sound SOUND_THUNDER1 "Sounds\\Environment\\Thunders\\Thunder1.wav", + 4 sound SOUND_THUNDER2 "Sounds\\Environment\\Thunders\\Thunder2.wav", + 5 sound SOUND_THUNDER3 "Sounds\\Environment\\Thunders\\Thunder3.wav", + +functions: + void Precache(void) + { + CMovableModelEntity::Precache(); + PrecacheSound(SOUND_THUNDER1); + PrecacheSound(SOUND_THUNDER2); + PrecacheSound(SOUND_THUNDER3); + } + + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + if (m_penLight==NULL) { + return NULL; + } + + // if light entity + if (IsOfClass(m_penLight, "Light")) + { + CLight *penLight = (CLight*)&*m_penLight; + + if (slPropertyOffset==offsetof(CLightning, m_iLightAnim)) + { + return penLight->m_aoLightAnimation.GetData(); + } + } + else + { + WarningMessage("Target '%s' is not of light class!", (const char*)m_penLight->GetName()); + } + return NULL; + }; + + void RenderParticles(void) + { + if( m_penTarget==NULL) {return;}; + + TIME tmNow = _pTimer->GetLerpedCurrentTick(); + // if lightning is traveling + if( + ((tmNow-m_tmLightningStart) > 0.0f) && + ((tmNow-m_tmLightningStart) < 1.5f) ) + { + // render lightning particles + FLOAT3D vSrc = GetPlacement().pl_PositionVector; + FLOAT3D vDst = m_penTarget->GetPlacement().pl_PositionVector; + Particles_Lightning( vSrc, vDst, m_tmLightningStart); + } + } + +procedures: + LightningStike() + { + // choose random sound + m_iSoundPlaying = 1+IRnd()%( ARRAYCOUNT(_atiThunderSounds)-1); + if( m_fSoundDelay != 0) + { + m_iSoundPlaying=0; + } + m_soThunder.SetVolume(1.5f*m_fLightningPower, 1.5f*m_fLightningPower); + m_soThunder.SetPitch(Lerp(0.9f, 1.2f, FRnd())); + + if( m_fSoundDelay == 0.0f) + { + // play thunder ! + PlaySound(m_soThunder, _atiThunderSounds[ m_iSoundPlaying].ti_iSound, 0); + } + + // wait for sound to progress to lightning strike + autowait( _atiThunderSounds[ m_iSoundPlaying].ti_fThunderStrikeDelay); + + // remember current time as lightning start time + TIME tmNow = _pTimer->CurrentTick(); + m_tmLightningStart = tmNow; + // also in world settings controller + ((CWorldSettingsController *)&*m_penwsc)->m_tmLightningStart = tmNow; + // set power of lightning + ((CWorldSettingsController *)&*m_penwsc)->m_fLightningPower = m_fLightningPower; + + // trigger light animation + if( m_penLight != NULL) + { + EChangeAnim eChange; + eChange.iLightAnim = m_iLightAnim; + eChange.bLightLoop = FALSE; + m_penLight->SendEvent(eChange); + } + + if( m_fSoundDelay != 0.0f) + { + // wait given delay time + autowait( m_fSoundDelay); + // play thunder ! + PlaySound(m_soThunder, _atiThunderSounds[ m_iSoundPlaying].ti_iSound, 0); + } + + // wait until end of sound + wait( GetSoundLength(_atiThunderSounds[ m_iSoundPlaying].ti_iSound)- + _atiThunderSounds[ m_iSoundPlaying].ti_fThunderStrikeDelay) + { + on (ETimer) : + { + stop; + } + otherwise() : + { + resume; + }; + } + + return EBegin(); + } + + Main(EVoid) + { + // set appearance + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_TELEPORT); + SetModelMainTexture(TEXTURE_TELEPORT); + + // see if it is lightning on background + if (m_bBackground) + { + SetFlags(GetFlags()|ENF_BACKGROUND); + } + else + { + SetFlags(GetFlags()&~ENF_BACKGROUND); + } + + // obtain bcg viewer entity + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer == NULL) + { + // don't do anything + return; + } + + // obtain world settings controller + m_penwsc = penBcgViewer->m_penWorldSettingsController; + if( m_penwsc == NULL) + { + // don't do anything + return; + } + + // must be world settings controller entity + if (!IsOfClass(m_penwsc, "WorldSettingsController")) + { + // don't do anything + return; + } + + // lightning target must be marker + if( (m_penTarget == NULL) || (!IsOfClass(m_penTarget, "Marker")) ) + { + if( m_penTarget != NULL) + { + WarningMessage("Target '%s' is not of Marker class!", (const char*)m_penTarget->GetName()); + } + // don't do anything + return; + } + + // stretch model + FLOAT3D vDirection = + (m_penTarget->GetPlacement().pl_PositionVector- + GetPlacement().pl_PositionVector); + + FLOAT3D vStretch = vDirection; + vStretch(1) = 1.0f; + vStretch(2) = 1.0f; + vStretch(3) = -vDirection.Length(); + + // set entity orientation + CPlacement3D pl = GetPlacement(); + DirectionVectorToAngles(vDirection.Normalize(), pl.pl_OrientationAngle); + SetPlacement(pl); + + GetModelObject()->StretchModel(vStretch); + ModelChangeNotify(); + + // correct power factor to fall under 0-1 boundaries + m_fLightningPower = Clamp( m_fLightningPower, 0.0f, 1.0f); + + // spawn in world editor + autowait(0.1f); + + while (TRUE) + { + wait() + { + on (EBegin) : { resume; } + on (ETrigger eTrigger) : + { + call LightningStike(); + resume; + } + otherwise() : + { + resume; + }; + }; + } + } +}; diff --git a/Sources/Entities/Mamut.es b/Sources/Entities/Mamut.es new file mode 100644 index 0000000..f63825b --- /dev/null +++ b/Sources/Entities/Mamut.es @@ -0,0 +1,452 @@ +327 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Mamut/MAMUT.H" +#include "Models/Enemies/MAMUTMAN/Mamutman.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Mamutman"; +uses "Entities/AirWave"; +uses "Entities/Bullet"; + + +enum MamutChar { + 0 MAT_SUMMER "Summer", + 1 MAT_WINTER "Winter", +}; + + +%{ +// info structure +static EntityInfo eiMamut = { + EIBT_FLESH, 2500.0f, + 0.0f, 1.5f, 0.0f, + 0.0f, 2.0f, 0.0f, +}; + +#define HIT_DISTANCE 13.0f +#define FIRE_BULLET FLOAT3D(0.0f*2, 4.0f*2, -4.0f*2) +#define FIRE_AIRWAVE FLOAT3D(0.0f*2, 0.5f*2, -4.0f*2) +#define RIDER_FRONT FLOAT3D( 0.25f*2, 6.5f*2, 0.5f*2) +#define RIDER_MIDDLE FLOAT3D(-0.25f*2, 5.6f*2, 1.5f*2) +#define RIDER_REAR FLOAT3D( 0.1f*2, 4.6f*2, 2.4f*2) +%} + + +class CMamut : CEnemyBase { +name "Mamut"; +thumbnail "Thumbnails\\Mamut.tbn"; + +properties: + 1 enum MamutChar m_EmcChar "Character" 'C' = MAT_SUMMER, // character + 2 BOOL m_bFrontRider "Rider Front" 'H' = FALSE, // front rider + 3 BOOL m_bMiddleRider "Rider Middle" 'J' = FALSE, // middle rider + 4 BOOL m_bRearRider "Rider Rear" 'K' = FALSE, // rear rider + 5 CEntityPointer m_penBullet, // bullet + 6 FLOAT m_fLastShootTime = 0.0f, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_BULLET "Classes\\Bullet.ecl", + 2 class CLASS_MAMUTMAN "Classes\\Mamutman.ecl", + 3 class CLASS_AIRWAVE "Classes\\AirWave.ecl", + + 10 model MODEL_MAMUT "Models\\Enemies\\Mamut\\Mamut.mdl", + 11 texture TEXTURE_MAMUT_SUMMER "Models\\Enemies\\Mamut\\Mamut.tex", + 12 texture TEXTURE_MAMUT_WINTER "Models\\Enemies\\Mamut\\Mamut3.tex", + + 20 model MODEL_MAMUTMAN "Models\\Enemies\\Mamutman\\Mamutman.mdl", + 21 texture TEXTURE_MAMUTMAN "Models\\Enemies\\Mamutman\\Mamutman.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Mamut\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Mamut\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Mamut\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Mamut\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Mamut\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Mamut\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiMamut; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // mamut can't harm mamut + if (!IsOfClass(penInflictor, "Mamut")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // play attachmnet anim + void PlayAttachmentAnim(INDEX iAttachment, INDEX iAnim, ULONG ulFlags) { + CAttachmentModelObject *amo = GetModelObject()->GetAttachmentModel(iAttachment); + if (amo!=NULL) { + amo->amo_moModelObject.PlayAnim(iAnim, ulFlags); + } + }; + + + // death + INDEX AnimForDeath(void) { + StartModelAnim(MAMUT_ANIM_DEATH, 0); + return MAMUT_ANIM_DEATH; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(MAMUT_COLLISION_BOX_DEATH); + DropRiders(TRUE); + }; + + + // drop riders + void CreateRider(const FLOAT3D &vPos, INDEX iRider) { + // mamutman start position + CPlacement3D pl; + pl.pl_OrientationAngle = ANGLE3D(0,0,0); + pl.pl_PositionVector = vPos; + pl.RelativeToAbsolute(GetPlacement()); + // create rider + CEntityPointer pen = CreateEntity(pl, CLASS_MAMUTMAN); + ((CMamutman&)*pen).m_bSpawned = TRUE; + ((CMamutman&)*pen).m_bSpawnedPosition = iRider; + ((CMamutman&)*pen).m_penEnemy = m_penEnemy; + ((CMamutman&)*pen).m_ttTarget = m_ttTarget; + pen->Initialize(EVoid()); + }; + + void DropRiders(BOOL bAlways) { + if (m_bFrontRider && (bAlways || (IRnd()&1))) { + m_bFrontRider = FALSE; + CreateRider(RIDER_FRONT, 0); + RemoveAttachmentFromModel(*GetModelObject(), MAMUT_ATTACHMENT_MAN_FRONT); + } + if (m_bMiddleRider && (bAlways || (IRnd()&1))) { + m_bMiddleRider = FALSE; + CreateRider(RIDER_MIDDLE, 1); + RemoveAttachmentFromModel(*GetModelObject(), MAMUT_ATTACHMENT_MAN_MIDDLE); + } + if (m_bRearRider && (bAlways || (IRnd()&1))) { + m_bRearRider = FALSE; + CreateRider(RIDER_REAR, 2); + RemoveAttachmentFromModel(*GetModelObject(), MAMUT_ATTACHMENT_MAN_REAR); + } + }; + + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(MAMUT_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_FRONT, MAMUTMAN_ANIM_STANDMOUNTEDFIRST, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_MIDDLE, MAMUTMAN_ANIM_STANDMOUNTEDSECOND, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_REAR, MAMUTMAN_ANIM_STANDMOUNTEDTHIRD, 0); + }; + void WalkingAnim(void) { + StartModelAnim(MAMUT_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_FRONT, MAMUTMAN_ANIM_MOUNTEDWALKFIRST, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_MIDDLE, MAMUTMAN_ANIM_MOUNTEDWALKSECOND, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_REAR, MAMUTMAN_ANIM_MOUNTEDWALKTHIRD, 0); + }; + void RunningAnim(void) { + StartModelAnim(MAMUT_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_FRONT, MAMUTMAN_ANIM_MOUNTEDRUNFIRST, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_MIDDLE, MAMUTMAN_ANIM_MOUNTEDRUNSECOND, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_REAR, MAMUTMAN_ANIM_MOUNTEDRUNTHIRD, 0); + }; + void RotatingAnim(void) { + StartModelAnim(MAMUT_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_FRONT, MAMUTMAN_ANIM_MOUNTEDWALKFIRST, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_MIDDLE, MAMUTMAN_ANIM_MOUNTEDWALKSECOND, 0); + PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_REAR, MAMUTMAN_ANIM_MOUNTEDWALKTHIRD, 0); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +/************************************************************ + * FIRE BULLET * + ************************************************************/ + // prepare bullet + void PrepareBullet(void) { + // bullet start position + CPlacement3D plBullet; + plBullet.pl_OrientationAngle = ANGLE3D(0,0,0); + plBullet.pl_PositionVector = FIRE_BULLET; + plBullet.RelativeToAbsolute(GetPlacement()); + // create bullet + m_penBullet = CreateEntity(plBullet, CLASS_BULLET); + // init bullet + EBulletInit eInit; + eInit.penOwner = this; + eInit.fDamage = 1.0f; + m_penBullet->Initialize(eInit); + ((CBullet&)*m_penBullet).CalcTarget(m_penEnemy, 100); + }; + + // fire bullet + void FireBullet(void) { + ((CBullet&)*m_penBullet).LaunchBullet(TRUE, TRUE, TRUE); + ((CBullet&)*m_penBullet).DestroyBullet(); + }; + + + // fire air wave + void FireAirWave(void) { + // target enemy body + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + + // launch + CPlacement3D pl; + PrepareFreeFlyingProjectile(pl, vShootTarget, FIRE_AIRWAVE, ANGLE3D(0, 0, 0)); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_AIRWAVE); + EAirWave eLaunch; + eLaunch.penLauncher = this; + penProjectile->Initialize(eLaunch); + }; + + + +procedures: +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + // Play wound animation and falling body part + BeWounded(EDamage eDamage) : CEnemyBase::BeWounded + { + StopMoving(); + // damage anim + StartModelAnim(MAMUT_ANIM_WOUND02, 0); + autowait(0.5f); + // drop riders + if (GetHealth()<600.0f) { + DropRiders(GetHealth()<250.0f); + } + autowait(1.5f); + + return EReturn(); + }; + + + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ +/* // initial preparation + InitializeAttack(EVoid) : CEnemyBase::InitializeAttack { + m_fLastShootTime = 0.0f; + jump CEnemyBase::InitializeAttack(); + }; + + + // attack shoot + AttackShoot() : CEnemyBase::AttackShoot { + // shoot at enemy if possible + if (CanAttackEnemy(m_penEnemy, Cos(AngleDeg(130.0f)))) { + // set next shoot time + m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/3.0f); + // fire + // mamut shoot + if (m_fLastShootTime+4.0f<_pTimer->CurrentTick() && + CanAttackEnemy(m_penEnemy, Cos(AngleDeg(50.0f)))) { + // stop moving (rotation and translation) + StopMoving(); + autocall Fire() EReturn; + // rider (mamutman) shoot + } else if (m_bFrontRider || m_bMiddleRider || m_bRearRider) { + // stop rotating + StopRotating(); + autocall RiderFire() EReturn; + } + } else { + // safety precocious from stack overflow loop + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + } + return ETimer(); + }; + + // close shoot + CloseShoot() : CEnemyBase::CloseShoot { + // shoot at enemy if possible + if (CalcDist(m_penEnemy)CurrentTick() + m_fCloseFireTime*(1.0f + FRnd()/3.0f); + // hit + // mamut shoot + if (m_fLastShootTime+4.0f<_pTimer->CurrentTick() && + CanHitEnemy(m_penEnemy, Cos(AngleDeg(50.0f)))) { + // stop moving (rotaion and translation) + StopMoving(); + autocall Hit() EReturn; + // rider (mamutman) shoot + } else if (m_bFrontRider || m_bMiddleRider || m_bRearRider) { + // stop rotating + StopRotating(); + autocall RiderFire() EReturn; + } + + // try attack shoot + } else { + jump AttackShoot(); + } + return ETimer(); + }; + */ + + Fire(EVoid) : CEnemyBase::Fire { + m_fLastShootTime = _pTimer->CurrentTick(); + + // fire projectile + StartModelAnim(MAMUT_ANIM_WOUND01, 0); + autowait(1.1f); + FireAirWave(); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(FRnd()*0.2f); + + return EReturn(); + }; + + Hit(EVoid) : CEnemyBase::Hit { + m_fLastShootTime = _pTimer->CurrentTick(); + + // hit the ground + StartModelAnim(MAMUT_ANIM_ATTACK01, 0); + autowait(0.3f); + if (CalcDist(m_penEnemy) < HIT_DISTANCE) { + FLOAT3D vSource = GetPlacement().pl_PositionVector + + FLOAT3D(en_mRotation(1, 2), en_mRotation(2, 2), en_mRotation(3, 2)); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + // damage + InflictRangeDamage(this, DMT_CLOSERANGE, 20.0f, vSource, 1.0f, 15.0f); + } + autowait(0.5f); + if (CalcDist(m_penEnemy) < HIT_DISTANCE) { + FLOAT3D vSource = GetPlacement().pl_PositionVector + + FLOAT3D(en_mRotation(1, 2), en_mRotation(2, 2), en_mRotation(3, 2)); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + // damage + InflictRangeDamage(this, DMT_CLOSERANGE, 20.0f, vSource, 1.0f, 15.0f); + } + autowait(0.7f+FRnd()*0.1f); + + return EReturn(); + }; + + RiderFire() { + // if have any rider fire + if (m_bFrontRider || m_bMiddleRider || m_bRearRider) { + // prepare + PrepareBullet(); + + // find valid rider + INDEX iRider = IRnd()%3; + if (iRider==0 && !m_bFrontRider) { iRider = 1; } + if (iRider==1 && !m_bMiddleRider) { iRider = 2; } + if (iRider==2 && !m_bRearRider) { iRider = 0; } + if (iRider==0 && !m_bFrontRider) { iRider = 1; } + if (iRider==1 && !m_bMiddleRider) { iRider = 2; } + + // animation + switch (iRider) { + case 0: PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_FRONT, MAMUTMAN_ANIM_MOUNTEDATTACKFIRST, 0); break; + case 1: PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_MIDDLE, MAMUTMAN_ANIM_MOUNTEDATTACKSECOND, 0); break; + case 2: PlayAttachmentAnim(MAMUT_ATTACHMENT_MAN_REAR, MAMUTMAN_ANIM_MOUNTEDATTACKTHIRD, 0); break; + } + + // fire bullet + autowait(0.8f); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + FireBullet(); + } + + return EReturn(); + }; + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + en_tmMaxHoldBreath = 35.0f; + en_fDensity = 4000.0f; + + // set your appearance + GetModelObject()->StretchModel(FLOAT3D(2,2,2)); + SetModel(MODEL_MAMUT); + ModelChangeNotify(); + if (m_EmcChar==MAT_SUMMER) { + SetModelMainTexture(TEXTURE_MAMUT_SUMMER); + } else { + SetModelMainTexture(TEXTURE_MAMUT_WINTER); + } + SetHealth(700.0f); + m_fMaxHealth = 700.0f; + // set riders + RemoveAttachmentFromModel(*GetModelObject(), MAMUT_ATTACHMENT_MAN_FRONT); + RemoveAttachmentFromModel(*GetModelObject(), MAMUT_ATTACHMENT_MAN_MIDDLE); + RemoveAttachmentFromModel(*GetModelObject(), MAMUT_ATTACHMENT_MAN_REAR); + if (m_bFrontRider) { + AddAttachmentToModel(this, *GetModelObject(), MAMUT_ATTACHMENT_MAN_FRONT, + MODEL_MAMUTMAN, TEXTURE_MAMUTMAN, 0, 0, 0); + } + if (m_bMiddleRider) { + AddAttachmentToModel(this, *GetModelObject(), MAMUT_ATTACHMENT_MAN_MIDDLE, + MODEL_MAMUTMAN, TEXTURE_MAMUTMAN, 0, 0, 0); + } + if (m_bRearRider) { + AddAttachmentToModel(this, *GetModelObject(), MAMUT_ATTACHMENT_MAN_REAR, + MODEL_MAMUTMAN, TEXTURE_MAMUTMAN, 0, 0, 0); + } + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.0f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); + m_fAttackRunSpeed = FRnd() + 9.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*15.0f + 250.0f); + m_fCloseRunSpeed = FRnd() + 10.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*15.0f + 250.0f); + // setup attack distances + m_fAttackDistance = 120.0f; + m_fCloseDistance = 14.0f; + m_fStopDistance = 12.0f; + INDEX iTime = 4.0f; + if (m_bFrontRider) { iTime--; } + if (m_bMiddleRider) { iTime--; } + if (m_bRearRider) { iTime--; } + m_fAttackFireTime = iTime; + m_fCloseFireTime = 0.5f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 250.0f; + m_fBodyParts = 5; + m_fDamageWounded = 200.0f; + m_iScore = 5000; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Mamutman.es b/Sources/Entities/Mamutman.es new file mode 100644 index 0000000..8c441ba --- /dev/null +++ b/Sources/Entities/Mamutman.es @@ -0,0 +1,289 @@ +326 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/MAMUTMAN/Mamutman.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Bullet"; + +%{ +// info structure +static EntityInfo eiMamutman = { + EIBT_FLESH, 60.0f, + 0.0f, 2.0f, 0.0f, + 0.0f, 1.5f, 0.0f, +}; + +#define FIRE FLOAT3D(0.0f, 0.8f, 0.0f) + +#define FRONT 0 +#define MIDDLE 1 +#define REAR 2 +%} + + +class CMamutman : CEnemyBase { +name "Mamutman"; +thumbnail "Thumbnails\\Mamutman.tbn"; + +properties: + 1 CEntityPointer m_penBullet, // bullet + 2 BOOL m_bSpawned = FALSE, + 3 INDEX m_bSpawnedPosition = 0, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_BULLET "Classes\\Bullet.ecl", + + 5 model MODEL_MAMUTMAN "Models\\Enemies\\Mamutman\\Mamutman.mdl", + 6 texture TEXTURE_MAMUTMAN "Models\\Enemies\\Mamutman\\Mamutman.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Mamutman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Mamutman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Mamutman\\Sounds\\Wound.wav", + 53 sound SOUND_DEATH "Models\\Enemies\\Mamutman\\Sounds\\Death.wav", + 54 sound SOUND_FIRE "Models\\Weapons\\Colt\\Sounds\\Fire.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiMamutman; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // mamutman and mamut can't harm mamutman + if (!IsOfClass(penInflictor, "Mamutman") && !IsOfClass(penInflictor, "Mamut")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = MAMUTMAN_ANIM_DEATH01; break; + case 1: iAnim = MAMUTMAN_ANIM_DEATH01; break; + default: ASSERTALWAYS("Mamutman unknown death"); + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(MAMUTMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(MAMUTMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { + StartModelAnim(MAMUTMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { + StartModelAnim(MAMUTMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + StartModelAnim(MAMUTMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +/************************************************************ + * FIRE BULLET * + ************************************************************/ + void PrepareBullet(void) { + // bullet start position + CPlacement3D plBullet; + plBullet.pl_OrientationAngle = ANGLE3D(0,0,0); + plBullet.pl_PositionVector = FIRE; + plBullet.RelativeToAbsolute(GetPlacement()); + // create bullet + m_penBullet = CreateEntity(plBullet, CLASS_BULLET); + // init bullet + EBulletInit eInit; + eInit.penOwner = this; + eInit.fDamage = 1.0f; + m_penBullet->Initialize(eInit); + ((CBullet&)*m_penBullet).CalcTarget(m_penEnemy, 100); + }; + + // fire bullet + void FireBullet(void) { + ((CBullet&)*m_penBullet).LaunchBullet(TRUE, TRUE, TRUE); + ((CBullet&)*m_penBullet).DestroyBullet(); + }; + + + +procedures: +/************************************************************ + * CLASS INTERNAL * + ************************************************************/ + FallOnFloor(EVoid) { + // drop to floor + m_bSpawned = FALSE; + switch (m_bSpawnedPosition) { + case FRONT: + StartModelAnim(MAMUTMAN_ANIM_FALLFROMMAMUTFIRST, 0); + GiveImpulseTranslationRelative(FLOAT3D(FRnd()*4+8.0f, FRnd()+10.0f, FRnd()+2.0f)); + break; + case MIDDLE: + StartModelAnim(MAMUTMAN_ANIM_FALLFROMMAMUTSECOND, 0); + GiveImpulseTranslationRelative(FLOAT3D(-FRnd()*4-8.0f, FRnd()+10.0f, FRnd()+2.0f)); + break; + case REAR: + StartModelAnim(MAMUTMAN_ANIM_FALLFROMMAMUTTHIRD, 0); + GiveImpulseTranslationRelative(FLOAT3D(0.0f, FRnd()+10.0f, FRnd()*2+2.0f)); + break; + } + // wait to touch brush or time limit + wait (10.0f) { + on (EBegin) : { resume; } + // brush touched + on (ETouch et) : { + if (et.penOther->GetRenderType()&RT_BRUSH) { + StopMoving(); + stop; + } + resume; + } + // death + on (EDeath) : { + StopMoving(); + SendEvent(EDeath()); + jump CEnemyBase::MainLoop(); + } + on (ETimer) : { stop; } + } + + // get up + StopMoving(); + StartModelAnim(MAMUTMAN_ANIM_GETUP01, 0); + wait (GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_GETUP01)) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + // death + on (EDeath) : { + StopMoving(); + SendEvent(EDeath()); + jump CEnemyBase::MainLoop(); + } + } + return EReturn(); + }; + + + +/************************************************************ + * PROCEDURES WHEN HARMED * + ************************************************************/ + // Play wound animation and falling body part + BeWounded(EDamage eDamage) : CEnemyBase::BeWounded + { + StopMoving(); + // determine damage anim and play the wounding + if (IRnd()&1) { + StartModelAnim(MAMUTMAN_ANIM_FALL01, 0); + autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_FALL01)); + autowait(0.2f + FRnd()/3); + StartModelAnim(MAMUTMAN_ANIM_GETUP01, 0); + autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_GETUP01)); + + } else if (TRUE) { + StartModelAnim(MAMUTMAN_ANIM_FALL02, 0); + autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_FALL02)); + autowait(0.2f + FRnd()/3); + StartModelAnim(MAMUTMAN_ANIM_GETUP02, 0); + autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_GETUP02)); + } + return EReturn(); + }; + + + +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire { + // wait for a while + StandingAnim(); + PrepareBullet(); + m_fLockOnEnemyTime = 0.2f + FRnd()/8; + autocall CEnemyBase::LockOnEnemy() EReturn; + + // fire bullet + StartModelAnim(MAMUTMAN_ANIM_ATTACK02, 0); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + FireBullet(); + autowait(FRnd()/3 + 0.6f); + + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(40.0f); + m_fMaxHealth = 40.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 1000.0f; + + // set your appearance + SetModel(MODEL_MAMUTMAN); + SetModelMainTexture(TEXTURE_MAMUTMAN); + if (!m_bSpawned) { + StandingAnim(); + } + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); + m_fAttackRunSpeed = FRnd()*2.0f + 10.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd()*2.0f + 10.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 60.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 17.0f; + m_fAttackFireTime = 1.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 20.0f; + m_fBodyParts = 4; + m_fDamageWounded = 30.0f; + m_iScore = 500; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/Mantaman.es b/Sources/Entities/Mantaman.es new file mode 100644 index 0000000..83410e2 --- /dev/null +++ b/Sources/Entities/Mantaman.es @@ -0,0 +1,197 @@ +329 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/MANTAMAN/mantaman.h" +%} + +uses "Entities/EnemyDive"; + +%{ +static EntityInfo eiMantamanLiquid = { + EIBT_FLESH, 150.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + +#define FIRE_WATER FLOAT3D(0.0f, 0.5f, -1.25f) +}; +%} + + +class CMantaman : CEnemyDive { +name "Mantaman"; +thumbnail "Thumbnails\\Mantaman.tbn"; + +properties: + 1 BOOL m_FixedState "Fixed state" 'X' = FALSE, // fixed state on beginning + +components: + 0 class CLASS_BASE "Classes\\EnemyDive.ecl", + 1 model MODEL_MANTAMAN "Models\\Enemies\\Mantaman\\Mantaman.mdl", + 2 texture TEXTURE_MANTAMAN "Models\\Enemies\\Mantaman\\Mantaman.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Mantaman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Mantaman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Mantaman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Mantaman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Mantaman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Mantaman\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiMantamanLiquid; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // mantaman can't harm mantaman + if (!IsOfClass(penInflictor, "Mantaman")) { + CEnemyDive::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = MANTAMAN_ANIM_WOUND01; break; + case 1: iAnim = MANTAMAN_ANIM_WOUND02; break; + default: ASSERTALWAYS("Mantaman unknown liquid damage"); + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + StartModelAnim(MANTAMAN_ANIM_DEATH, 0); + return MANTAMAN_ANIM_DEATH; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(MANTAMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + if (m_FixedState) { + StartModelAnim(MANTAMAN_ANIM_DEFAULT_ANIMATION02, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(MANTAMAN_ANIM_STANDORANDSWIMSLOW, AOF_LOOPING|AOF_NORESTART); + } + }; + void WalkingAnim(void) { + StartModelAnim(MANTAMAN_ANIM_STANDORANDSWIMSLOW, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { + StartModelAnim(MANTAMAN_ANIM_SWIMFAST, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + StartModelAnim(MANTAMAN_ANIM_STANDORANDSWIMSLOW, AOF_LOOPING|AOF_NORESTART); + }; + void ChangeCollisionToLiquid() { + ChangeCollisionBoxIndexWhenPossible(MANTAMAN_COLLISION_BOX_DEAFULT); + }; + void ChangeCollisionToGround() { + ChangeCollisionBoxIndexWhenPossible(MANTAMAN_COLLISION_BOX_DEAFULT); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + AttackEnemy(EVoid) : CEnemyBase::AttackEnemy { + if (m_FixedState) { + m_FixedState = FALSE; + StartModelAnim(MANTAMAN_ANIM_MORPH, 0); + wait(GetModelObject()->GetAnimLength(MANTAMAN_ANIM_MORPH)) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + on (EWatch) : { resume; } + on (EDamage) : { resume; } + } + } + jump CEnemyBase::AttackEnemy(); + }; + + + DiveFire(EVoid) : CEnemyDive::DiveFire { + // fire projectile + StartModelAnim(MANTAMAN_ANIM_ATTACK01, 0); + autowait(0.3f); + ShootProjectile(PRT_MANTAMAN_FIRE, FIRE_WATER, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.8f); + StandingAnim(); + autowait(FRnd()/2 + _pTimer->TickQuantum); + + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASGILLS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(50.0f); + m_fMaxHealth = 50.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 1000.0f; + + // set your appearance + SetModel(MODEL_MANTAMAN); + SetModelMainTexture(TEXTURE_MANTAMAN); + // dive moving properties + m_fDiveWalkSpeed = FRnd() + 2.0f; + m_aDiveWalkRotateSpeed = FRnd()*10.0f + 500.0f; + m_fDiveAttackRunSpeed = FRnd()*4.0f + 14.0f; + m_aDiveAttackRotateSpeed = FRnd()*25 + 250.0f; + m_fDiveCloseRunSpeed = FRnd()*2.0f + 6.5f; + m_aDiveCloseRotateSpeed = FRnd()*50 + 250.0f; + // attack properties + m_fDiveAttackDistance = 100.0f; + m_fDiveCloseDistance = 0.0f; + m_fDiveStopDistance = 5.0f; + m_fDiveAttackFireTime = 3.0f; + m_fDiveCloseFireTime = 2.0f; + m_fDiveIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 140.0f; + m_fBodyParts = 4; + m_fDamageWounded = 30.0f; + m_iScore = 2000; + + + // allowed types + m_EedtType = EDT_DIVE_ONLY; + + // continue behavior in base class + jump CEnemyDive::MainLoop(); + }; +}; diff --git a/Sources/Entities/Marker.es b/Sources/Entities/Marker.es new file mode 100644 index 0000000..8549edb --- /dev/null +++ b/Sources/Entities/Marker.es @@ -0,0 +1,59 @@ +202 +%{ +#include "Entities/StdH/StdH.h" +%} + +class CMarker: CEntity { +name "Marker"; +thumbnail "Thumbnails\\Marker.tbn"; +features "HasName", "HasTarget", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Marker", + 3 CTString m_strDescription = "", + 2 CEntityPointer m_penTarget "Target" 'T' COLOR(C_dGREEN|0xFF), + +components: + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + +functions: + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s", (const char*)m_penTarget->GetName()); + } + return m_strDescription; + } + + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\Marker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + // this is MARKER !!!! + virtual BOOL IsMarker(void) const { + return TRUE; + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + return; + } +}; + diff --git a/Sources/Entities/MessageHolder.es b/Sources/Entities/MessageHolder.es new file mode 100644 index 0000000..d103ef0 --- /dev/null +++ b/Sources/Entities/MessageHolder.es @@ -0,0 +1,63 @@ +226 +%{ +#include "Entities/StdH/StdH.h" +extern INDEX ent_bReportBrokenChains; +%} + +class CMessageHolder : CRationalEntity { +name "MessageHolder"; +thumbnail "Thumbnails\\MessageHolder.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "MessageHolder", + 3 CTString m_strDescription = "", + 2 CTFileName m_fnmMessage "Message" 'M' = CTString(""), + 4 FLOAT m_fDistance "Distance" 'D' = 2.0f, + 5 BOOL m_bActive "Active" 'A' = TRUE, + 6 CEntityPointer m_penNext "Next" 'X', + +components: + 1 model MODEL_MARKER "Models\\Editor\\MessageHolder.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\MessageHolder.tex" + +functions: + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("%s", (const char*)m_fnmMessage.FileName()); + return m_strDescription; + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + wait() { + on (ETrigger eTrigger): { + if (!m_bActive) { + resume; + } + CEntity *penCaused = FixupCausedToPlayer(this, eTrigger.penCaused); + EComputerMessage eMsg; + eMsg.fnmMessage = m_fnmMessage; + penCaused->SendEvent(eMsg); + resume; + } + on (EActivate): { + m_bActive = TRUE; + resume; + } + on (EDeactivate): { + m_bActive = FALSE; + resume; + } + } + return; + } +}; + diff --git a/Sources/Entities/MessageItem.es b/Sources/Entities/MessageItem.es new file mode 100644 index 0000000..5973ec8 --- /dev/null +++ b/Sources/Entities/MessageItem.es @@ -0,0 +1,102 @@ +807 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +%} + +uses "Entities/Item"; + +// event for sending through receive item +event EMessageItem { + CTFileName fnmMessage, +}; + +%{ +%} + +class CMessageItem : CItem { +name "MessageItem"; +thumbnail "Thumbnails\\MessageItem.tbn"; + +properties: + 1 CTString m_strName "Name" 'N' = "MessageItem", + 2 CTString m_strDescription = "", + 3 CTFileName m_fnmMessage "Message" 'M' = CTString(""), + 4 INDEX m_iSoundComponent = 0, + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + + 1 model MODEL_PERGAMENT "Models\\Items\\Pergament\\Pergament.mdl", + 2 texture TEXTURE_PERGAMENT "Models\\Items\\Pergament\\Pergament.tex", + + // ********* MISC ********* +255 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", +256 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", + +// ************** SOUNDS ************** +301 sound SOUND_KEY "Sounds\\Items\\Key.wav", + +functions: + void Precache(void) { + PrecacheSound(SOUND_KEY); + } + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = "Pergament"; + pes->es_ctCount = 1; + pes->es_ctAmmount = 1; + pes->es_fValue = 1; + pes->es_iScore = 0;//m_iScore; + return TRUE; + } + // render particles + void RenderParticles(void) { + // no particles when not existing + if (GetRenderType()!=CEntity::RT_MODEL) { + return; + } + Particles_Stardust(this, 0.9f, 0.70f, PT_STAR08, 32); + } + + // set health properties depending on type + void SetProperties(void) { + m_fRespawnTime = 10.0f; + m_strDescription = m_fnmMessage.FileName(); + + // set appearance + AddItem(MODEL_PERGAMENT, TEXTURE_PERGAMENT, 0, 0, 0); + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.2f,0), FLOAT3D(1,1,0.3f) ); + StretchItem(FLOAT3D(1.0f, 1.0f, 1.0f)); + m_iSoundComponent = SOUND_KEY; + }; + +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected { + ASSERT(epass.penOther!=NULL); + + // send key to entity + EMessageItem eMessage; + eMessage.fnmMessage = m_fnmMessage; + // if health is received + if (epass.penOther->ReceiveItem(eMessage)) { + // play the pickup sound + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soPick, m_iSoundComponent, SOF_3D); + m_fPickSoundLen = GetSoundLength(m_iSoundComponent); + jump CItem::ItemReceived(); + } + return; + }; + + Main() { + Initialize(); // initialize base class + StartModelAnim(ITEMHOLDER_ANIM_SMALLOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_SMALL); + SetProperties(); // set properties + + jump CItem::ItemLoop(); + }; +}; diff --git a/Sources/Entities/MirrorMarker.es b/Sources/Entities/MirrorMarker.es new file mode 100644 index 0000000..5cc754c --- /dev/null +++ b/Sources/Entities/MirrorMarker.es @@ -0,0 +1,82 @@ +218 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +enum WarpRotation { + 0 WR_NONE "none", + 1 WR_BANKING "banking", + 2 WR_TWIRLING "twirling", +}; + +class CMirrorMarker: CMarker { +name "Mirror Marker"; +thumbnail "Thumbnails\\WarpMarker.tbn"; +features "IsImportant"; + +properties: + 1 enum WarpRotation m_wrRotation "Rotation Type" 'R' = WR_NONE, + 2 FLOAT m_fRotationSpeed "Rotation Speed" 'S' = 90.0f, +components: + 1 model MODEL_IN "Models\\Editor\\WarpEntrance.mdl", + 2 texture TEXTURE_IN "Models\\Editor\\Warp.tex", + 3 model MODEL_OUT "Models\\Editor\\WarpExit.mdl", + 4 texture TEXTURE_OUT "Models\\Editor\\Warp.tex" + +functions: + + /* Get mirror type name, return empty string if not used. */ + const CTString &GetMirrorName(void) + { + return m_strName; + } + /* Get mirror. */ + void GetMirror(class CMirrorParameters &mpMirror) + { + mpMirror.mp_ulFlags = MPF_WARP; + mpMirror.mp_plWarpIn = GetLerpedPlacement(); + if (m_penTarget!=NULL) { + mpMirror.mp_penWarpViewer = m_penTarget; + mpMirror.mp_plWarpOut = m_penTarget->GetLerpedPlacement(); + } else { + mpMirror.mp_penWarpViewer = this; + mpMirror.mp_plWarpOut = GetLerpedPlacement(); + } + FLOAT tmNow = _pTimer->GetLerpedCurrentTick(); + mpMirror.mp_fWarpFOV = -1.0f; + if (m_wrRotation==WR_BANKING) { + mpMirror.mp_plWarpOut.Rotate_Airplane(ANGLE3D(0,0,m_fRotationSpeed*tmNow)); + } else if (m_wrRotation==WR_TWIRLING) { + ANGLE3D a; + a(1) = sin(tmNow*3.9)*5.0f; + a(2) = sin(tmNow*2.7)*5.0f; + a(3) = sin(tmNow*4.5)*5.0f; + mpMirror.mp_plWarpOut.Rotate_Airplane(a); + mpMirror.mp_fWarpFOV = 90.0f+sin(tmNow*7.79f)*5.0f; + } + } +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + if (m_penTarget!=NULL) { + SetModel(MODEL_IN); + SetModelMainTexture(TEXTURE_IN); + } else { + SetModel(MODEL_OUT); + SetModelMainTexture(TEXTURE_OUT); + } + + // set name + if (m_strName=="Marker") { + m_strName = "Mirror marker"; + } + return; + } +}; diff --git a/Sources/Entities/ModelDestruction.es b/Sources/Entities/ModelDestruction.es new file mode 100644 index 0000000..f675596 --- /dev/null +++ b/Sources/Entities/ModelDestruction.es @@ -0,0 +1,195 @@ +217 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelHolder2"; +uses "Entities/BasicEffects"; +uses "Entities/Debris"; +uses "Entities/BloodSpray"; + +// event sent to entities in range of model destroy +// (e.g light can turn off) +event ERangeModelDestruction { +}; + +// type of debris +enum DestructionDebrisType { + 1 DDT_STONE "Stone", + 2 DDT_WOOD "Wood", + 3 DDT_PALM "Palm", +}; + +class CModelDestruction : CEntity { +name "ModelDestruction"; +thumbnail "Thumbnails\\ModelDestruction.tbn"; +features "HasName", "IsTargetable", "IsImportant"; + +properties: + 1 CTString m_strName "Name" 'N' = "ModelDestruction", + 2 CTString m_strDescription = "", + + 10 CEntityPointer m_penModel0 "Model 0" 'M' COLOR(C_RED|0x00), + 11 CEntityPointer m_penModel1 "Model 1" COLOR(C_RED|0x00), + 12 CEntityPointer m_penModel2 "Model 2" COLOR(C_RED|0x00), + 13 CEntityPointer m_penModel3 "Model 3" COLOR(C_RED|0x00), + 14 CEntityPointer m_penModel4 "Model 4" COLOR(C_RED|0x00), + + 20 FLOAT m_fHealth "Health" 'H' = 50.0f, // health of the model pointing to this + 22 enum DestructionDebrisType m_ddtDebris "Debris" 'D' = DDT_STONE, // type of debris + 23 INDEX m_ctDebris "Debris Count" = 3, + 24 FLOAT m_fDebrisSize "Debris Size" = 1.0f, + 25 enum EntityInfoBodyType m_eibtBodyType "Body Type" = EIBT_ROCK, + 26 enum SprayParticlesType m_sptType "Particle Type" = SPT_NONE, // type of particles + +components: + 1 model MODEL_MODELDESTRUCTION "Models\\Editor\\ModelDestruction.mdl", + 2 texture TEXTURE_MODELDESTRUCTION "Models\\Editor\\ModelDestruction.tex", + 3 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +// ************** WOOD PARTS ************** + 10 model MODEL_WOOD "Models\\Effects\\Debris\\Wood01\\Wood.mdl", + 11 texture TEXTURE_WOOD "Models\\Effects\\Debris\\Wood01\\Wood.tex", + +// ************** STONE PARTS ************** + 14 model MODEL_STONE "Models\\Effects\\Debris\\Stone\\Stone.mdl", + 15 texture TEXTURE_STONE "Models\\Effects\\Debris\\Stone\\Stone.tex", + +functions: + void Precache(void) { + PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + switch(m_ddtDebris) { + case DDT_STONE: { + PrecacheModel(MODEL_STONE); + PrecacheTexture(TEXTURE_STONE); + } break; + case DDT_WOOD: { + PrecacheModel(MODEL_WOOD); + PrecacheTexture(TEXTURE_WOOD); + } break; + case DDT_PALM: { + PrecacheModel(MODEL_WOOD); + PrecacheTexture(TEXTURE_WOOD); + } break; + } + }; + + const CTString &GetDescription(void) const { + INDEX ct = GetModelsCount(); + if(ct==0) { + ((CTString&)m_strDescription).PrintF("(%g): no more", m_fHealth); + } else if(ct==1) { + ((CTString&)m_strDescription).PrintF("(%g): %s", m_fHealth, (const char*)m_penModel0->GetName()); + } else if (TRUE) { + ((CTString&)m_strDescription).PrintF("(%g): %s,...(%d)", m_fHealth, (const char*)m_penModel0->GetName(), ct); + } + return m_strDescription; + } + + // check if one model target is valid + void CheckOneModelTarget(CEntityPointer &pen) + { + if (pen!=NULL && !IsOfClass(pen, "ModelHolder2")) { + WarningMessage("Model '%s' is not ModelHolder2!", (const char*)pen->GetName()); + pen=NULL; + } + } + + // get next phase in destruction + class CModelHolder2 *GetNextPhase(void) + { + INDEX ct = GetModelsCount(); + // if not more models + if (ct==0) { + // return none + return NULL; + // if there are some + } else { + // choose by random + return GetModel(IRnd()%ct); + } + } + + // get number of models set by user + INDEX GetModelsCount(void) const + { + // note: only first N that are no NULL are used + if (m_penModel0==NULL) { return 0; }; + if (m_penModel1==NULL) { return 1; }; + if (m_penModel2==NULL) { return 2; }; + if (m_penModel3==NULL) { return 3; }; + if (m_penModel4==NULL) { return 4; }; + return 5; + } + // get model by its index + class CModelHolder2 *GetModel(INDEX iModel) + { + ASSERT(iModel<=GetModelsCount()); + iModel = Clamp(iModel, INDEX(0), GetModelsCount()); + return (CModelHolder2 *)&*(&m_penModel0)[iModel]; + } + // spawn debris for given model + void SpawnDebris(CModelHolder2 *penModel) + { + FLOATaabbox3D box; + penModel->GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + FLOAT fSize = m_fDebrisSize; + switch(m_ddtDebris) { + case DDT_STONE: { + Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(0,0,0), FLOAT3D(0,0,0), 1.0f, 0.0f); + for(INDEX iDebris = 0; iDebrism_vDamage*0.3f, FLOAT3D(0,0,0), 1.0f, 0.0f); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 0, fSize, + FLOAT3D(0.5f, 0.2f, 0.5f)); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 1, fSize, + FLOAT3D(0.5f, 0.3f, 0.5f)); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 2, fSize, + FLOAT3D(0.5f, 0.4f, 0.5f)); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 3, fSize, + FLOAT3D(0.5f, 0.5f, 0.5f)); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 1, fSize, + FLOAT3D(0.5f, 0.6f, 0.5f)); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 2, fSize, + FLOAT3D(0.5f, 0.8f, 0.5f)); + Debris_Spawn(penModel, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 1, fSize, + FLOAT3D(0.5f, 0.9f, 0.5f)); + } break; + default: {} break; + }; + } + +procedures: + Main() + { + // must not allow invalid classes + CheckOneModelTarget(m_penModel0); + CheckOneModelTarget(m_penModel1); + CheckOneModelTarget(m_penModel2); + CheckOneModelTarget(m_penModel3); + CheckOneModelTarget(m_penModel4); + + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MODELDESTRUCTION); + SetModelMainTexture(TEXTURE_MODELDESTRUCTION); + + return; + } +}; + diff --git a/Sources/Entities/ModelHolder.es b/Sources/Entities/ModelHolder.es new file mode 100644 index 0000000..5f2375f --- /dev/null +++ b/Sources/Entities/ModelHolder.es @@ -0,0 +1,176 @@ +203 +%{ +#include "Entities/StdH/StdH.h" +%} + +class CModelHolder : CEntity { +name "ModelHolder"; +thumbnail ""; +features "HasName", "HasDescription"; + +properties: + 1 CTFileName m_fnModel "Model" 'M' =CTFILENAME("Models\\Editor\\Axis.mdl"), + 2 CTFileName m_fnTexture "Texture" 'T' =CTFILENAME("Models\\Editor\\Vector.tex"), + 3 FLOAT m_fStretchAll "StretchAll" 'S' = 1.0f, + 4 FLOAT m_fStretchX "StretchX" 'X' = 1.0f, + 5 FLOAT m_fStretchY "StretchY" 'Y' = 1.0f, + 6 FLOAT m_fStretchZ "StretchZ" 'Z' = 1.0f, + 7 CTString m_strName "Name" 'N' ="", + 12 CTString m_strDescription = "", + 8 BOOL m_bColliding "Colliding" 'C' = FALSE, // set if model is not immatierial + 9 ANIMATION m_iModelAnimation "Model animation" 'A' = 0, + 10 ANIMATION m_iTextureAnimation "Texture animation" = 0, + 11 BOOL m_bClusterShadows "Cluster shadows" = FALSE, // set if model uses cluster shadows + 13 BOOL m_bBackground "Background" = FALSE, // set if model is rendered in background + + // parameters for custom shading of a model (overrides automatic shading calculation) + 14 BOOL m_bCustomShading "Custom shading" 'H' = FALSE, + 15 ANGLE3D m_aShadingDirection "Light direction" = ANGLE3D( AngleDeg(45.0f),AngleDeg(45.0f),AngleDeg(45.0f)), + 16 COLOR m_colLight "Light color" = C_WHITE, + 17 COLOR m_colAmbient "Ambient color" = C_BLACK, + 18 CTFileName m_fnmLightAnimation "Light animation file" = CTString(""), + 19 ANIMATION m_iLightAnimation "Light animation" = 0, + 20 CAnimObject m_aoLightAnimation, +{ + CTFileName m_fnOldModel; // used for remembering last selected model (not saved at all) +} + +components: + +functions: + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + if (slPropertyOffset==offsetof(CModelHolder, m_iModelAnimation)) { + return GetModelObject()->GetData(); + } else if (slPropertyOffset==offsetof(CModelHolder, m_iTextureAnimation)) { + return GetModelObject()->mo_toTexture.GetData(); + } else if (slPropertyOffset==offsetof(CModelHolder, m_iLightAnimation)) { + return m_aoLightAnimation.GetData(); + } else { + return CEntity::GetAnimData(slPropertyOffset); + } + }; + + /* Adjust model shading parameters if needed. */ + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + if (m_bCustomShading) { + // if there is color animation + if (m_aoLightAnimation.GetData()!=NULL) { + // get lerping info + SLONG colFrame0, colFrame1; FLOAT fRatio; + m_aoLightAnimation.GetFrame( colFrame0, colFrame1, fRatio); + UBYTE ubAnimR0, ubAnimG0, ubAnimB0; + UBYTE ubAnimR1, ubAnimG1, ubAnimB1; + ColorToRGB( colFrame0, ubAnimR0, ubAnimG0, ubAnimB0); + ColorToRGB( colFrame1, ubAnimR1, ubAnimG1, ubAnimB1); + + // calculate current animation color + FLOAT fAnimR = NormByteToFloat( Lerp( ubAnimR0, ubAnimR1, fRatio)); + FLOAT fAnimG = NormByteToFloat( Lerp( ubAnimG0, ubAnimG1, fRatio)); + FLOAT fAnimB = NormByteToFloat( Lerp( ubAnimB0, ubAnimB1, fRatio)); + + // decompose constant colors + UBYTE ubLightR, ubLightG, ubLightB; + UBYTE ubAmbientR, ubAmbientG, ubAmbientB; + ColorToRGB( m_colLight, ubLightR, ubLightG, ubLightB); + ColorToRGB( m_colAmbient, ubAmbientR, ubAmbientG, ubAmbientB); + colLight = RGBToColor( ubLightR *fAnimR, ubLightG *fAnimG, ubLightB *fAnimB); + colAmbient = RGBToColor( ubAmbientR*fAnimR, ubAmbientG*fAnimG, ubAmbientB*fAnimB); + + // if there is no color animation + } else { + colLight = m_colLight; + colAmbient = m_colAmbient; + } + + AnglesToDirectionVector(m_aShadingDirection, vLightDirection); + vLightDirection = -vLightDirection; + } + return TRUE; + }; + + /* Init model holder*/ + void InitModelHolder(void) { + // stretch factors must not have extreme values + if (m_fStretchX < 0.01f) { m_fStretchX = 0.01f; } + if (m_fStretchY < 0.01f) { m_fStretchY = 0.01f; } + if (m_fStretchZ < 0.01f) { m_fStretchZ = 0.01f; } + if (m_fStretchAll< 0.01f) { m_fStretchAll = 0.01f; } + if (m_fStretchX >100.0f) { m_fStretchX = 100.0f; } + if (m_fStretchY >100.0f) { m_fStretchY = 100.0f; } + if (m_fStretchZ >100.0f) { m_fStretchZ = 100.0f; } + if (m_fStretchAll>100.0f) { m_fStretchAll = 100.0f; } + + // if initialized for the first time + if (m_fnOldModel=="") { + // just remember the model filename + m_fnOldModel = m_fnModel; + // if re-initialized + } else { + // if the model filename has changed + if (m_fnOldModel != m_fnModel) { + // set texture filename to same as the model filename with texture extension + m_fnTexture = m_fnModel.FileDir()+m_fnModel.FileName()+CTString(".tex"); + // remember the model filename + m_fnOldModel = m_fnModel; + } + } + + InitAsModel(); + if (m_bColliding) { + SetPhysicsFlags(EPF_MODEL_FIXED); + SetCollisionFlags(ECF_MODEL_HOLDER); + } else { + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + } + + if (m_bClusterShadows) { + SetFlags(GetFlags()|ENF_CLUSTERSHADOWS); + } else { + SetFlags(GetFlags()&~ENF_CLUSTERSHADOWS); + } + + if (m_bBackground) { + SetFlags(GetFlags()|ENF_BACKGROUND); + } else { + SetFlags(GetFlags()&~ENF_BACKGROUND); + } + + // set model stretch -- MUST BE DONE BEFORE SETTING MODEL! + GetModelObject()->mo_Stretch = FLOAT3D( + m_fStretchAll*m_fStretchX, + m_fStretchAll*m_fStretchY, + m_fStretchAll*m_fStretchZ); + + // set appearance + SetModel(m_fnModel); + SetModelMainTexture(m_fnTexture); + + GetModelObject()->PlayAnim(m_iModelAnimation, AOF_LOOPING); + GetModelObject()->mo_toTexture.PlayAnim(m_iTextureAnimation, AOF_LOOPING); + + try { + m_aoLightAnimation.SetData_t(m_fnmLightAnimation); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load '%s': %s"), (const char*)(CTString&)m_fnmLightAnimation,(const char*) strError); + m_fnmLightAnimation = ""; + } + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, AOF_LOOPING); + } + + m_strDescription.PrintF("%s,%s", (const char*)m_fnModel.FileName(), (const char*)m_fnTexture.FileName()); + + return; + }; + +procedures: + Main() + { + InitModelHolder(); + return; + } +}; diff --git a/Sources/Entities/ModelHolder2.es b/Sources/Entities/ModelHolder2.es new file mode 100644 index 0000000..f07188a --- /dev/null +++ b/Sources/Entities/ModelHolder2.es @@ -0,0 +1,640 @@ +210 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelDestruction"; +uses "Entities/AnimationChanger"; +uses "Entities/BloodSpray"; + +enum CustomShadingType { + 0 CST_NONE "None", + 1 CST_FULL_CUSTOMIZED "Full customized", + 2 CST_CONSTANT_SHADING "Constant shading" +}; + +enum ShadowType { + 0 ST_NONE "None", + 1 ST_CLUSTER "Cluster shadows", + 2 ST_POLYGONAL "Polygonal" +}; + +class CModelHolder2 : CRationalEntity { +name "ModelHolder2"; +thumbnail "Thumbnails\\ModelHolder.tbn"; +features "HasName", "HasDescription"; + +properties: + 1 CTFileName m_fnModel "Model" 'M' =CTFILENAME("Models\\Editor\\Axis.mdl"), + 2 CTFileName m_fnTexture "Texture" 'T' =CTFILENAME("Models\\Editor\\Vector.tex"), + 22 CTFileName m_fnReflection "Reflection" =CTString(""), + 23 CTFileName m_fnSpecular "Specular" =CTString(""), + 24 CTFileName m_fnBump "Bump" =CTString(""), + 3 FLOAT m_fStretchAll "StretchAll" 'S' = 1.0f, + 4 FLOAT m_fStretchX "StretchX" 'X' = 1.0f, + 5 FLOAT m_fStretchY "StretchY" 'Y' = 1.0f, + 6 FLOAT m_fStretchZ "StretchZ" 'Z' = 1.0f, + 7 CTString m_strName "Name" 'N' ="", + 12 CTString m_strDescription = "", + 8 BOOL m_bColliding "Colliding" 'L' = FALSE, // set if model is not immatierial + 9 ANIMATION m_iModelAnimation "Model animation" = 0, + 10 ANIMATION m_iTextureAnimation "Texture animation" = 0, + 11 enum ShadowType m_stClusterShadows "Shadows" 'W' = ST_CLUSTER, // set if model uses cluster shadows + 13 BOOL m_bBackground "Background" 'B' = FALSE, // set if model is rendered in background + 21 BOOL m_bTargetable "Targetable" = FALSE, // st if model should be targetable + + // parameters for custom shading of a model (overrides automatic shading calculation) + 14 enum CustomShadingType m_cstCustomShading "Custom shading" 'H' = CST_NONE, + 15 ANGLE3D m_aShadingDirection "Light direction" 'D' = ANGLE3D( AngleDeg(45.0f),AngleDeg(45.0f),AngleDeg(45.0f)), + 16 COLOR m_colLight "Light color" 'O' = C_WHITE, + 17 COLOR m_colAmbient "Ambient color" 'A' = C_BLACK, + 18 CTFileName m_fnmLightAnimation "Light animation file" = CTString(""), + 19 ANIMATION m_iLightAnimation "Light animation" = 0, + 20 CAnimObject m_aoLightAnimation, + 25 BOOL m_bAttachments "Attachments" = TRUE, // set if model should auto load attachments + 26 BOOL m_bActive "Active" = TRUE, + 31 FLOAT m_fMipAdd "Mip Add" = 0.0f, + 32 FLOAT m_fMipMul "Mip Mul" = 1.0f, + 33 FLOAT m_fMipFadeDist "Mip Fade Dist" = 0.0f, + 34 FLOAT m_fMipFadeLen "Mip Fade Len" = 0.0f, + + // random values variables + 50 BOOL m_bRandomStretch "Apply RND stretch" = FALSE, // apply random stretch + 52 FLOAT m_fStretchRndX "Stretch RND X (%)" = 0.2f, // random stretch width + 51 FLOAT m_fStretchRndY "Stretch RND Y (%)" = 0.2f, // random stretch height + 53 FLOAT m_fStretchRndZ "Stretch RND Z (%)" = 0.2f, // random stretch depth + 54 FLOAT m_fStretchRndAll "Stretch RND All (%)" = 0.0f, // random stretch all + 55 FLOAT3D m_fStretchRandom = FLOAT3D(1, 1, 1), + + // destruction values + 60 CEntityPointer m_penDestruction "Destruction" 'Q' COLOR(C_BLACK|0x20), // model destruction entity + 61 FLOAT3D m_vDamage = FLOAT3D(0,0,0), // current damage impact + 62 FLOAT m_tmLastDamage = -1000.0f, + 63 CEntityPointer m_penDestroyTarget "Destruction Target" COLOR(C_WHITE|0xFF), // targeted when destroyed + 64 CEntityPointer m_penLastDamager, + 65 FLOAT m_tmSpraySpawned = 0.0f, // time when damage has been applied + 66 FLOAT m_fSprayDamage = 0.0f, // total ammount of damage + 67 CEntityPointer m_penSpray, // the blood spray + 68 FLOAT m_fMaxDamageAmmount = 0.0f, // max ammount of damage recived in in last xxx ticks + + 70 FLOAT m_fClassificationStretch "Classification stretch" = 1.0f, // classification box multiplier +100 FLOAT m_fMaxTessellationLevel "Max tessellation level" = 0.0f, + +{ + CTFileName m_fnOldModel; // used for remembering last selected model (not saved at all) +} + +components: + 1 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + +functions: + void Precache(void) { + PrecacheClass(CLASS_BLOOD_SPRAY, 0); + }; + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = m_fnModel.FileName()+", "+m_fnTexture.FileName(); + pes->es_ctCount = 1; + pes->es_ctAmmount = 1; + if (m_penDestruction!=NULL) { + pes->es_strName += " (destroyable)"; + pes->es_fValue = GetDestruction()->m_fHealth; + pes->es_iScore = 0; + } else { + pes->es_fValue = 0; + pes->es_iScore = 0; + } + return TRUE; + } + + // classification box multiplier + FLOAT3D GetClassificationBoxStretch(void) + { + return FLOAT3D( m_fClassificationStretch, m_fClassificationStretch, m_fClassificationStretch); + } + + + // maximum allowed tessellation level for this model (for Truform/N-Patches support) + FLOAT GetMaxTessellationLevel(void) + { + return m_fMaxTessellationLevel; + } + + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + FLOAT fNewDamage = fDamageAmmount; + + // if not destroyable + if (m_penDestruction==NULL) { + // do nothing + return; + } + CModelDestruction *penDestruction = GetDestruction(); + // adjust damage + fNewDamage *=DamageStrength(penDestruction->m_eibtBodyType, dmtType); + // if no damage + if (fNewDamage==0) { + // do nothing + return; + } + FLOAT fKickDamage = fNewDamage; + if( (dmtType == DMT_EXPLOSION) || (dmtType == DMT_IMPACT) || (dmtType == DMT_CANNONBALL_EXPLOSION) ) + { + fKickDamage*=1.5f; + } + if (dmtType == DMT_CLOSERANGE) { + fKickDamage=0.0f; + } + if(dmtType == DMT_BULLET && penDestruction->m_eibtBodyType==EIBT_ROCK) { + fKickDamage=0.0f; + } + + // get passed time since last damage + TIME tmNow = _pTimer->CurrentTick(); + TIME tmDelta = tmNow-m_tmLastDamage; + m_tmLastDamage = tmNow; + + // remember who damaged you + m_penLastDamager = penInflictor; + + // fade damage out + if (tmDelta>=_pTimer->TickQuantum*3) { + m_vDamage=FLOAT3D(0,0,0); + } + // add new damage + FLOAT3D vDirectionFixed; + if (vDirection.ManhattanNorm()>0.5f) { + vDirectionFixed = vDirection; + } else { + vDirectionFixed = FLOAT3D(0,1,0); + } + FLOAT3D vDamageOld = m_vDamage; + m_vDamage += vDirectionFixed*fKickDamage; + + // NOTE: we don't receive damage here, but handle death differently + if (m_vDamage.Length()>GetHealth()) { + EDeath eDeath; // we don't need any extra parameters + SendEvent(eDeath); + } + + if( m_fMaxDamageAmmountCurrentTick()-_pTimer->TickQuantum*8 || + m_fSprayDamage+fNewDamage>50.0f) { + + // spawn blood spray + CPlacement3D plSpray = CPlacement3D( vHitPoint, ANGLE3D(0, 0, 0)); + m_penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + m_penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + + // adjust spray power + if( m_fMaxDamageAmmount > 10.0f) { + eSpawnSpray.fDamagePower = 3.0f; + } else if(m_fSprayDamage+fNewDamage>50.0f) { + eSpawnSpray.fDamagePower = 2.0f; + } else { + eSpawnSpray.fDamagePower = 1.0f; + } + + // remember spray type + eSpawnSpray.sptType = penDestruction->m_sptType; + eSpawnSpray.fSizeMultiplier = 1.0f; + + // get your down vector (simulates gravity) + FLOAT3D vDn(-en_mRotation(1,2), -en_mRotation(2,2), -en_mRotation(3,2)); + + // setup direction of spray + FLOAT3D vHitPointRelative = vHitPoint - GetPlacement().pl_PositionVector; + FLOAT3D vReflectingNormal; + GetNormalComponent( vHitPointRelative, vDn, vReflectingNormal); + vReflectingNormal.Normalize(); + + vReflectingNormal(1)/=5.0f; + + FLOAT3D vProjectedComponent = vReflectingNormal*(vDirection%vReflectingNormal); + FLOAT3D vSpilDirection = vDirection-vProjectedComponent*2.0f-vDn*0.5f; + + eSpawnSpray.vDirection = vSpilDirection; + eSpawnSpray.penOwner = this; + + // initialize spray + m_penSpray->Initialize( eSpawnSpray); + m_tmSpraySpawned = _pTimer->CurrentTick(); + m_fSprayDamage = 0.0f; + m_fMaxDamageAmmount = 0.0f; + } + m_fSprayDamage+=fNewDamage; + }; + + class CModelDestruction *GetDestruction(void) + { + ASSERT(m_penDestruction!=NULL && IsOfClass(m_penDestruction, "ModelDestruction")); + return (CModelDestruction*)&*m_penDestruction; + } + BOOL IsTargetable(void) const + { + return m_bTargetable; + } + + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + if (slPropertyOffset==offsetof(CModelHolder2, m_iModelAnimation)) { + return GetModelObject()->GetData(); + } else if (slPropertyOffset==offsetof(CModelHolder2, m_iTextureAnimation)) { + return GetModelObject()->mo_toTexture.GetData(); + } else if (slPropertyOffset==offsetof(CModelHolder2, m_iLightAnimation)) { + return m_aoLightAnimation.GetData(); + } else { + return CEntity::GetAnimData(slPropertyOffset); + } + }; + + /* Adjust model mip factor if needed. */ + void AdjustMipFactor(FLOAT &fMipFactor) + { + // if should fade last mip + if (m_fMipFadeDist>0) { + CModelObject *pmo = GetModelObject(); + if(pmo==NULL) { + return; + } + // adjust for stretch + FLOAT fMipForFade = fMipFactor; + if (pmo->mo_Stretch != FLOAT3D(1,1,1)) { + fMipForFade -= Log2( Max(pmo->mo_Stretch(1),Max(pmo->mo_Stretch(2),pmo->mo_Stretch(3)))); + } + + // if not visible + if (fMipForFade>m_fMipFadeDist) { + // set mip factor so that model is never rendered + fMipFactor = UpperLimit(0.0f); + return; + } + + // adjust fading + FLOAT fFade = (m_fMipFadeDist-fMipForFade); + if (m_fMipFadeLen>0) { + fFade/=m_fMipFadeLen; + } else { + if (fFade>0) { + fFade = 1.0f; + } + } + + fFade = Clamp(fFade, 0.0f, 1.0f); + // make it invisible + pmo->mo_colBlendColor = (pmo->mo_colBlendColor&~255)|UBYTE(255*fFade); + } + + fMipFactor = fMipFactor*m_fMipMul+m_fMipAdd; + } + + /* Adjust model shading parameters if needed. */ + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + switch( m_cstCustomShading) + { + case CST_FULL_CUSTOMIZED: + { + // if there is color animation + if (m_aoLightAnimation.GetData()!=NULL) { + // get lerping info + SLONG colFrame0, colFrame1; FLOAT fRatio; + m_aoLightAnimation.GetFrame( colFrame0, colFrame1, fRatio); + UBYTE ubAnimR0, ubAnimG0, ubAnimB0; + UBYTE ubAnimR1, ubAnimG1, ubAnimB1; + ColorToRGB( colFrame0, ubAnimR0, ubAnimG0, ubAnimB0); + ColorToRGB( colFrame1, ubAnimR1, ubAnimG1, ubAnimB1); + + // calculate current animation color + FLOAT fAnimR = NormByteToFloat( Lerp( ubAnimR0, ubAnimR1, fRatio)); + FLOAT fAnimG = NormByteToFloat( Lerp( ubAnimG0, ubAnimG1, fRatio)); + FLOAT fAnimB = NormByteToFloat( Lerp( ubAnimB0, ubAnimB1, fRatio)); + + // decompose constant colors + UBYTE ubLightR, ubLightG, ubLightB; + UBYTE ubAmbientR, ubAmbientG, ubAmbientB; + ColorToRGB( m_colLight, ubLightR, ubLightG, ubLightB); + ColorToRGB( m_colAmbient, ubAmbientR, ubAmbientG, ubAmbientB); + colLight = RGBToColor( ubLightR *fAnimR, ubLightG *fAnimG, ubLightB *fAnimB); + colAmbient = RGBToColor( ubAmbientR*fAnimR, ubAmbientG*fAnimG, ubAmbientB*fAnimB); + + // if there is no color animation + } else { + colLight = m_colLight; + colAmbient = m_colAmbient; + } + + AnglesToDirectionVector(m_aShadingDirection, vLightDirection); + vLightDirection = -vLightDirection; + break; + } + case CST_CONSTANT_SHADING: + { + // combine colors with clamp + UBYTE lR,lG,lB,aR,aG,aB,rR,rG,rB; + ColorToRGB( colLight, lR, lG, lB); + ColorToRGB( colAmbient, aR, aG, aB); + colLight = 0; + rR = (UBYTE) Clamp( (ULONG)lR+aR, (ULONG)0, (ULONG)255); + rG = (UBYTE) Clamp( (ULONG)lG+aG, (ULONG)0, (ULONG)255); + rB = (UBYTE) Clamp( (ULONG)lB+aB, (ULONG)0, (ULONG)255); + colAmbient = RGBToColor( rR, rG, rB); + break; + } + case CST_NONE: + { + // do nothing + break; + } + } + + return m_stClusterShadows!=ST_NONE; + }; + + // apply mirror and stretch to the entity + void MirrorAndStretch(FLOAT fStretch, BOOL bMirrorX) + { + m_fStretchAll*=fStretch; + if (bMirrorX) { + m_fStretchX = -m_fStretchX; + } + } + + // Stretch model + void StretchModel(void) { + // stretch factors must not have extreme values + if (Abs(m_fStretchX) < 0.01f) { m_fStretchX = 0.01f; } + if (Abs(m_fStretchY) < 0.01f) { m_fStretchY = 0.01f; } + if (Abs(m_fStretchZ) < 0.01f) { m_fStretchZ = 0.01f; } + if (m_fStretchAll< 0.01f) { m_fStretchAll = 0.01f; } + + if (Abs(m_fStretchX) >100.0f) { m_fStretchX = 100.0f*Sgn(m_fStretchX); } + if (Abs(m_fStretchY) >100.0f) { m_fStretchY = 100.0f*Sgn(m_fStretchY); } + if (Abs(m_fStretchZ) >100.0f) { m_fStretchZ = 100.0f*Sgn(m_fStretchZ); } + if (m_fStretchAll>100.0f) { m_fStretchAll = 100.0f; } + + if (m_bRandomStretch) { + m_bRandomStretch = FALSE; + // stretch + m_fStretchRndX = Clamp( m_fStretchRndX , 0.0f, 1.0f); + m_fStretchRndY = Clamp( m_fStretchRndY , 0.0f, 1.0f); + m_fStretchRndZ = Clamp( m_fStretchRndZ , 0.0f, 1.0f); + m_fStretchRndAll = Clamp( m_fStretchRndAll , 0.0f, 1.0f); + + m_fStretchRandom(1) = (FRnd()*m_fStretchRndX*2 - m_fStretchRndX) + 1; + m_fStretchRandom(2) = (FRnd()*m_fStretchRndY*2 - m_fStretchRndY) + 1; + m_fStretchRandom(3) = (FRnd()*m_fStretchRndZ*2 - m_fStretchRndZ) + 1; + + FLOAT fRNDAll = (FRnd()*m_fStretchRndAll*2 - m_fStretchRndAll) + 1; + m_fStretchRandom(1) *= fRNDAll; + m_fStretchRandom(2) *= fRNDAll; + m_fStretchRandom(3) *= fRNDAll; + } + + GetModelObject()->StretchModel( FLOAT3D( + m_fStretchAll*m_fStretchX*m_fStretchRandom(1), + m_fStretchAll*m_fStretchY*m_fStretchRandom(2), + m_fStretchAll*m_fStretchZ*m_fStretchRandom(3)) ); + ModelChangeNotify(); + }; + + /* Init model holder*/ + void InitModelHolder(void) { + + // must not crash when model is removed + if (m_fnModel=="") { + m_fnModel=CTFILENAME("Models\\Editor\\Axis.mdl"); + } + + if( m_fnReflection == CTString("Models\\Editor\\Vector.tex")) { + m_fnReflection = CTString(""); + } + if( m_fnSpecular == CTString("Models\\Editor\\Vector.tex")) { + m_fnSpecular = CTString(""); + } + if( m_fnBump == CTString("Models\\Editor\\Vector.tex")) { + m_fnBump = CTString(""); + } + + if (m_bActive) { + InitAsModel(); + } else { + InitAsEditorModel(); + } + // set appearance + SetModel(m_fnModel); + GetModelObject()->PlayAnim(m_iModelAnimation, AOF_LOOPING); + + // if initialized for the first time + if (m_fnOldModel=="") { + // just remember the model filename + m_fnOldModel = m_fnModel; + // if re-initialized + } else { + // if the model filename has changed + if (m_fnOldModel != m_fnModel) { + m_fnOldModel = m_fnModel; + GetModelObject()->AutoSetTextures(); + m_fnTexture = GetModelObject()->mo_toTexture.GetName(); + m_fnReflection = GetModelObject()->mo_toReflection.GetName(); + m_fnSpecular = GetModelObject()->mo_toSpecular.GetName(); + m_fnBump = GetModelObject()->mo_toBump.GetName(); + } + } + + if( m_bAttachments) + { + GetModelObject()->AutoSetAttachments(); + } + else + { + GetModelObject()->RemoveAllAttachmentModels(); + } + + try + { + GetModelObject()->mo_toTexture.SetData_t(m_fnTexture); + GetModelObject()->mo_toTexture.PlayAnim(m_iTextureAnimation, AOF_LOOPING); + GetModelObject()->mo_toReflection.SetData_t(m_fnReflection); + GetModelObject()->mo_toSpecular.SetData_t(m_fnSpecular); + GetModelObject()->mo_toBump.SetData_t(m_fnBump); + } catch (char *strError) { + WarningMessage(strError); + } + + // set model stretch + StretchModel(); + ModelChangeNotify(); + + if (m_bColliding) { + SetPhysicsFlags(EPF_MODEL_FIXED); + SetCollisionFlags(ECF_MODEL_HOLDER); + } else { + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + } + + switch(m_stClusterShadows) { + case ST_NONE: + { + SetFlags(GetFlags()&~ENF_CLUSTERSHADOWS); + //SetFlags(GetFlags()&~ENF_POLYGONALSHADOWS); + break; + } + case ST_CLUSTER: + { + SetFlags(GetFlags()|ENF_CLUSTERSHADOWS); + //SetFlags(GetFlags()&~ENF_POLYGONALSHADOWS); + break; + } + case ST_POLYGONAL: + { + //SetFlags(GetFlags()|ENF_POLYGONALSHADOWS); + SetFlags(GetFlags()&~ENF_CLUSTERSHADOWS); + break; + } + } + + if (m_bBackground) { + SetFlags(GetFlags()|ENF_BACKGROUND); + } else { + SetFlags(GetFlags()&~ENF_BACKGROUND); + } + + try { + m_aoLightAnimation.SetData_t(m_fnmLightAnimation); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load '%s': %s"), (const char*)(CTString&)m_fnmLightAnimation,(const char*) strError); + m_fnmLightAnimation = ""; + } + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, AOF_LOOPING); + } + + if (m_penDestruction==NULL) { + m_strDescription.PrintF("%s,%s undestroyable", (const char*)m_fnModel.FileName(), (const char*)m_fnTexture.FileName()); + } else { + m_strDescription.PrintF("%s,%s -> %s", (const char*)m_fnModel.FileName(), (const char*)m_fnTexture.FileName(), + (const char*)m_penDestruction->GetName()); + } + + return; + }; + +procedures: + Die() + { + // for each child of this entity + {FOREACHINLIST(CEntity, en_lnInParent, en_lhChildren, itenChild) { + // send it destruction event + itenChild->SendEvent(ERangeModelDestruction()); + }} + + // spawn debris + GetDestruction()->SpawnDebris(this); + // if there is another phase in destruction + CModelHolder2 *penNext = GetDestruction()->GetNextPhase(); + if (penNext!=NULL) { + // copy it here + CEntity *penNew = GetWorld()->CopyEntityInWorld( *penNext, GetPlacement() ); + penNew->GetModelObject()->StretchModel(GetModelObject()->mo_Stretch); + penNew->ModelChangeNotify(); + } + +/* currently, environment destruction does not yield score. + update statistics, if score is re-enabled! + // send score to who killed you + if (m_penLastDamager!=NULL) { + EReceiveScore eScore; + eScore.fPoints = 10.0f; + m_penLastDamager->SendEvent(eScore); + }*/ + + // if there is a destruction target + if (m_penDestroyTarget!=NULL) { + // notify it + SendToTarget(m_penDestroyTarget, EET_TRIGGER, m_penLastDamager); + } + + // destroy yourself + Destroy(); + return; + } + Main() + { + // initialize the model + InitModelHolder(); + + // check your destruction pointer + if (m_penDestruction!=NULL && !IsOfClass(m_penDestruction, "ModelDestruction")) { + WarningMessage("Destruction '%s' is wrong class!",(const char*) m_penDestruction->GetName()); + m_penDestruction=NULL; + } + + // wait forever + wait() { + // on the beginning + on(EBegin): { + // set your health + if (m_penDestruction!=NULL) { + SetHealth(GetDestruction()->m_fHealth); + } + resume; + } + // activate/deactivate shows/hides model + on (EActivate): { + SwitchToModel(); + m_bActive = TRUE; + resume; + } + on (EDeactivate): { + SwitchToEditorModel(); + m_bActive = FALSE; + resume; + } + // when your parent is destroyed + on(ERangeModelDestruction): { + // destroy yourself + Destroy(); + resume; + } + // when dead + on(EDeath): { + if (m_penDestruction!=NULL) { + jump Die(); + } + resume; + } + // when animation should be changed + on(EChangeAnim eChange): { + m_iModelAnimation = eChange.iModelAnim; + m_iTextureAnimation = eChange.iTextureAnim; + m_iLightAnimation = eChange.iLightAnim; + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(m_iLightAnimation, eChange.bLightLoop?AOF_LOOPING:0); + } + if (GetModelObject()->GetData()!=NULL) { + GetModelObject()->PlayAnim(m_iModelAnimation, eChange.bModelLoop?AOF_LOOPING:0); + } + if (GetModelObject()->mo_toTexture.GetData()!=NULL) { + GetModelObject()->mo_toTexture.PlayAnim(m_iTextureAnimation, eChange.bTextureLoop?AOF_LOOPING:0); + } + resume; + } + otherwise(): { + resume; + } + }; + } +}; diff --git a/Sources/Entities/MovingBrush.es b/Sources/Entities/MovingBrush.es new file mode 100644 index 0000000..b254449 --- /dev/null +++ b/Sources/Entities/MovingBrush.es @@ -0,0 +1,848 @@ +101 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/MovingBrushMarker"; +uses "Entities/SoundHolder"; +uses "Entities/MirrorMarker"; +uses "Entities/Debris"; + +event EHit { +}; +event EBrushDestroyed { // sent to all children of a moving brush when it is destroyed +}; + +enum BlockAction { + 0 BA_NONE "None", // continue moving + 1 BA_BOUNCE "Bounce", // bounce when obstructed + 2 BA_SKIPMARKER "Skip marker", // skip moving to next marker +}; + +enum TouchOrDamageEvent { + 0 TDE_TOUCHONLY "Touch Only", + 1 TDE_DAMAGEONLY "Damage Only", + 2 TDE_BOTH "Both", +}; + +%{ +static const float TRANSLATION_EPSILON=0.05f; +static const float ROTATION_EPSILON=0.05f; +extern void GetDefaultForce(INDEX iForce, const FLOAT3D &vPoint, + CForceStrength &fsGravity, CForceStrength &fsField); +%} + +class CMovingBrush : CMovableBrushEntity { +name "Moving Brush"; +thumbnail "Thumbnails\\MovingBrush.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Moving Brush", + 2 CTString m_strDescription = "", + + 3 CEntityPointer m_penTarget "Target" 'T' COLOR(C_BLUE|0xFF), + 4 BOOL m_bAutoStart "Auto start" 'A' = FALSE, + 5 FLOAT m_fSpeed "Speed" 'S' = 1.0f, + 6 FLOAT m_fWaitTime "Wait time" 'W' = 0.0f, + 7 BOOL m_bMoveOnTouch "Move on touch" 'M' = FALSE, + 8 enum BlockAction m_ebaAction "Block action" 'B' = BA_NONE, + 9 FLOAT m_fBlockDamage "Block damage" 'D' = 10.0f, + 10 BOOL m_bPlayersOnly "Players Only" 'P' = TRUE, + 11 BOOL m_bDynamicShadows "Dynamic shadows" = FALSE, + 12 BOOL m_bVeryBigBrush "Very Big Brush" = FALSE, + + // send event on touch + 13 enum EventEType m_eetTouchEvent "Touch Event - Type" 'U' = EET_IGNORE, // type of event to send + 14 CEntityPointer m_penTouchEvent "Touch Event - Target" 'I' COLOR(C_dCYAN|0xFF), // target to send event to + 19 enum TouchOrDamageEvent m_tdeSendEventOnDamage "Send touch event on damage" = TDE_TOUCHONLY, + + 15 CEntityPointer m_penSwitch "Switch", // for switch relaying + + // send event on marker + 16 enum EventEType m_eetMarkerEvent = EET_IGNORE, + 17 CEntityPointer m_penMarkerEvent, + + // rotation + 18 FLOAT m_tmBankingRotation "Banking rotation speed" = 0.0f, // set if only banking rotation + + // class properties + 20 BOOL m_bMoving = FALSE, // the brush is moving + 21 FLOAT3D m_vDesiredTranslation = FLOAT3D(0,0,0), // desired translation + 22 ANGLE3D m_aDesiredRotation = FLOAT3D(0,0,0), // desired rotation + 23 BOOL m_bInverseRotate = FALSE, // use inverse rotation to target + 24 BOOL m_bStopMoving = FALSE, // stop moving brush on next target + 25 BOOL m_bMoveToMarker = FALSE, // PerMoving acknowledge od brush moving + 26 BOOL m_bSkipMarker = FALSE, // when obstructed skip next marker (actually stop moving) + 27 BOOL m_bValidMarker = FALSE, // internal for moving through valid markers + + // moving limits + 30 FLOAT m_fXLimitSign = 0.0f, + 31 FLOAT m_fYLimitSign = 0.0f, + 32 FLOAT m_fZLimitSign = 0.0f, + 33 ANGLE m_aHLimitSign = 0.0f, + 34 ANGLE m_aPLimitSign = 0.0f, + 35 ANGLE m_aBLimitSign = 0.0f, + + // continuous speed change + 40 FLOAT3D m_vStartTranslation = FLOAT3D(0,0,0), // start translation + 41 ANGLE3D m_aStartRotation = ANGLE3D(0,0,0), // start rotation + 42 FLOAT m_fCourseLength = 0.0f, // course length + 43 ANGLE m_aHeadLenght = 0.0f, // head lenght + 44 ANGLE m_aPitchLenght = 0.0f, // pitch lenght + 45 ANGLE m_aBankLenght = 0.0f, // bank lenght + + // sound target + 50 CEntityPointer m_penSoundStart "Sound start entity" 'Q', // sound start entity + 51 CEntityPointer m_penSoundStop "Sound stop entity" 'Z', // sound stop entity + 52 CEntityPointer m_penSoundFollow "Sound follow entity" 'F', // sound follow entity + 53 CSoundObject m_soStart, + 54 CSoundObject m_soStop, + 55 CSoundObject m_soFollow, + + + 60 CEntityPointer m_penMirror0 "Mirror 0" 'M', + 61 CEntityPointer m_penMirror1 "Mirror 1", + 62 CEntityPointer m_penMirror2 "Mirror 2", + 63 CEntityPointer m_penMirror3 "Mirror 3", + 64 CEntityPointer m_penMirror4 "Mirror 4", + + 65 FLOAT m_fHealth "Health" 'H' = -1.0f, + 66 BOOL m_bBlowupByBull "Blowup by Bull" = FALSE, // special feature for bull crushing doors + // send event on touch + 67 enum EventEType m_eetBlowupEvent "Blowup Event - Type" = EET_IGNORE, // type of event to send + 68 CEntityPointer m_penBlowupEvent "Blowup Event - Target" COLOR(C_BLACK|0xFF), // target to send event to + 69 BOOL m_bZoning "Zoning" 'Z' =FALSE, + 70 BOOL m_bMoveOnDamage "Move on damage" = FALSE, // move when recive damage + 71 FLOAT m_fTouchDamage "Touch damage" = 0.0f, + 72 COLOR m_colDebrises "Color of debrises" = C_WHITE, + 74 INDEX m_ctDebrises "Debris count" = 12, + 75 FLOAT m_fCandyEffect "Debris blow power" = 0.0f, + 76 FLOAT m_fCubeFactor "Cube factor" = 1.0f, + 77 BOOL m_bBlowupByDamager "Blowup by Damager" = FALSE, // if only damager can destroy brush + +components: +// ************** STONE PARTS ************** + 14 model MODEL_STONE "Models\\Effects\\Debris\\Stone\\Stone.mdl", + 15 texture TEXTURE_STONE "Models\\Effects\\Debris\\Stone\\Stone.tex", + 16 class CLASS_DEBRIS "Classes\\Debris.ecl", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", +functions: + void Precache(void) + { + PrecacheClass(CLASS_DEBRIS); + PrecacheModel(MODEL_STONE); + PrecacheTexture(TEXTURE_STONE); + } + /* Get force in given point. */ + void GetForce(INDEX iForce, const FLOAT3D &vPoint, + CForceStrength &fsGravity, CForceStrength &fsField) + { + GetDefaultForce(iForce, vPoint, fsGravity, fsField); + } + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + if( m_bMoveOnDamage) + { + EHit eHit; + SendEvent( eHit); + return; + } + + // send event on damage + if(m_tdeSendEventOnDamage!=TDE_TOUCHONLY && CanReactOnEntity(penInflictor)) { + SendToTarget(m_penTouchEvent, m_eetTouchEvent, penInflictor); + } + + // if not destroyable + if(m_fHealth<0) { + // ignore damages + return; + } + + // if special feature for bull crushing doors + if (m_bBlowupByBull) + { + // if impact by bull + if( dmtType == DMT_IMPACT && IsOfClass(penInflictor, "Werebull")) + { + // recieve the damage so large to blowup + CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, m_fHealth*2, vHitPoint, vDirection); + // kill the bull in place, but make sure it doesn't blow up + ((CLiveEntity*)penInflictor)->SetHealth(0.0f); + InflictDirectDamage(penInflictor, this, DMT_IMPACT, 1.0f, + GetPlacement().pl_PositionVector, FLOAT3D(0,1,0)); + } + } + else if(m_bBlowupByDamager) + { + if( dmtType == DMT_DAMAGER) + { + CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + } + else + { + // react only on explosions + if( (dmtType == DMT_EXPLOSION) || + (dmtType == DMT_PROJECTILE) || + (dmtType == DMT_CANNONBALL) ) + { + CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + } + }; + + // adjust angle + void AdjustAngle(ANGLE &a) { + if (m_bInverseRotate) { + if (a>0) { a = a - 360; } + else if (a<0) { a = 360 + a; } + } + }; + + + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\MovingBrushMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s", (const char*)m_penTarget->GetName()); + } + return m_strDescription; + } + /* Get mirror type name, return empty string if not used. */ + const CTString &GetMirrorName(INDEX iMirror) + { + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + if (iMirror==0) { + return strDummyName; + } + + switch (iMirror) { + case 1: { static const CTString str("std mirror 1"); return str; }; break; + case 2: { static const CTString str("std mirror 2"); return str; }; break; + case 3: { static const CTString str("std mirror 3"); return str; }; break; + case 4: { static const CTString str("std mirror 4"); return str; }; break; + case 5: { static const CTString str("std mirror 5"); return str; }; break; + case 6: { static const CTString str("std mirror 6"); return str; }; break; + case 7: { static const CTString str("std mirror 7"); return str; }; break; + case 8: { static const CTString str("std mirror 8"); return str; }; break; + default: { + iMirror-=9; + INDEX ctMirrorMarkers = &m_penMirror4-&m_penMirror0; + if (iMirrorGetMirrorName(); + } else { + return strMarkerUnused; + } + } + } + } + return strDummyName; + } + + /* Get mirror, return FALSE for none. */ + BOOL GetMirror(INDEX iMirror, class CMirrorParameters &mpMirror) + { + if (iMirror==0) { + return FALSE; + } + if (iMirror>=1 && iMirror<=8) { + mpMirror.mp_ulFlags = 0; + return TRUE; + } + iMirror-=9; + INDEX ctMirrorMarkers = &m_penMirror4-&m_penMirror0; + if (iMirrorGetMirror(mpMirror); + return TRUE; + } + } + return FALSE; + } + + // pre moving + void PreMoving() { + if (m_bMoveToMarker) { + const FLOAT3D &vTarget = m_penTarget->GetPlacement().pl_PositionVector; + const ANGLE3D &aTarget = m_penTarget->GetPlacement().pl_OrientationAngle; + const FLOAT3D &vSource = GetPlacement().pl_PositionVector; + const ANGLE3D &aSource = GetPlacement().pl_OrientationAngle; + + // translation + FLOAT3D vSpeed = (vTarget-vSource)/_pTimer->TickQuantum; + // X axis + if (Abs(vSpeed(1))0) { + vSpeed(1) = m_vDesiredTranslation(1); + } + // Y axis + if (Abs(vSpeed(2))0) { + vSpeed(2) = m_vDesiredTranslation(2); + } + // Z axis + if (Abs(vSpeed(3))0) { + vSpeed(3) = m_vDesiredTranslation(3); + } + + // rotation + ANGLE3D aSpeed; + aSpeed(1) = NormalizeAngle(aTarget(1)-aSource(1)); // normalize angle + AdjustAngle(aSpeed(1)); // adjust angle (inverse rotation) + aSpeed(1) = Abs(aSpeed(1)) * m_aHLimitSign; // set sign (direction) + aSpeed(1) /= _pTimer->TickQuantum; // transform to tick speed + aSpeed(2) = NormalizeAngle(aTarget(2)-aSource(2)); + AdjustAngle(aSpeed(2)); + aSpeed(2) = Abs(aSpeed(2)) * m_aPLimitSign; + aSpeed(2) /= _pTimer->TickQuantum; + aSpeed(3) = NormalizeAngle(aTarget(3)-aSource(3)); + AdjustAngle(aSpeed(3)); + aSpeed(3) = Abs(aSpeed(3)) * m_aBLimitSign; + aSpeed(3) /= _pTimer->TickQuantum; + // Heading + if (Abs(aSpeed(1))0) { + aSpeed(1) = m_aDesiredRotation(1); + } + // Pitch + if (Abs(aSpeed(2))0) { + aSpeed(2) = m_aDesiredRotation(2); + } + // Banking + if (Abs(aSpeed(3))0) { + aSpeed(3) = m_aDesiredRotation(3); + } + + // stop moving ? + if (vSpeed(1)==0.0f && vSpeed(2)==0.0f && vSpeed(3)==0.0f && + aSpeed(1)==0.0f && aSpeed(2)==0.0f && aSpeed(3)==0.0f) { + // stop brush + ForceFullStop(); + // stop PreMoving check + m_bMoveToMarker = FALSE; + // this EEnd event will end MoveToMarker autowait() and return to MoveBrush + SendEvent(EEnd()); + + // move brush + } else { + SetDesiredTranslation(vSpeed); + SetDesiredRotation(aSpeed); + } + + } + CMovableBrushEntity::PreMoving(); + }; + + + // load marker parameters + BOOL LoadMarkerParameters() { + if (m_penTarget==NULL) { + return FALSE; + } + + if (!IsOfClass(m_penTarget, "Moving Brush Marker")) { + WarningMessage("Entity '%s' is not of Moving Brush Marker class!", (const char*)m_penTarget->GetName()); + return FALSE; + } + + CMovingBrushMarker &mbm = (CMovingBrushMarker&) *m_penTarget; + if (mbm.m_penTarget==NULL) { + return FALSE; + } + + // speed + if (mbm.m_fSpeed > 0.0f) { m_fSpeed = mbm.m_fSpeed; } + + // wait time + if (mbm.m_fWaitTime >= 0.0f) { m_fWaitTime = mbm.m_fWaitTime; } + + // inverse rotate + m_bInverseRotate = mbm.m_bInverseRotate; + + // move on touch + SetBoolFromBoolEType(m_bMoveOnTouch, mbm.m_betMoveOnTouch); + + // stop moving + m_bStopMoving = mbm.m_bStopMoving; + + // block damage + if (mbm.m_fBlockDamage >= 0.0f) { + m_fBlockDamage = mbm.m_fBlockDamage; + } + + // touch event + if (mbm.m_penTouchEvent != NULL) { + m_penTouchEvent = mbm.m_penTouchEvent; + m_eetTouchEvent = mbm.m_eetTouchEvent; + } + + // marker event -> SEND ALWAYS (if target is valid) !!! + SendToTarget(mbm.m_penMarkerEvent, mbm.m_eetMarkerEvent); + + // sound entity + if (mbm.m_penSoundStart!=NULL) { + m_penSoundStart = mbm.m_penSoundStart; + } + if (mbm.m_penSoundStop!=NULL) { + m_penSoundStop = mbm.m_penSoundStop; + } + if (mbm.m_penSoundFollow!=NULL) { + m_penSoundFollow = mbm.m_penSoundFollow; + } + + return TRUE; + }; + + + // test if this door reacts on this entity + BOOL CanReactOnEntity(CEntity *pen) + { + if (pen==NULL) { + return FALSE; + } + // never react on non-live or dead entities + if (!(pen->GetFlags()&ENF_ALIVE)) { + return FALSE; + } + + if (m_bPlayersOnly && !IsDerivedFromClass(pen, "Player")) { + return FALSE; + } + + return TRUE; + } + + // play start sound + void PlayStartSound(void) { + // if sound entity exists + if (m_penSoundStart!=NULL) { + CSoundHolder &sh = (CSoundHolder&)*m_penSoundStart; + m_soStart.Set3DParameters(FLOAT(sh.m_rFallOffRange), FLOAT(sh.m_rHotSpotRange), sh.m_fVolume, 1.0f); + PlaySound(m_soStart, sh.m_fnSound, sh.m_iPlayType); + } + }; + + // play stop sound + void PlayStopSound(void) { + // if sound entity exists + if (m_penSoundStop!=NULL) { + CSoundHolder &sh = (CSoundHolder&)*m_penSoundStop; + m_soStop.Set3DParameters(FLOAT(sh.m_rFallOffRange), FLOAT(sh.m_rHotSpotRange), sh.m_fVolume, 1.0f); + PlaySound(m_soStop, sh.m_fnSound, sh.m_iPlayType); + } + }; + + // play follow sound + void PlayFollowSound(void) { + // if sound entity exists + if (m_penSoundFollow!=NULL) { + CSoundHolder &sh = (CSoundHolder&)*m_penSoundFollow; + m_soFollow.Set3DParameters(FLOAT(sh.m_rFallOffRange), FLOAT(sh.m_rHotSpotRange), sh.m_fVolume, 1.0f); + PlaySound(m_soFollow, sh.m_fnSound, sh.m_iPlayType); + } + }; + + // stop follow sound + void StopFollowSound(void) { + m_soFollow.Stop(); + }; + + + void MovingOn(void) + { + if (m_bMoving) { + return; + } + if (m_bVeryBigBrush) { + SetCollisionFlags(ECF_BRUSH|ECF_IGNOREMODELS); + } + m_bMoving = TRUE; + } + void MovingOff(void) + { + if (!m_bMoving) { + return; + } + if (m_bVeryBigBrush) { + SetCollisionFlags(ECF_BRUSH); + } + m_bMoving = FALSE; + } + + +procedures: + MoveToMarker() { + // move to target + const FLOAT3D &vTarget = m_penTarget->GetPlacement().pl_PositionVector; + const ANGLE3D &aTarget = m_penTarget->GetPlacement().pl_OrientationAngle; + const FLOAT3D &vSource = GetPlacement().pl_PositionVector; + const ANGLE3D &aSource = GetPlacement().pl_OrientationAngle; + + // set new translation + m_vDesiredTranslation = (vTarget-vSource)/m_fSpeed; + m_fXLimitSign = Sgn(vTarget(1)-vSource(1)); + m_fYLimitSign = Sgn(vTarget(2)-vSource(2)); + m_fZLimitSign = Sgn(vTarget(3)-vSource(3)); + + // set new rotation + // heading + ANGLE aDelta = NormalizeAngle(aTarget(1)-aSource(1)); + AdjustAngle(aDelta); + m_aDesiredRotation(1) = aDelta/m_fSpeed; + m_aHLimitSign = Sgn(aDelta); + // pitch + aDelta = NormalizeAngle(aTarget(2)-aSource(2)); + AdjustAngle(aDelta); + m_aDesiredRotation(2) = aDelta/m_fSpeed; + m_aPLimitSign = Sgn(aDelta); + // banking + aDelta = NormalizeAngle(aTarget(3)-aSource(3)); + AdjustAngle(aDelta); + m_aDesiredRotation(3) = aDelta/m_fSpeed; + m_aBLimitSign = Sgn(aDelta); + + // start moving + m_bMoveToMarker = TRUE; + SetDesiredTranslation(m_vDesiredTranslation); + SetDesiredRotation(m_aDesiredRotation); + + // DoMoving will send EEnd event to end + wait() { + on (EBegin) : { resume; } + on (EStop) : { + SetCollisionFlags(ECF_IMMATERIAL); + resume; + } + // move is obstructed + on (EBlock eBlock) : { + // inflict damage to entity that block brush + InflictDirectDamage(eBlock.penOther, this, DMT_BRUSH, m_fBlockDamage, + FLOAT3D(0.0f,0.0f,0.0f), (FLOAT3D &)eBlock.plCollision); + if (m_ebaAction == BA_BOUNCE) { + // change direction for two ticks + SetDesiredTranslation(-m_vDesiredTranslation); + SetDesiredRotation(-m_aDesiredRotation); + // wait for two ticks and reset direction + call BounceObstructed(); + } else if (m_ebaAction == BA_SKIPMARKER) { + // stop moving brush + ForceFullStop(); + // stop PreMoving check + m_bMoveToMarker = FALSE; + // skip this marker and move to next one + m_bSkipMarker = TRUE; + return EEnd(); + } + resume; + } + } + } + + BounceObstructed() { + autowait(0.2f); + // return to standard direction + SetDesiredTranslation(m_vDesiredTranslation); + SetDesiredRotation(m_aDesiredRotation); + return; + } + + Rotating() + { + if (m_bAutoStart) { + jump RotActive(); + } else { + jump RotInactive(); + } + } + + RotInactive() + { + SetDesiredRotation(ANGLE3D(0,0,0)); + wait() { + on (EActivate) : { + jump RotActive(); + } + otherwise() : { + resume; + } + }; + } + + RotActive() + { + SetDesiredRotation(ANGLE3D(0,0,360.0f/m_tmBankingRotation)); + + wait() { + on (EDeactivate) : { + jump RotInactive(); + } + otherwise() : { + resume; + } + }; + } + + // move brush + MoveBrush() + { + if (m_penTarget==NULL) { + MovingOff(); + return; + } + + MovingOn(); + + // move through markers + do { + // new moving target + m_penTarget = m_penTarget->GetTarget(); + + if (m_penTarget==NULL) { + MovingOff(); + return EVoid(); + } + + // skip this marker / ignore wait time + if (m_bSkipMarker) { + m_bSkipMarker = FALSE; + // wait for a while + } else if (m_fWaitTime > 0.0f) { + autowait(m_fWaitTime); + } + + PlayStartSound(); + PlayFollowSound(); + autocall MoveToMarker() EEnd; + StopFollowSound(); + PlayStopSound(); + + // load marker parameters or stop moving if there is no marker + m_bValidMarker = LoadMarkerParameters(); + + // skip this marker / ignore stop moving + if (m_bSkipMarker) { + m_bStopMoving = FALSE; + } + } while (!m_bStopMoving && m_bValidMarker); + + MovingOff(); + return; + } + + TeleportToStopMarker() + { + MovingOn(); + + INDEX ctMarkers=0; + // new moving target + CMovingBrushMarker *pmbm = (CMovingBrushMarker *) &*m_penTarget; + while( pmbm!=NULL && IsOfClass(pmbm->m_penTarget, "Moving Brush Marker") && !pmbm->m_bStopMoving && ctMarkers<50) + { + pmbm = (CMovingBrushMarker *) &*pmbm->m_penTarget; + ctMarkers++; + } + + if( pmbm!=NULL && IsOfClass(pmbm, "Moving Brush Marker") && ctMarkers<50) + { + SetPlacement(pmbm->GetPlacement()); + ForceFullStop(); + m_soStart.Stop(); + m_soStop.Stop(); + m_soFollow.Stop(); + } + + // stop PreMoving check + m_bMoveToMarker = FALSE; + MovingOff(); + return EReturn(); + } + + Main() { + // declare yourself as a brush + InitAsBrush(); + SetPhysicsFlags(EPF_BRUSH_MOVING); + SetCollisionFlags(ECF_BRUSH); + SetHealth(m_fHealth); + + // set zoning flag + if (m_bZoning) { + SetFlags(GetFlags()|ENF_ZONING); + } else { + SetFlags(GetFlags()&~ENF_ZONING); + } + + + // set dynamic shadows as needed + if (m_bDynamicShadows) { + SetFlags(GetFlags()|ENF_DYNAMICSHADOWS); + } else { + SetFlags(GetFlags()&~ENF_DYNAMICSHADOWS); + } + + // stop moving brush + ForceFullStop(); + + autowait(0.1f); + + // load marker parameters + m_bValidMarker = LoadMarkerParameters(); + + if (m_tmBankingRotation!=0) { + jump Rotating(); + } + + // start moving + wait() { + on (EBegin) : { + if (m_bAutoStart) { + // if not already moving and have target + if(!m_bMoving && m_bValidMarker) { + call MoveBrush(); + } + } + resume; + } + on (EHit eHit) : { + if (!m_bMoving) { + call MoveBrush(); + } + resume; + } + // move on touch + on (ETouch eTouch) : { + // inflict damage if required + if( m_fTouchDamage != 0.0f) + { + InflictDirectDamage( eTouch.penOther, this, DMT_SPIKESTAB, m_fTouchDamage, + eTouch.penOther->GetPlacement().pl_PositionVector, eTouch.plCollision); + } + // send event on touch + if(m_tdeSendEventOnDamage!=TDE_DAMAGEONLY && CanReactOnEntity(eTouch.penOther)) { + SendToTarget(m_penTouchEvent, m_eetTouchEvent); + } + // if not already moving + if(!m_bMoving) { + // move brush + if (m_bMoveOnTouch && CanReactOnEntity(eTouch.penOther) && m_bValidMarker) { + call MoveBrush(); + } + } + // if special feature for bull crushing doors + if (m_bBlowupByBull) { + // if hit by bull + if (IsOfClass(eTouch.penOther, "Werebull")) { + // calculate speed along impact normal + FLOAT fImpactSpeed = + ((CMovableEntity&)*eTouch.penOther).en_vCurrentTranslationAbsolute% + -(FLOAT3D&)eTouch.plCollision; + + // if strong collision + if (fImpactSpeed>m_fHealth) { + // receive artificial impact damage + ReceiveDamage(eTouch.penOther, DMT_IMPACT, m_fHealth*2, + FLOAT3D(0,0,0), FLOAT3D(0,0,0)); + } + } + } + resume; + } + // move on start (usually trigger) + on (EStart) : { + // if not already moving and have target + if(!m_bMoving && m_bValidMarker) { + call MoveBrush(); + } + resume; + } + on (EStop) : { + SetCollisionFlags(ECF_IMMATERIAL); + resume; + } + on (ETeleportMovingBrush) : { + call TeleportToStopMarker(); + resume; + } + on (ETrigger) : { + // if not already moving and have target + if(!m_bMoving && m_bValidMarker) { + call MoveBrush(); + } + resume; + } + on (EDeath eDeath) : { + // get your size + FLOATaabbox3D box; + GetSize(box); + if( m_ctDebrises<=0) + { + m_ctDebrises=1; + } + FLOAT fEntitySize = pow(box.Size()(1)*box.Size()(2)*box.Size()(3)/m_ctDebrises, 1.0f/3.0f)*m_fCubeFactor; + + Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(1.0f,2.0f,3.0f), + FLOAT3D(0,0,0), 1.0f+m_fCandyEffect/2.0f, m_fCandyEffect, m_colDebrises); + for(INDEX iDebris = 0; iDebrisSendEvent( EBrushDestroyed()); + } + // send event to blowup target + SendToTarget(m_penBlowupEvent, m_eetBlowupEvent, eDeath.eLastDamage.penInflictor); + + // make sure it doesn't loop with destroying itself + m_tdeSendEventOnDamage = TDE_TOUCHONLY; + m_fHealth = -1; + m_bMoveOnDamage = FALSE; + ForceFullStop(); + SetDefaultProperties(); + + // notify engine to kickstart entities that are cached in stationary position, + // before we turn off, so they can fall + NotifyCollisionChanged(); + + SetFlags( GetFlags()|ENF_HIDDEN); + SetCollisionFlags(ECF_IMMATERIAL); + + // for each child of this entity + {FOREACHINLIST(CEntity, en_lnInParent, en_lhChildren, itenChild) { + // send it destruction event + itenChild->SendEvent(ERangeModelDestruction()); + }} + + stop; + } + } + return; + } +}; diff --git a/Sources/Entities/MovingBrushMarker.es b/Sources/Entities/MovingBrushMarker.es new file mode 100644 index 0000000..b1711e3 --- /dev/null +++ b/Sources/Entities/MovingBrushMarker.es @@ -0,0 +1,58 @@ +102 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +class CMovingBrushMarker: CMarker { +name "Moving Brush Marker"; +thumbnail "Thumbnails\\MovingBrushMarker.tbn"; + +properties: + 1 BOOL m_bInverseRotate "Inverse Rotate" 'R' = FALSE, + 2 FLOAT m_fSpeed "Speed" 'S' = -1.0f, + 3 FLOAT m_fWaitTime "Wait time" 'W' = -1.0f, + 4 BOOL m_bStopMoving "Stop moving" 'O' = FALSE, + 6 enum BoolEType m_betMoveOnTouch "Move on touch" 'M' = BET_IGNORE, + 7 FLOAT m_fBlockDamage "Block damage" 'D' = -1.0f, + + // send event on marker + 10 enum EventEType m_eetMarkerEvent "Marker Event - Type" 'J' = EET_IGNORE, // type of event to send + 11 CEntityPointer m_penMarkerEvent "Marker Event - Target" 'K', // target to send event to + + // send event on touch + 16 enum EventEType m_eetTouchEvent "Touch Event - Type" 'U' = EET_IGNORE, // type of event to send + 17 CEntityPointer m_penTouchEvent "Touch Event - Target" 'I', // target to send event to + + // sound target + 20 CEntityPointer m_penSoundStart "Sound start entity" 'Q', // sound start entity + 21 CEntityPointer m_penSoundStop "Sound stop entity" 'Z', // sound stop entity + 22 CEntityPointer m_penSoundFollow "Sound follow entity" 'F', // sound follow entity + +components: + 1 model MODEL_MARKER "Models\\Editor\\MovingBrushMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\GravityMarker.tex" + +functions: + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\MovingBrushMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + return; + } +}; + diff --git a/Sources/Entities/MusicChanger.es b/Sources/Entities/MusicChanger.es new file mode 100644 index 0000000..69c90f5 --- /dev/null +++ b/Sources/Entities/MusicChanger.es @@ -0,0 +1,76 @@ +225 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/MusicHolder"; + +%{ +%} + +class CMusicChanger : CRationalEntity { +name "MusicChanger"; +thumbnail "Thumbnails\\MusicChanger.tbn"; +features "HasName", "HasDescription", "IsTargetable", "IsImportant"; + +properties: + 1 CTString m_strName "Name" 'N' = "", + 2 CTString m_strDescription = "", + 3 CTFileName m_fnMusic "Music" 'M' = CTFILENAME(""), + 4 FLOAT m_fVolume "Volume" 'V' = 1.0f, + 5 enum MusicType m_mtType "Type" 'Y' = MT_EVENT, + 6 BOOL m_bForceStart "Force start" 'F' = TRUE, + +components: + 1 model MODEL_MARKER "Models\\Editor\\MusicChanger.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\MusicChanger.tex" + +functions: +procedures: + // initialize music + Main(EVoid) { + + // init as model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + m_strDescription.PrintF("%s: %s (%g)", + MusicType_enum.NameForValue((INDEX)m_mtType), + (const char*)m_fnMusic.FileName(), + m_fVolume); + + // wait for game to start + autowait(0.1f); + + // repeat forever + wait() { + // when triggered + on (ETrigger) : { + // find music holder for this level + CEntity *penMusicHolder = _pNetwork->GetEntityWithName("MusicHolder", 0); + // if not existing + if (penMusicHolder==NULL) { + // error + CPrintF("No MusicHolder on this level, cannot change music!\n"); + // if existing + } else { + // send event to change music + EChangeMusic ecm; + ecm.fnMusic = m_fnMusic; + ecm.fVolume = m_fVolume; + ecm.mtType = m_mtType; + ecm.bForceStart = m_bForceStart; + penMusicHolder->SendEvent(ecm); + } + resume; + }; + } + + return; + } +}; diff --git a/Sources/Entities/MusicHolder.es b/Sources/Entities/MusicHolder.es new file mode 100644 index 0000000..ee51e68 --- /dev/null +++ b/Sources/Entities/MusicHolder.es @@ -0,0 +1,400 @@ +222 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/EnemyBase.h" +#include "Entities/EnemySpawner.h" +#include "Entities/Trigger.h" +%} + +enum MusicType { + 0 MT_LIGHT "light", + 1 MT_MEDIUM "medium", + 2 MT_HEAVY "heavy", + 3 MT_EVENT "event", + 4 MT_CONTINUOUS "continuous", +}; + +event EChangeMusic { + enum MusicType mtType, + CTFileName fnMusic, + FLOAT fVolume, + BOOL bForceStart, +}; + +%{ +#define MUSIC_VOLUMEMIN 0.02f // minimum volume (considered off) +#define MUSIC_VOLUMEMAX 0.98f // maximum volume (considered full) + +float FadeInFactor(TIME fFadeTime) +{ + return (float) pow(MUSIC_VOLUMEMAX/MUSIC_VOLUMEMIN, 1/(fFadeTime/_pTimer->TickQuantum)); +} +float FadeOutFactor(TIME fFadeTime) +{ + return (float) pow(MUSIC_VOLUMEMIN/MUSIC_VOLUMEMAX, 1/(fFadeTime/_pTimer->TickQuantum)); +} +%} + +class CMusicHolder : CRationalEntity { +name "MusicHolder"; +thumbnail "Thumbnails\\MusicHolder.tbn"; +features "HasName", "IsTargetable", "IsImportant"; + +properties: + 1 CTString m_strName "" = "MusicHolder", + 2 FLOAT m_fScoreMedium "Score Medium" = 100.0f, + 3 FLOAT m_fScoreHeavy "Score Heavy" = 1000.0f, + + 10 CTFileName m_fnMusic0 "Music Light" 'M' = CTFILENAME(""), + 11 CTFileName m_fnMusic1 "Music Medium" = CTFILENAME(""), + 12 CTFileName m_fnMusic2 "Music Heavy" = CTFILENAME(""), + 13 CTFileName m_fnMusic3 = CTFILENAME(""), // event music + 14 CTFileName m_fnMusic4 = CTFILENAME(""), // continuous music + + 20 FLOAT m_fVolume0 "Volume Light" 'V' = 1.0f, + 21 FLOAT m_fVolume1 "Volume Medium" = 1.0f, + 22 FLOAT m_fVolume2 "Volume Heavy" = 1.0f, + 23 FLOAT m_fVolume3 = 1.0f, // event volume + 24 FLOAT m_fVolume4 = 1.0f, // continuous volume + +// internals + +100 CEntityPointer m_penBoss, // current boss if any +102 CEntityPointer m_penCounter, // enemy counter for wave-fight progress display +104 INDEX m_ctEnemiesInWorld = 0, // count of total enemies in world +105 CEntityPointer m_penRespawnMarker, // respawn marker for coop +106 INDEX m_ctSecretsInWorld = 0, // count of total secrets in world +101 FLOAT m_tmFade = 1.0f, // music cross-fade speed +103 enum MusicType m_mtCurrentMusic = MT_LIGHT, // current active channel + +// for cross-fade purposes +110 FLOAT m_fCurrentVolume0a = 1.0f, +210 FLOAT m_fCurrentVolume0b = 1.0f, +111 FLOAT m_fCurrentVolume1a = 1.0f, +211 FLOAT m_fCurrentVolume1b = 1.0f, +112 FLOAT m_fCurrentVolume2a = 1.0f, +212 FLOAT m_fCurrentVolume2b = 1.0f, +113 FLOAT m_fCurrentVolume3a = 1.0f, +213 FLOAT m_fCurrentVolume3b = 1.0f, +114 FLOAT m_fCurrentVolume4a = 1.0f, +214 FLOAT m_fCurrentVolume4b = 1.0f, + +// the music channels +120 CSoundObject m_soMusic0a, +220 CSoundObject m_soMusic0b, +121 CSoundObject m_soMusic1a, +221 CSoundObject m_soMusic1b, +122 CSoundObject m_soMusic2a, +222 CSoundObject m_soMusic2b, +123 CSoundObject m_soMusic3a, +223 CSoundObject m_soMusic3b, +124 CSoundObject m_soMusic4a, +224 CSoundObject m_soMusic4b, + +// next free subchannel markers (all starts at subchannel 1(b), first switch goes to subchannel 0(a)) +130 INDEX m_iSubChannel0 = 1, +131 INDEX m_iSubChannel1 = 1, +132 INDEX m_iSubChannel2 = 1, +133 INDEX m_iSubChannel3 = 1, +134 INDEX m_iSubChannel4 = 1, + + { + // array of enemies that make fuss + CDynamicContainer m_cenFussMakers; + } + +components: + 1 model MODEL_MARKER "Models\\Editor\\MusicHolder.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\MusicHolder.tex" + + +functions: + // count enemies in current world + void CountEnemies(void) + { + m_ctEnemiesInWorld = 0; + m_ctSecretsInWorld = 0; + // for each entity in the world + {FOREACHINDYNAMICCONTAINER(GetWorld()->wo_cenEntities, CEntity, iten) { + CEntity *pen = iten; + // if enemybase + if (IsDerivedFromClass(pen, "Enemy Base")) { + CEnemyBase *penEnemy = (CEnemyBase *)pen; + // if not template + if (!penEnemy->m_bTemplate) { + // count one + m_ctEnemiesInWorld++; + } + // if spawner + } else if (IsDerivedFromClass(pen, "Enemy Spawner")) { + CEnemySpawner *penSpawner = (CEnemySpawner *)pen; + // if not teleporting + if (penSpawner->m_estType!=EST_TELEPORTER) { + // add total count + m_ctEnemiesInWorld+=penSpawner->m_ctTotal; + } + // if trigger + } else if (IsDerivedFromClass(pen, "Trigger")) { + CTrigger *penTrigger = (CTrigger *)pen; + // if has score + if (penTrigger->m_fScore>0) { + // it counts as a secret + m_ctSecretsInWorld++; + } + } + }} + } + + // check for stale fuss-makers + void CheckOldFussMakers(void) + { + TIME tmNow = _pTimer->CurrentTick(); + TIME tmTooOld = tmNow-10.0f; + CDynamicContainer cenOldFussMakers; + // for each fussmaker + {FOREACHINDYNAMICCONTAINER(m_cenFussMakers, CEntity, itenFussMaker) { + CEnemyBase & enFussMaker = (CEnemyBase&)*itenFussMaker; + // if haven't done fuss for too long + if (enFussMaker.m_tmLastFussTimeTickQuantum); + + // prepare initial music channel values + ChangeMusicChannel(MT_LIGHT, m_fnMusic0, m_fVolume0); + ChangeMusicChannel(MT_MEDIUM, m_fnMusic1, m_fVolume1); + ChangeMusicChannel(MT_HEAVY, m_fnMusic2, m_fVolume2); + ChangeMusicChannel(MT_EVENT, m_fnMusic3, m_fVolume3); + ChangeMusicChannel(MT_CONTINUOUS, m_fnMusic4, m_fVolume4); + + // start with light music + m_mtCurrentMusic = MT_LIGHT; + m_fCurrentVolume0a = MUSIC_VOLUMEMAX*0.98f; + m_tmFade = 0.01f; + CrossFadeOneChannel(MT_LIGHT); + + // must react after enemyspawner and all enemies, but before player for proper enemy counting + // (total wait is two ticks so far) + autowait(_pTimer->TickQuantum); + + // count enemies in current world + CountEnemies(); + + // main loop + while(TRUE) { + // wait a bit + wait(0.1f) { + on (ETimer) : { + stop; + }; + // if music is to be changed + on (EChangeMusic ecm) : { + // change parameters + ChangeMusicChannel(ecm.mtType, ecm.fnMusic, ecm.fVolume); + // if force started + if (ecm.bForceStart) { + // set as current music + m_mtCurrentMusic = ecm.mtType; + } + // stop waiting + stop; + } + } + // check fuss + CheckOldFussMakers(); + // get total score of all active fuss makers + FLOAT fFussScore = GetFussMakersScore(); + // if event is on + if (m_mtCurrentMusic==MT_EVENT) { + // if event has ceased playing + if (!m_soMusic3a.IsPlaying() && !m_soMusic3b.IsPlaying()) { + // switch to light music + m_mtCurrentMusic=MT_LIGHT; + } + } + // if heavy fight is on + if (m_mtCurrentMusic==MT_HEAVY) { + // if no more fuss + if (fFussScore<=0.0f) { + // switch to no fight + m_mtCurrentMusic=MT_LIGHT; + } + // if medium fight is on + } else if (m_mtCurrentMusic==MT_MEDIUM) { + // if no more fuss + if (fFussScore<=0.0f) { + // switch to no fight + m_mtCurrentMusic=MT_LIGHT; + // if larger fuss + } else if (fFussScore>=m_fScoreHeavy) { + // switch to heavy fight + m_mtCurrentMusic=MT_HEAVY; + } + // if no fight is on + } else if (m_mtCurrentMusic==MT_LIGHT) { + // if heavy fuss + if (fFussScore>=m_fScoreHeavy) { + // switch to heavy fight + m_mtCurrentMusic=MT_HEAVY; + // if medium fuss + } else if (fFussScore>=m_fScoreMedium) { + // switch to medium fight + m_mtCurrentMusic=MT_MEDIUM; + } + } + + // setup fade speed depending on music type + if (m_mtCurrentMusic==MT_LIGHT) { + m_tmFade = 2.0f; + } else if (m_mtCurrentMusic==MT_MEDIUM) { + m_tmFade = 1.0f; + } else if (m_mtCurrentMusic==MT_HEAVY) { + m_tmFade = 1.0f; + } else if (m_mtCurrentMusic==MT_EVENT || m_mtCurrentMusic==MT_CONTINUOUS) { + m_tmFade = 0.5f; + } + + // fade all channels + CrossFadeOneChannel(MT_LIGHT); + CrossFadeOneChannel(MT_MEDIUM); + CrossFadeOneChannel(MT_HEAVY); + CrossFadeOneChannel(MT_EVENT); + CrossFadeOneChannel(MT_CONTINUOUS); + } + return; + } +}; diff --git a/Sources/Entities/NavigationMarker.es b/Sources/Entities/NavigationMarker.es new file mode 100644 index 0000000..468d85e --- /dev/null +++ b/Sources/Entities/NavigationMarker.es @@ -0,0 +1,178 @@ +704 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/Common/PathFinding.h" + +#define MAX_TARGETS 6 +%} + +uses "Entities/Marker"; + +%{ +// info structure +static EntityInfo eiMarker = { + EIBT_ROCK, 10.0f, + 0.0f, 1.0f, 0.0f, // source (eyes) + 0.0f, 1.0f, 0.0f, // target (body) +}; + +%} + +class export CNavigationMarker : CEntity { +name "NavigationMarker"; +thumbnail "Thumbnails\\NavigationMarker.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Marker", + 2 RANGE m_fMarkerRange "Marker Range" 'M' = 1.0f, // range around marker (marker doesn't have to be hit directly) + + 100 CEntityPointer m_penTarget0 "Target 0" 'T' COLOR(C_dBLUE|0xFF), + 101 CEntityPointer m_penTarget1 "Target 1" COLOR(C_dBLUE|0xFF), + 102 CEntityPointer m_penTarget2 "Target 2" COLOR(C_dBLUE|0xFF), + 103 CEntityPointer m_penTarget3 "Target 3" COLOR(C_dBLUE|0xFF), + 104 CEntityPointer m_penTarget4 "Target 4" COLOR(C_dBLUE|0xFF), + 105 CEntityPointer m_penTarget5 "Target 5" COLOR(C_dBLUE|0xFF), + + { + CPathNode *m_ppnNode; // for pathfinding algorithm + } + +components: + 1 model MODEL_MARKER "Models\\Editor\\NavigationMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\NavigationMarker.tex" + +functions: + void CNavigationMarker(void) + { + m_ppnNode = NULL; + } + void ~CNavigationMarker(void) + { + ASSERT(m_ppnNode == NULL); + } + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CEntity::Read_t(istr); + m_ppnNode = NULL; + } + + CEntity *GetTarget(void) const { return m_penTarget0; }; + + /* Entity info */ + void *GetEntityInfo(void) { + return &eiMarker; + }; + + // get node used for pathfinding algorithm + CPathNode *GetPathNode(void) + { + if (m_ppnNode==NULL) { + m_ppnNode = new CPathNode(this); + } + + return m_ppnNode; + } + + CEntityPointer &TargetPointer(INDEX i) + { + ASSERT(i>=0 && iStretchModel(FLOAT3D(fSize, fSize, fSize)); + SetModel(MODEL_MARKER); + ModelChangeNotify(); + SetModelMainTexture(TEXTURE_MARKER); + + // for each non-empty target + for (INDEX iTarget=0; iTarget100.0f) { m_fStretchX = 100.0f*Sgn(m_fStretchX); } + if (Abs(m_fStretchY) >100.0f) { m_fStretchY = 100.0f*Sgn(m_fStretchY); } + if (Abs(m_fStretchZ) >100.0f) { m_fStretchZ = 100.0f*Sgn(m_fStretchZ); } + if (m_fStretchAll>100.0f) { m_fStretchAll = 100.0f; } + + GetModelObject()->StretchModel( FLOAT3D( + m_fStretchAll*m_fStretchX, + m_fStretchAll*m_fStretchY, + m_fStretchAll*m_fStretchZ) ); + ModelChangeNotify(); + }; + + CPlacement3D GetLerpedPlacement(void) const + { + return CEntity::GetLerpedPlacement(); // we never move anyway, so let's be able to be parented + } + +procedures: + // particles are active + Active() + { + m_bActive = TRUE; + while( TRUE) + { + // wait defined time + wait( m_fParam2+FRnd()*m_fParam3) + { + on (ETimer) : + { + // for randomly spawned particles + if( m_phtType == PHT_LAVAERUPTING) + { + // spawn new particles + m_fActivateTime = _pTimer->CurrentTick(); + } + stop; + } + on (EBegin) : + { + resume; + } + on (EDeactivate) : + { + m_fDeactivateTime = _pTimer->CurrentTick(); + jump Inactive(); + } + } + } + }; + + // particles are not active + Inactive() { + m_bActive = FALSE; + wait() + { + on (EBegin) : { resume; } + on (EActivate) : + { + m_fActivateTime = _pTimer->CurrentTick(); + m_fDeactivateTime = _pTimer->CurrentTick()+10000.0f; + jump Active(); + } + } + }; + + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + StretchModel(); + SetModel(MODEL_TELEPORT); + ModelChangeNotify(); + SetModelMainTexture(TEXTURE_TELEPORT); + + if (m_bBackground) { + SetFlags(GetFlags()|ENF_BACKGROUND); + } else { + SetFlags(GetFlags()&~ENF_BACKGROUND); + } + + en_fGravityA = 30.0f; + GetPitchDirection(-90.0f, en_vGravityDir); + + m_fActivateTime = 0.0f; + m_fDeactivateTime = -10000.0f; + + if (m_bActive) { + jump Active(); + } else { + jump Inactive(); + } + + + return; + } +}; diff --git a/Sources/Entities/Pendulum.es b/Sources/Entities/Pendulum.es new file mode 100644 index 0000000..d6afe94 --- /dev/null +++ b/Sources/Entities/Pendulum.es @@ -0,0 +1,112 @@ +106 +%{ +#include "Entities/StdH/StdH.h" +%} + + +class CPendulum: CMovableBrushEntity { +name "Pendulum"; +thumbnail "Thumbnails\\Pendulum.tbn"; +features "HasName", "IsTargetable"; +properties: + 1 CTString m_strName "Name" 'N' = "Pendulum", // name + 2 BOOL m_bDynamicShadows "Dynamic shadows" = FALSE, // if has dynamic shadows + 3 FLOAT m_fMaxAngle "Maximum angle" = 60.0f, // pendulum will never go over this angle + 5 FLOAT m_fSpeed = 0.0f, // current speed + 6 FLOAT m_fDampFactor "Damp factor" = 0.9f, // dump factor + 7 FLOAT m_fPendulumFactor "Pendulum factor" = 1.0f, // pendulum factor + 8 FLOAT m_fImpulseFactor "Damage impulse factor" = 0.01f, // factor applied to damage ammount + 9 FLOAT m_fTriggerImpulse "Impulse on trigger" = 10.0f, // ipulse given on trigger + 10 BOOL m_bActive "Active" 'A' = TRUE, // if pendulum is active by default + +components: +functions: + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + if( !m_bActive) + { + return; + } + // get vector in direction of oscilation + FLOAT3D vOscilatingDirection; + GetHeadingDirection( -90.0f, vOscilatingDirection); + // project damage direction onto oscilating direction + FLOAT fImpulse = vDirection%vOscilatingDirection; + // calculate impulse strength + fImpulse *= fDamageAmmount*m_fImpulseFactor; + // apply impulse + m_fSpeed += fImpulse; + SetDesiredRotation( ANGLE3D(0, 0, m_fSpeed)); + } + + /* Post moving */ + void PostMoving() + { + CMovableBrushEntity::PostMoving(); + ANGLE fCurrentBanking = GetPlacement().pl_OrientationAngle(3); + FLOAT fNewSpeed = m_fSpeed*m_fDampFactor-m_fPendulumFactor*fCurrentBanking; + + // if maximum angle achieved, stop in place and turn back + if( Abs( fCurrentBanking) > m_fMaxAngle && Sgn(fNewSpeed)==Sgn(fCurrentBanking)) + { + fNewSpeed = 0.0f; + } + + m_fSpeed = fNewSpeed; + SetDesiredRotation( ANGLE3D(0, 0, fNewSpeed)); + + // if angle is not zero + if (Abs( fCurrentBanking) > 1.0f) + { + // clear in rendering flag + SetFlags(GetFlags()&~ENF_INRENDERING); + } + }; + +procedures: + Main() { + // declare yourself as a brush + InitAsBrush(); + SetPhysicsFlags(EPF_BRUSH_MOVING); + SetCollisionFlags(ECF_BRUSH); + // non-zoning brush + SetFlags(GetFlags()&~ENF_ZONING); + + // set dynamic shadows as needed + if (m_bDynamicShadows) { + SetFlags(GetFlags()|ENF_DYNAMICSHADOWS); + } else { + SetFlags(GetFlags()&~ENF_DYNAMICSHADOWS); + } + + // start moving + wait() { + on( EActivate): + { + m_bActive = TRUE; + resume; + } + on( EDeactivate): + { + m_bActive = FALSE; + resume; + } + on( ETrigger): + { + if( m_bActive) + { + // apply impulse + m_fSpeed += m_fTriggerImpulse; + AddToMovers(); + } + resume; + } + } + + Destroy(); + stop; + return; + } +}; diff --git a/Sources/Entities/Pipebomb.es b/Sources/Entities/Pipebomb.es new file mode 100644 index 0000000..963b447 --- /dev/null +++ b/Sources/Entities/Pipebomb.es @@ -0,0 +1,258 @@ +503 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/BasicEffects"; +uses "Entities/Light"; +uses "Entities/AmmoItem"; + +// input parameter for launching the projectile +event EDropPipebomb { + CEntityPointer penLauncher, // who launched it + FLOAT fSpeed, // launch speed +}; + +%{ +#define ECF_PIPEBOMB ( \ + ((ECBI_MODEL|ECBI_BRUSH|ECBI_PROJECTILE_SOLID|ECBI_MODEL_HOLDER)<PrecacheClass(CLASS_BASIC_EFFECT, BET_GRENADE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_SHOCKWAVE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_GRENADE_PLANE); + pdec->PrecacheModel(MODEL_PIPEBOMB); + pdec->PrecacheTexture(TEXTURE_PIPEBOMB); + pdec->PrecacheSound(SOUND_LAUNCH); +} +%} + +class CPipebomb : CMovableModelEntity { +name "Pipebomb"; +thumbnail ""; +features "ImplementsOnPrecache", "CanBePredictable"; + +properties: + 1 CEntityPointer m_penLauncher, // who lanuched it + 2 FLOAT m_fIgnoreTime = 0.0f, // time when laucher will be ignored + 3 FLOAT m_fSpeed = 0.0f, // launch speed + 4 BOOL m_bCollected = FALSE, // collect -> do not explode + +{ + CLightSource m_lsLightSource; +} + +components: + 1 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 2 class CLASS_LIGHT "Classes\\Light.ecl", + +// ********* PIPEBOMB (GRENADE) ********* + 10 model MODEL_PIPEBOMB "Models\\Weapons\\Pipebomb\\Grenade\\Grenade.mdl", + 11 texture TEXTURE_PIPEBOMB "Models\\Weapons\\Pipebomb\\Grenade\\Grenade.tex", + 12 sound SOUND_LAUNCH "Sounds\\Weapons\\RocketFired.wav", + +functions: + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CMovableModelEntity::Read_t(istr); + SetupLightSource(); + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_colColor = C_vdRED; + lsNew.ls_rFallOff = 1.0f; + lsNew.ls_rHotSpot = 0.1f; + lsNew.ls_plftLensFlare = &_lftYellowStarRedRingFar; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + + // render particles + void RenderParticles(void) { + Particles_GrenadeTrail(this); + } + +/************************************************************ + * PIPEBOMB * + ************************************************************/ +void Pipebomb(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PIPEBOMB); + //GetModelObject()->StretchModel(FLOAT3D(2.5f, 2.5f, 2.5f)); + //ModelChangeNotify(); + SetModel(MODEL_PIPEBOMB); + SetModelMainTexture(TEXTURE_PIPEBOMB); + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -m_fSpeed), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, FRnd()*120.0f+120.0f, FRnd()*250.0f-125.0f)); + en_fBounceDampNormal = 0.7f; + en_fBounceDampParallel = 0.7f; + en_fJumpControlMultiplier = 0.0f; + en_fCollisionSpeedLimit = 45.0f; + en_fCollisionDamageFactor = 10.0f; + SetHealth(20.0f); +}; + +void PipebombExplosion(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_GRENADE; + ese.vStretch = FLOAT3D(1,1,1); + SpawnEffect(GetPlacement(), ese); + // spawn sound event in range + if( IsDerivedFromClass( m_penLauncher, "Player")) { + SpawnRangeSound( m_penLauncher, this, SNDT_PLAYER, 50.0f); + } + + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // wall stain + ese.betType = BET_EXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // shock wave + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // second explosion on plane + ese.betType = BET_GRENADE_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + } + } +}; + + + + +/************************************************************ + * C O M M O N F U N C T I O N S * + ************************************************************/ +// projectile hitted (or time expired or can't move any more) +void ProjectileHitted(void) { + // explode ... + InflictRangeDamage(m_penLauncher, DMT_EXPLOSION, 100.0f, + GetPlacement().pl_PositionVector, 4.0f, 8.0f); + // sound event + ESound eSound; + eSound.EsndtSound = SNDT_EXPLOSION; + eSound.penTarget = m_penLauncher; + SendEventInRange(eSound, FLOATaabbox3D(GetPlacement().pl_PositionVector, 50.0f)); +}; + + +// spawn effect +void SpawnEffect(const CPlacement3D &plEffect, const ESpawnEffect &eSpawnEffect) { + CEntityPointer penEffect = CreateEntity(plEffect, CLASS_BASIC_EFFECT); + penEffect->Initialize(eSpawnEffect); +}; + + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> PROJECTILE SLIDE ON BRUSH + ProjectileSlide(EVoid) { + m_bCollected = FALSE; + // fly loop + wait() { + on (EBegin) : { resume; } + // collected + on (ETouch etouch) : { + // clear time limit for launcher + if (etouch.penOther->GetRenderType() & RT_BRUSH) { + m_fIgnoreTime = 0.0f; + resume; + } + + BOOL bCollect; + // ignore launcher within 0.5 second + bCollect = etouch.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // speed must be almost zero + bCollect &= (en_vCurrentTranslationAbsolute.Length() < 0.25f); + // only if can be collected + EAmmoItem eai; + eai.EaitType = AIT_GRENADES; + eai.iQuantity = 1; + if (bCollect && etouch.penOther->ReceiveItem(eai)) { + m_bCollected = TRUE; + stop; + } + resume; + } + // killed + on (EDeath) : { + ProjectileHitted(); + stop; + } + // activated + on (EStart) : { + ProjectileHitted(); + stop; + } + } + return EEnd(); + }; + + // --->>> MAIN + Main(EDropPipebomb edrop) { + // remember the initial parameters + ASSERT(edrop.penLauncher!=NULL); + m_penLauncher = edrop.penLauncher; + m_fSpeed = edrop.fSpeed; + + // projectile initialization + Pipebomb(); + + // setup light source + SetupLightSource(); + + // remember lauching time + m_fIgnoreTime = _pTimer->CurrentTick() + 0.5f; + + // slide + autocall ProjectileSlide() EEnd; + + // pipebomb explosion if not collected + if (!m_bCollected) { + PipebombExplosion(); + } + + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/Player.es b/Sources/Entities/Player.es new file mode 100644 index 0000000..4f55061 --- /dev/null +++ b/Sources/Entities/Player.es @@ -0,0 +1,5887 @@ +401 +%{ + +#include "Entities/StdH/StdH.h" + +#include +#include +#include + +#include "Models/Player/SeriousSam/Player.h" +#include "Models/Player/SeriousSam/Body.h" +#include "Models/Player/SeriousSam/Head.h" + +#include "Entities/PlayerMarker.h" +#include "Entities/PlayerWeapons.h" +#include "Entities/PlayerAnimator.h" +#include "Entities/PlayerView.h" +#include "Entities/MovingBrush.h" +#include "Entities/Switch.h" +#include "Entities/MessageHolder.h" +#include "Entities/Camera.h" +#include "Entities/WorldLink.h" +#include "Entities/HealthItem.h" +#include "Entities/ArmorItem.h" +#include "Entities/WeaponItem.h" +#include "Entities/AmmoItem.h" +#include "Entities/MessageItem.h" +#include "Entities/AmmoPack.h" +#include "Entities/KeyItem.h" +#include "Entities/MusicHolder.h" +#include "Entities/EnemyBase.h" +#include "Entities/PlayerActionMarker.h" +#include "Entities/BasicEffects.h" +#include "Entities/BackgroundViewer.h" +#include "Entities/WorldSettingsController.h" + +extern void JumpFromBouncer(CEntity *penToBounce, CEntity *penBouncer); +// from game +#define GRV_SHOWEXTRAS (1L<<0) // add extra stuff like console, weapon, pause + +%} + +uses "Entities/WorldLink"; + +enum PlayerViewType { + 0 PVT_PLAYEREYES "", + 1 PVT_PLAYERAUTOVIEW "", + 2 PVT_SCENECAMERA "", + 3 PVT_3RDPERSONVIEW "", +}; + +enum PlayerState { + 0 PST_STAND "", + 1 PST_CROUCH "", + 2 PST_SWIM "", + 3 PST_DIVE "", + 4 PST_FALL "", +}; + +// event for starting cinematic camera sequence +event ECameraStart { + CEntityPointer penCamera, // the camera +}; + +// event for ending cinematic camera sequence +event ECameraStop { + CEntityPointer penCamera, // the camera +}; + + +// sent when needs to rebirth +event ERebirth { +}; + +// sent when player was disconnected from game +event EDisconnected { +}; + +// starts automatic player actions +event EAutoAction { + CEntityPointer penFirstMarker, +}; + +%{ +extern void DrawHUD( const CPlayer *penPlayerCurrent, CDrawPort *pdpCurrent, BOOL bSnooping); +extern void InitHUD(void); +extern void EndHUD(void); + +static CTimerValue _tvProbingLast; + +// used to render certain entities only for certain players (like picked items, etc.) +ULONG _ulPlayerRenderingMask = 0; + +#define NAME name + +const FLOAT _fBlowUpAmmount = 70.0f; + +// computer message adding flags +#define CMF_READ (1L<<0) +#define CMF_ANALYZE (1L<<1) + +struct MarkerDistance { +public: + FLOAT md_fMinD; + CPlayerMarker *md_ppm; + void Clear(void); +}; + +int qsort_CompareMarkerDistance(const void *pv0, const void *pv1) +{ + MarkerDistance &md0 = *(MarkerDistance*)pv0; + MarkerDistance &md1 = *(MarkerDistance*)pv1; + if( md0.md_fMinDmd1.md_fMinD) return -1; + else return 0; +} + +static inline FLOAT IntensityAtDistance( FLOAT fFallOff, FLOAT fHotSpot, FLOAT fDistance) +{ + // intensity is zero if further than fall-off range + if( fDistance>fFallOff) return 0.0f; + // intensity is maximum if closer than hot-spot range + if( fDistanceGetWorld()->wo_cenEntities, CEntity, iten) { + CEntity *pen = iten; + if (IsDerivedFromClass(pen, "Enemy Base") && !IsOfClass(pen, "Devil")) { + CEnemyBase *penEnemy = (CEnemyBase *)pen; + if (penEnemy->m_penEnemy==NULL) { + continue; + } + penKiller->InflictDirectDamage(pen, penKiller, DMT_BULLET, + penEnemy->GetHealth()+1, pen->GetPlacement().pl_PositionVector, FLOAT3D(0,1,0)); + } + }} +} + + +#define HEADING_MAX 45.0f +#define PITCH_MAX 90.0f +#define BANKING_MAX 45.0f + +// player flags +#define PLF_INITIALIZED (1UL<<0) // set when player entity is ready to function +#define PLF_VIEWROTATIONCHANGED (1UL<<1) // for adjusting view rotation separately from legs +#define PLF_JUMPALLOWED (1UL<<2) // if jumping is allowed +#define PLF_SYNCWEAPON (1UL<<3) // weapon model needs to be synchronized before rendering +#define PLF_AUTOMOVEMENTS (1UL<<4) // complete automatic control of movements +#define PLF_DONTRENDER (1UL<<5) // don't render view (used at end of level) +#define PLF_CHANGINGLEVEL (1UL<<6) // mark that we next are to appear at start of new level +#define PLF_APPLIEDACTION (1UL<<7) // used to detect when player is not connected +#define PLF_NOTCONNECTED (1UL<<8) // set if the player is not connected +#define PLF_LEVELSTARTED (1UL<<9) // marks that level start time was recorded +#define PLF_RESPAWNINPLACE (1UL<<10) // don't move to marker when respawning (for current death only) + +// defines representing flags used to fill player buttoned actions +#define PLACT_FIRE (1L<<0) +#define PLACT_RELOAD (1L<<1) +#define PLACT_WEAPON_NEXT (1L<<2) +#define PLACT_WEAPON_PREV (1L<<3) +#define PLACT_WEAPON_FLIP (1L<<4) +#define PLACT_USE (1L<<5) +#define PLACT_COMPUTER (1L<<6) +#define PLACT_3RD_PERSON_VIEW (1L<<7) +#define PLACT_CENTER_VIEW (1L<<8) +#define PLACT_SELECT_WEAPON_SHIFT (9) +#define PLACT_SELECT_WEAPON_MASK (0x1FL<en_pcCharacter==pc) { + penThis = pen; + break; + } + } + // if not found + if (penThis==NULL) { + // do nothing + return; + } + // accumulate local rotation + penThis->m_aLocalRotation +=paAction.pa_aRotation; + penThis->m_aLocalViewRotation+=paAction.pa_aViewRotation; + penThis->m_vLocalTranslation +=paAction.pa_vTranslation; + + // if prescanning + if (bPreScan) { + // no button checking + return; + } + + // add button movement/rotation/look actions to the axis actions + if(pctlCurrent.bMoveForward || pctlCurrent.bStrafeFB&&pctlCurrent.bTurnUp ) paAction.pa_vTranslation(3) -= plr_fSpeedForward; + if(pctlCurrent.bMoveBackward || pctlCurrent.bStrafeFB&&pctlCurrent.bTurnDown) paAction.pa_vTranslation(3) += plr_fSpeedBackward; + if(pctlCurrent.bMoveLeft || pctlCurrent.bStrafe&&pctlCurrent.bTurnLeft) paAction.pa_vTranslation(1) -= plr_fSpeedSide; + if(pctlCurrent.bMoveRight || pctlCurrent.bStrafe&&pctlCurrent.bTurnRight) paAction.pa_vTranslation(1) += plr_fSpeedSide; + if(pctlCurrent.bMoveUp ) paAction.pa_vTranslation(2) += plr_fSpeedUp; + if(pctlCurrent.bMoveDown ) paAction.pa_vTranslation(2) -= plr_fSpeedUp; + + const FLOAT fQuantum = _pTimer->TickQuantum; + if(pctlCurrent.bTurnLeft && !pctlCurrent.bStrafe) penThis->m_aLocalRotation(1) += ctl_fButtonRotationSpeedH*fQuantum; + if(pctlCurrent.bTurnRight && !pctlCurrent.bStrafe) penThis->m_aLocalRotation(1) -= ctl_fButtonRotationSpeedH*fQuantum; + if(pctlCurrent.bTurnUp && !pctlCurrent.bStrafeFB) penThis->m_aLocalRotation(2) += ctl_fButtonRotationSpeedP*fQuantum; + if(pctlCurrent.bTurnDown && !pctlCurrent.bStrafeFB) penThis->m_aLocalRotation(2) -= ctl_fButtonRotationSpeedP*fQuantum; + if(pctlCurrent.bTurnBankingLeft ) penThis->m_aLocalRotation(3) += ctl_fButtonRotationSpeedB*fQuantum; + if(pctlCurrent.bTurnBankingRight ) penThis->m_aLocalRotation(3) -= ctl_fButtonRotationSpeedB*fQuantum; + + if(pctlCurrent.bLookLeft ) penThis->m_aLocalViewRotation(1) += ctl_fButtonRotationSpeedH*fQuantum; + if(pctlCurrent.bLookRight ) penThis->m_aLocalViewRotation(1) -= ctl_fButtonRotationSpeedH*fQuantum; + if(pctlCurrent.bLookUp ) penThis->m_aLocalViewRotation(2) += ctl_fButtonRotationSpeedP*fQuantum; + if(pctlCurrent.bLookDown ) penThis->m_aLocalViewRotation(2) -= ctl_fButtonRotationSpeedP*fQuantum; + if(pctlCurrent.bLookBankingLeft ) penThis->m_aLocalViewRotation(3) += ctl_fButtonRotationSpeedB*fQuantum; + if(pctlCurrent.bLookBankingRight ) penThis->m_aLocalViewRotation(3) -= ctl_fButtonRotationSpeedB*fQuantum; + + // use current accumulated rotation + paAction.pa_aRotation = penThis->m_aLocalRotation; + paAction.pa_aViewRotation = penThis->m_aLocalViewRotation; + //paAction.pa_vTranslation = penThis->m_vLocalTranslation; + + // if walking + if(pctlCurrent.bWalk) { + // make forward/backward and sidestep speeds slower + paAction.pa_vTranslation(3) /= 2.0f; + paAction.pa_vTranslation(1) /= 2.0f; + } + + // reset all button actions + paAction.pa_ulButtons = 0; + + // set weapon selection bits + for(INDEX i=1; ips_ulFlags&PSF_COMPSINGLECLICK)) { + // press both + paAction.pa_ulButtons |= PLACT_USE|PLACT_COMPUTER; + // if double-click is on + } else { + // if double click + if (_pTimer->GetRealTimeTick()<=_tmLastUseOrCompPressed+ctl_tmComputerDoubleClick) { + // computer pressed + paAction.pa_ulButtons |= PLACT_COMPUTER; + // if single click + } else { + // use pressed + paAction.pa_ulButtons |= PLACT_USE; + } + } + _tmLastUseOrCompPressed = _pTimer->GetRealTimeTick(); + } + // remember old userorcomp pressed state + pctlCurrent.bUseOrComputerLast = pctlCurrent.bUseOrComputer; +}; + +void CPlayer_Precache(void) +{ + CDLLEntityClass *pdec = &CPlayer_DLLClass; + + // precache view + extern void CPlayerView_Precache(void); + CPlayerView_Precache(); + + // precache all player sounds + pdec->PrecacheSound(SOUND_WATER_ENTER ); + pdec->PrecacheSound(SOUND_WATER_LEAVE ); + pdec->PrecacheSound(SOUND_WALK_L ); + pdec->PrecacheSound(SOUND_WALK_R ); + pdec->PrecacheSound(SOUND_WALK_SAND_L ); + pdec->PrecacheSound(SOUND_WALK_SAND_R ); + pdec->PrecacheSound(SOUND_SWIM_L ); + pdec->PrecacheSound(SOUND_SWIM_R ); + pdec->PrecacheSound(SOUND_DIVE_L ); + pdec->PrecacheSound(SOUND_DIVE_R ); + pdec->PrecacheSound(SOUND_DIVEIN ); + pdec->PrecacheSound(SOUND_DIVEOUT ); + pdec->PrecacheSound(SOUND_DROWN ); + pdec->PrecacheSound(SOUND_INHALE0 ); + pdec->PrecacheSound(SOUND_JUMP ); + pdec->PrecacheSound(SOUND_LAND ); + pdec->PrecacheSound(SOUND_WOUNDWEAK ); + pdec->PrecacheSound(SOUND_WOUNDMEDIUM ); + pdec->PrecacheSound(SOUND_WOUNDSTRONG ); + pdec->PrecacheSound(SOUND_WOUNDWATER ); + pdec->PrecacheSound(SOUND_DEATH ); + pdec->PrecacheSound(SOUND_DEATHWATER ); + pdec->PrecacheSound(SOUND_WATERAMBIENT ); + pdec->PrecacheSound(SOUND_WATERBUBBLES ); + pdec->PrecacheSound(SOUND_WATERWALK_L ); + pdec->PrecacheSound(SOUND_WATERWALK_R ); + pdec->PrecacheSound(SOUND_INHALE1 ); + pdec->PrecacheSound(SOUND_INHALE2 ); + pdec->PrecacheSound(SOUND_INFO ); +// pdec->PrecacheSound(SOUND_HIGHSCORE ); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_TELEPORT); + + pdec->PrecacheModel(MODEL_FLESH); + pdec->PrecacheModel(MODEL_FLESH_APPLE); + pdec->PrecacheModel(MODEL_FLESH_BANANA); + pdec->PrecacheModel(MODEL_FLESH_BURGER); + pdec->PrecacheTexture(TEXTURE_FLESH_RED); + pdec->PrecacheTexture(TEXTURE_FLESH_GREEN); + pdec->PrecacheTexture(TEXTURE_FLESH_APPLE); + pdec->PrecacheTexture(TEXTURE_FLESH_BANANA); + pdec->PrecacheTexture(TEXTURE_FLESH_BURGER); + pdec->PrecacheTexture(TEXTURE_FLESH_LOLLY); + pdec->PrecacheTexture(TEXTURE_FLESH_ORANGE); + + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSPILL); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODSTAINGROW); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BLOODEXPLODE); +} + +void CPlayer_OnInitClass(void) +{ + // clear current player controls + memset(&pctlCurrent, 0, sizeof(pctlCurrent)); + // declare player control variables + _pShell->DeclareSymbol("user INDEX ctl_bMoveForward;", &pctlCurrent.bMoveForward); + _pShell->DeclareSymbol("user INDEX ctl_bMoveBackward;", &pctlCurrent.bMoveBackward); + _pShell->DeclareSymbol("user INDEX ctl_bMoveLeft;", &pctlCurrent.bMoveLeft); + _pShell->DeclareSymbol("user INDEX ctl_bMoveRight;", &pctlCurrent.bMoveRight); + _pShell->DeclareSymbol("user INDEX ctl_bMoveUp;", &pctlCurrent.bMoveUp); + _pShell->DeclareSymbol("user INDEX ctl_bMoveDown;", &pctlCurrent.bMoveDown); + _pShell->DeclareSymbol("user INDEX ctl_bTurnLeft;", &pctlCurrent.bTurnLeft); + _pShell->DeclareSymbol("user INDEX ctl_bTurnRight;", &pctlCurrent.bTurnRight); + _pShell->DeclareSymbol("user INDEX ctl_bTurnUp;", &pctlCurrent.bTurnUp); + _pShell->DeclareSymbol("user INDEX ctl_bTurnDown;", &pctlCurrent.bTurnDown); + _pShell->DeclareSymbol("user INDEX ctl_bTurnBankingLeft;", &pctlCurrent.bTurnBankingLeft); + _pShell->DeclareSymbol("user INDEX ctl_bTurnBankingRight;", &pctlCurrent.bTurnBankingRight); + _pShell->DeclareSymbol("user INDEX ctl_bCenterView;", &pctlCurrent.bCenterView); + _pShell->DeclareSymbol("user INDEX ctl_bLookLeft;", &pctlCurrent.bLookLeft); + _pShell->DeclareSymbol("user INDEX ctl_bLookRight;", &pctlCurrent.bLookRight); + _pShell->DeclareSymbol("user INDEX ctl_bLookUp;", &pctlCurrent.bLookUp); + _pShell->DeclareSymbol("user INDEX ctl_bLookDown;", &pctlCurrent.bLookDown); + _pShell->DeclareSymbol("user INDEX ctl_bLookBankingLeft;", &pctlCurrent.bLookBankingLeft); + _pShell->DeclareSymbol("user INDEX ctl_bLookBankingRight;", &pctlCurrent.bLookBankingRight ); + _pShell->DeclareSymbol("user INDEX ctl_bWalk;", &pctlCurrent.bWalk); + _pShell->DeclareSymbol("user INDEX ctl_bStrafe;", &pctlCurrent.bStrafe); + _pShell->DeclareSymbol("user INDEX ctl_bStrafeFB;", &pctlCurrent.bStrafeFB); + _pShell->DeclareSymbol("user INDEX ctl_bFire;", &pctlCurrent.bFire); + _pShell->DeclareSymbol("user INDEX ctl_bReload;", &pctlCurrent.bReload); + _pShell->DeclareSymbol("user INDEX ctl_bUse;", &pctlCurrent.bUse); + _pShell->DeclareSymbol("user INDEX ctl_bComputer;", &pctlCurrent.bComputer); + _pShell->DeclareSymbol("user INDEX ctl_bUseOrComputer;", &pctlCurrent.bUseOrComputer); + _pShell->DeclareSymbol("user INDEX ctl_b3rdPersonView;", &pctlCurrent.b3rdPersonView); + _pShell->DeclareSymbol("user INDEX ctl_bWeaponNext;", &pctlCurrent.bWeaponNext); + _pShell->DeclareSymbol("user INDEX ctl_bWeaponPrev;", &pctlCurrent.bWeaponPrev); + _pShell->DeclareSymbol("user INDEX ctl_bWeaponFlip;", &pctlCurrent.bWeaponFlip); + _pShell->DeclareSymbol("user INDEX ctl_bSelectWeapon[30+1];", &pctlCurrent.bSelectWeapon); + _pShell->DeclareSymbol("persistent user FLOAT ctl_tmComputerDoubleClick;", &ctl_tmComputerDoubleClick); + _pShell->DeclareSymbol("persistent user FLOAT ctl_fButtonRotationSpeedH;", &ctl_fButtonRotationSpeedH); + _pShell->DeclareSymbol("persistent user FLOAT ctl_fButtonRotationSpeedP;", &ctl_fButtonRotationSpeedP); + _pShell->DeclareSymbol("persistent user FLOAT ctl_fButtonRotationSpeedB;", &ctl_fButtonRotationSpeedB); + _pShell->DeclareSymbol("persistent user FLOAT ctl_fAxisStrafingModifier;", &ctl_fAxisStrafingModifier); + + _pShell->DeclareSymbol("user FLOAT plr_fSwimSoundDelay;", &plr_fSwimSoundDelay); + _pShell->DeclareSymbol("user FLOAT plr_fDiveSoundDelay;", &plr_fDiveSoundDelay); + _pShell->DeclareSymbol("user FLOAT plr_fWalkSoundDelay;", &plr_fWalkSoundDelay); + _pShell->DeclareSymbol("user FLOAT plr_fRunSoundDelay;", &plr_fRunSoundDelay); + + _pShell->DeclareSymbol("persistent user FLOAT cli_fPredictPlayersRange;",&cli_fPredictPlayersRange); + _pShell->DeclareSymbol("persistent user FLOAT cli_fPredictItemsRange;", &cli_fPredictItemsRange ); + _pShell->DeclareSymbol("persistent user FLOAT cli_tmPredictFoe;", &cli_tmPredictFoe ); + _pShell->DeclareSymbol("persistent user FLOAT cli_tmPredictAlly;", &cli_tmPredictAlly ); + _pShell->DeclareSymbol("persistent user FLOAT cli_tmPredictEnemy;", &cli_tmPredictEnemy ); + + _pShell->DeclareSymbol(" INDEX hud_bShowAll;", &hud_bShowAll); + _pShell->DeclareSymbol("user INDEX hud_bShowInfo;", &hud_bShowInfo); + _pShell->DeclareSymbol("user const FLOAT net_tmLatencyAvg;", &net_tmLatencyAvg); + _pShell->DeclareSymbol("persistent user INDEX hud_bShowLatency;", &hud_bShowLatency); + _pShell->DeclareSymbol("persistent user INDEX hud_iShowPlayers;", &hud_iShowPlayers); + _pShell->DeclareSymbol("persistent user INDEX hud_iSortPlayers;", &hud_iSortPlayers); + _pShell->DeclareSymbol("persistent user INDEX hud_bShowWeapon;", &hud_bShowWeapon); + _pShell->DeclareSymbol("persistent user INDEX hud_bShowMessages;",&hud_bShowMessages); + _pShell->DeclareSymbol("persistent user FLOAT hud_fScaling;", &hud_fScaling); + _pShell->DeclareSymbol("persistent user FLOAT hud_fOpacity;", &hud_fOpacity); + _pShell->DeclareSymbol("persistent user FLOAT hud_tmWeaponsOnScreen;", &hud_tmWeaponsOnScreen); + _pShell->DeclareSymbol("persistent user FLOAT hud_tmLatencySnapshot;", &hud_tmLatencySnapshot); + _pShell->DeclareSymbol("persistent user FLOAT plr_fBreathingStrength;", &plr_fBreathingStrength); + _pShell->DeclareSymbol("INDEX cht_bKillFinalBoss;", &cht_bKillFinalBoss); + _pShell->DeclareSymbol("INDEX cht_bDebugFinalBoss;", &cht_bDebugFinalBoss); + _pShell->DeclareSymbol("INDEX cht_bDumpFinalBossData;", &cht_bDumpFinalBossData); + _pShell->DeclareSymbol("INDEX cht_bDebugFinalBossAnimations;", &cht_bDebugFinalBossAnimations); + _pShell->DeclareSymbol("INDEX cht_bDumpPlayerShading;", &cht_bDumpPlayerShading); + + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilSpeed[17];", &wpn_fRecoilSpeed); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilLimit[17];", &wpn_fRecoilLimit); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilDampUp[17];", &wpn_fRecoilDampUp); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilDampDn[17];", &wpn_fRecoilDampDn); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilOffset[17];", &wpn_fRecoilOffset); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilFactorP[17];", &wpn_fRecoilFactorP); + _pShell->DeclareSymbol("persistent user FLOAT wpn_fRecoilFactorZ[17];", &wpn_fRecoilFactorZ); + + // cheats + _pShell->DeclareSymbol("user INDEX cht_bGod;", &cht_bGod); + _pShell->DeclareSymbol("user INDEX cht_bFly;", &cht_bFly); + _pShell->DeclareSymbol("user INDEX cht_bGhost;", &cht_bGhost); + _pShell->DeclareSymbol("user INDEX cht_bInvisible;", &cht_bInvisible); + _pShell->DeclareSymbol("user INDEX cht_bGiveAll;", &cht_bGiveAll); + _pShell->DeclareSymbol("user INDEX cht_bKillAll;", &cht_bKillAll); + _pShell->DeclareSymbol("user INDEX cht_bOpen;", &cht_bOpen); + _pShell->DeclareSymbol("user INDEX cht_bAllMessages;", &cht_bAllMessages); + _pShell->DeclareSymbol("user FLOAT cht_fTranslationMultiplier ;", &cht_fTranslationMultiplier); + _pShell->DeclareSymbol("user INDEX cht_bRefresh;", &cht_bRefresh); + // this one is masqueraded cheat enable variable + _pShell->DeclareSymbol("INDEX cht_bEnable;", &cht_bEnable); + + // this cheat is always enabled + _pShell->DeclareSymbol("user INDEX cht_iGoToMarker;", &cht_iGoToMarker); + + // player speed and view parameters, not declared except in internal build + #if 0 + _pShell->DeclareSymbol("user FLOAT plr_fViewHeightStand;", &plr_fViewHeightStand); + _pShell->DeclareSymbol("user FLOAT plr_fViewHeightCrouch;",&plr_fViewHeightCrouch); + _pShell->DeclareSymbol("user FLOAT plr_fViewHeightSwim;", &plr_fViewHeightSwim); + _pShell->DeclareSymbol("user FLOAT plr_fViewHeightDive;", &plr_fViewHeightDive); + _pShell->DeclareSymbol("user FLOAT plr_fViewDampFactor;", &plr_fViewDampFactor); + _pShell->DeclareSymbol("user FLOAT plr_fViewDampLimitGroundUp;", &plr_fViewDampLimitGroundUp); + _pShell->DeclareSymbol("user FLOAT plr_fViewDampLimitGroundDn;", &plr_fViewDampLimitGroundDn); + _pShell->DeclareSymbol("user FLOAT plr_fViewDampLimitWater;", &plr_fViewDampLimitWater); + _pShell->DeclareSymbol("user FLOAT plr_fAcceleration;", &plr_fAcceleration); + _pShell->DeclareSymbol("user FLOAT plr_fDeceleration;", &plr_fDeceleration); + _pShell->DeclareSymbol("user FLOAT plr_fSpeedForward;", &plr_fSpeedForward); + _pShell->DeclareSymbol("user FLOAT plr_fSpeedBackward;", &plr_fSpeedBackward); + _pShell->DeclareSymbol("user FLOAT plr_fSpeedSide;", &plr_fSpeedSide); + _pShell->DeclareSymbol("user FLOAT plr_fSpeedUp;", &plr_fSpeedUp); + #endif + _pShell->DeclareSymbol("persistent user FLOAT plr_fFOV;", (void*) &plr_fFOV); + _pShell->DeclareSymbol("persistent user FLOAT plr_fFrontClipDistance;", (void*) &plr_fFrontClipDistance); + _pShell->DeclareSymbol("persistent user INDEX plr_bRenderPicked;", (void*) &plr_bRenderPicked); + _pShell->DeclareSymbol("persistent user INDEX plr_bRenderPickedParticles;", (void*) &plr_bRenderPickedParticles); + _pShell->DeclareSymbol("persistent user INDEX plr_bOnlySam;", (void*) &plr_bOnlySam); + _pShell->DeclareSymbol("persistent user INDEX ent_bReportBrokenChains;", (void*) &ent_bReportBrokenChains); + _pShell->DeclareSymbol("persistent user FLOAT ent_tmMentalIn ;", (void*) &ent_tmMentalIn ); + _pShell->DeclareSymbol("persistent user FLOAT ent_tmMentalOut ;", (void*) &ent_tmMentalOut ); + _pShell->DeclareSymbol("persistent user FLOAT ent_tmMentalFade;", (void*) &ent_tmMentalFade); + _pShell->DeclareSymbol("persistent user CTString plr_strLastLevel;", (void*) &plr_strLastLevel); + + // player appearance interface + _pShell->DeclareSymbol("INDEX SetPlayerAppearance(INDEX, INDEX, INDEX, INDEX);", (void *)&SetPlayerAppearance); + + // call player weapons persistant variable initialization + extern void CPlayerWeapons_Init(void); + CPlayerWeapons_Init(); + + // initialize HUD + InitHUD(); + + // precache + CPlayer_Precache(); +} + +// clean up +void CPlayer_OnEndClass(void) +{ + EndHUD(); +} + +CTString GetDifficultyString(void) +{ + if (GetSP()->sp_bMental) { return TRANS("Mental"); } + + switch (GetSP()->sp_gdGameDifficulty) { + case CSessionProperties::GD_TOURIST: return TRANS("Tourist"); + case CSessionProperties::GD_EASY: return TRANS("Easy"); + default: + case CSessionProperties::GD_NORMAL: return TRANS("Normal"); + case CSessionProperties::GD_HARD: return TRANS("Hard"); + case CSessionProperties::GD_EXTREME: return TRANS("Serious"); + } +} +// armor & health constants getters + +FLOAT MaxArmor(void) +{ + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + return 300; + } else { + return 200; + } +} +FLOAT TopArmor(void) +{ + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + return 200; + } else { + return 100; + } +} +FLOAT MaxHealth(void) +{ + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + return 300; + } else { + return 200; + } +} +FLOAT TopHealth(void) +{ + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + return 200; + } else { + return 100; + } +} + +// info structure +static EntityInfo eiPlayerGround = { + EIBT_FLESH, 80.0f, + 0.0f, 1.7f, 0.0f, // source (eyes) + 0.0f, 1.0f, 0.0f, // target (body) +}; +static EntityInfo eiPlayerCrouch = { + EIBT_FLESH, 80.0f, + 0.0f, 1.2f, 0.0f, // source (eyes) + 0.0f, 0.7f, 0.0f, // target (body) +}; +static EntityInfo eiPlayerSwim = { + EIBT_FLESH, 40.0f, + 0.0f, 0.0f, 0.0f, // source (eyes) + 0.0f, 0.0f, 0.0f, // target (body) +}; + + +// animation light specific +#define LIGHT_ANIM_MINIGUN 2 +#define LIGHT_ANIM_TOMMYGUN 3 +#define LIGHT_ANIM_COLT_SHOTGUN 4 +#define LIGHT_ANIM_NONE 5 + +const char *NameForState(PlayerState pst) +{ + switch(pst) { + case PST_STAND: return "stand"; + case PST_CROUCH: return "crouch"; + case PST_FALL: return "fall"; + case PST_SWIM: return "swim"; + case PST_DIVE: return "dive"; + default: return "???"; + }; +} + + +// print explanation on how a player died +void PrintPlayerDeathMessage(CPlayer *ppl, const EDeath &eDeath) +{ + CTString strMyName = ppl->GetPlayerName(); + CEntity *penKiller = eDeath.eLastDamage.penInflictor; + // if killed by a valid entity + if (penKiller!=NULL) { + // if killed by a player + if (IsOfClass(penKiller, "Player")) { + // if not self + if (penKiller!=ppl) { + CTString strKillerName = ((CPlayer*)penKiller)->GetPlayerName(); + + if(eDeath.eLastDamage.dmtType==DMT_TELEPORT) { + CPrintF(TRANS("%s telefragged %s\n"), (const char*)strKillerName, (const char*)strMyName); + } else if(eDeath.eLastDamage.dmtType==DMT_CLOSERANGE) { + CPrintF(TRANS("%s cut %s into pieces\n"), (const char*)strKillerName, (const char*)strMyName); + } else if(eDeath.eLastDamage.dmtType==DMT_BULLET) { + CPrintF(TRANS("%s poured lead into %s\n"), (const char*)strKillerName, (const char*)strMyName); + } else if(eDeath.eLastDamage.dmtType==DMT_PROJECTILE || eDeath.eLastDamage.dmtType==DMT_EXPLOSION) { + CPrintF(TRANS("%s blew %s away\n"), (const char*)strKillerName, (const char*)strMyName); + } else if(eDeath.eLastDamage.dmtType==DMT_CANNONBALL) { + CPrintF(TRANS("%s smashed %s with a cannon\n"), (const char*)strKillerName, (const char*)strMyName); + } else if(eDeath.eLastDamage.dmtType==DMT_CANNONBALL_EXPLOSION) { + CPrintF(TRANS("%s nuked %s\n"), (const char*)strKillerName, (const char*)strMyName); + } else { + CPrintF(TRANS("%s killed %s\n"), (const char*)strKillerName, (const char*)strMyName); + } + } else { + // make message from damage type + switch(eDeath.eLastDamage.dmtType) { + case DMT_DROWNING: CPrintF(TRANS("%s drowned\n"), (const char*)strMyName); break; + case DMT_BURNING: CPrintF(TRANS("%s burst into flames\n"), (const char*)strMyName); break; + case DMT_SPIKESTAB: CPrintF(TRANS("%s fell into a spike-hole\n"), (const char*)strMyName); break; + case DMT_FREEZING: CPrintF(TRANS("%s has frozen\n"), (const char*)strMyName); break; + case DMT_ACID: CPrintF(TRANS("%s dissolved\n"), (const char*)strMyName); break; + case DMT_PROJECTILE: + case DMT_EXPLOSION: + CPrintF(TRANS("%s blew himself away\n"), (const char*)strMyName); break; + default: CPrintF(TRANS("%s has committed suicide\n"), (const char*)strMyName); + } + } + // if killed by an enemy + } else if (IsDerivedFromClass(penKiller, "Enemy Base")) { + // check for telefrag first + if(eDeath.eLastDamage.dmtType==DMT_TELEPORT) { + CPrintF(TRANS("%s was telefragged\n"), (const char*)strMyName); + return; + } + // describe how this enemy killed player + CPrintF("%s\n", (const char*)((CEnemyBase*)penKiller)->GetPlayerKillDescription(strMyName, eDeath)); + + // if killed by some other entity + } else { + // make message from damage type + switch(eDeath.eLastDamage.dmtType) { + case DMT_SPIKESTAB: CPrintF(TRANS("%s was pierced\n"), (const char*)strMyName); break; + case DMT_BRUSH: CPrintF(TRANS("%s was squashed\n"), (const char*)strMyName); break; + case DMT_ABYSS: CPrintF(TRANS("%s went over the edge\n"), (const char*)strMyName); break; + case DMT_IMPACT: CPrintF(TRANS("%s swashed\n"), (const char*)strMyName); break; + case DMT_HEAT: CPrintF(TRANS("%s stood in the sun for too long\n"), (const char*)strMyName); break; + default: CPrintF(TRANS("%s passed away\n"), (const char*)strMyName); + } + } + // if no entity pointer (shouldn't happen) + } else { + CPrintF(TRANS("%s is missing in action\n"), (const char*)strMyName); + } +} + +%} + +class export CPlayer : CPlayerEntity { +name "Player"; +thumbnail ""; +features "ImplementsOnInitClass", "ImplementsOnEndClass", "CanBePredictable"; + +properties: + 1 CTString m_strName "Name" = "", + 2 COLOR m_ulLastButtons = 0x0, // buttons last pressed + 3 FLOAT m_fArmor = 0.0f, // armor + 4 CTString m_strGroup = "", // group name for world change + 5 INDEX m_ulKeys = 0, // mask for all picked-up keys + 6 FLOAT m_fMaxHealth = 1, // default health supply player can have + 7 INDEX m_ulFlags = 0, // various flags + + 16 CEntityPointer m_penWeapons, // player weapons + 17 CEntityPointer m_penAnimator, // player animator + 18 CEntityPointer m_penView, // player view + 19 CEntityPointer m_pen3rdPersonView, // player 3rd person view + 20 INDEX m_iViewState=PVT_PLAYEREYES, // view state + 21 INDEX m_iLastViewState=PVT_PLAYEREYES, // last view state + + 26 CAnimObject m_aoLightAnimation, // light animation object + 27 FLOAT m_fDamageAmmount = 0.0f, // how much was last wound + 28 FLOAT m_tmWoundedTime = 0.0f, // when was last wound + 29 FLOAT m_tmScreamTime = 0.0f, // when was last wound sound played + + 34 enum PlayerState m_pstState = PST_STAND, // current player state + 35 FLOAT m_fFallTime = 0.0f, // time passed when falling + 36 FLOAT m_fSwimTime = 0.0f, // time when started swimming + 45 FLOAT m_tmOutOfWater = 0.0f, // time when got out of water last time + 37 FLOAT m_tmMoveSound = 0.0f, // last time move sound was played + 38 BOOL m_bMoveSoundLeft = TRUE, // left or right walk channel is current + 39 FLOAT m_tmNextAmbientOnce = 0.0f, // next time to play local ambient sound + 43 FLOAT m_tmMouthSoundLast = 0.0f, // time last played some repeating mouth sound + + 40 CEntityPointer m_penCamera, // camera for current cinematic sequence, or null + 41 CTString m_strCenterMessage="", // center message + 42 FLOAT m_tmCenterMessageEnd = 0.0f, // last time to show centered message + 48 BOOL m_bPendingMessage = FALSE, // message sound pending to be played + 47 FLOAT m_tmMessagePlay = 0.0f, // when to play the message sound + 49 FLOAT m_tmAnalyseEnd = 0.0f, // last time to show analysation + 50 BOOL m_bComputerInvoked = FALSE, // set if computer was invoked at least once + 57 FLOAT m_tmAnimateInbox = -100.0f, // show animation of inbox icon animation + + 44 CEntityPointer m_penMainMusicHolder, + + 51 FLOAT m_tmLastDamage = -1.0f, + 52 FLOAT m_fMaxDamageAmmount = 0.0f, + 53 FLOAT3D m_vDamage = FLOAT3D(0,0,0), + 54 FLOAT m_tmSpraySpawned = -1.0f, + 55 FLOAT m_fSprayDamage = 0.0f, + 56 CEntityPointer m_penSpray, + + // sounds + 60 CSoundObject m_soWeapon0, + 61 CSoundObject m_soWeapon1, + 62 CSoundObject m_soWeapon2, + 63 CSoundObject m_soWeapon3, + + 70 CSoundObject m_soMouth, // breating, yelling etc. + 71 CSoundObject m_soFootL, // walking etc. + 72 CSoundObject m_soFootR, + 73 CSoundObject m_soBody, // splashing etc. + 74 CSoundObject m_soLocalAmbientLoop, // local ambient that only this player hears + 75 CSoundObject m_soLocalAmbientOnce, // local ambient that only this player hears + 76 CSoundObject m_soMessage, // message sounds + 77 CSoundObject m_soHighScore, // high score sound + 78 CSoundObject m_soSpeech, // for quotes + + 81 INDEX m_iMana = 0, // current score worth for killed player + 94 FLOAT m_fManaFraction = 0.0f,// fractional part of mana, for slow increase with time + 84 INDEX m_iHighScore = 0, // internal hiscore for demo playing + 85 INDEX m_iBeatenHighScore = 0, // hiscore that was beaten + 89 FLOAT m_tmLatency = 0.0f, // player-server latency (in seconds) + // for latency averaging + 88 FLOAT m_tmLatencyLastAvg = 0.0f, + 87 FLOAT m_tmLatencyAvgSum = 0.0f, + 86 INDEX m_ctLatencyAvg = 0, + + 96 BOOL m_bEndOfLevel = FALSE, + 97 BOOL m_bEndOfGame = FALSE, + 98 INDEX m_iMayRespawn = 0, // must get to 2 to be able to respawn + 99 FLOAT m_tmSpawned = 0.0f, // when player was spawned + 100 FLOAT3D m_vDied = FLOAT3D(0,0,0), // where player died (for respawn in-place) + 101 FLOAT3D m_aDied = FLOAT3D(0,0,0), + + // statistics + 103 FLOAT m_tmEstTime = 0.0f, // time estimated for this level + 105 INDEX m_iTimeScore = 0, + 106 INDEX m_iStartTime = 0, // game start time (ansi c time_t type) + 107 INDEX m_iEndTime = 0, // game end time (ansi c time_t type) + 108 FLOAT m_tmLevelStarted = 0.0f, // game time when level started + 93 CTString m_strLevelStats = "", // detailed statistics for each level + + // auto action vars + 110 CEntityPointer m_penActionMarker, // current marker for auto actions + 111 FLOAT m_fAutoSpeed = 0.0f, // speed to go towards the marker + 112 INDEX m_iAutoOrgWeapon = 0, // original weapon for autoactions + 113 FLOAT3D m_vAutoSpeed = FLOAT3D(0,0,0), + 114 FLOAT m_tmSpiritStart = 0.0f, + 115 FLOAT m_tmFadeStart = 0.0f, + + // 'picked up' display vars + 120 FLOAT m_tmLastPicked = -10000.0f, // when something was last picked up + 121 CTString m_strPickedName = "", // name of item picked + 122 FLOAT m_fPickedAmmount = 0.0f, // total picked ammount + 123 FLOAT m_fPickedMana = 0.0f, // total picked mana + + // shaker values + 130 INDEX m_iLastHealth = 0, + 131 INDEX m_iLastArmor = 0, + 132 INDEX m_iLastAmmo = 0, + 135 FLOAT m_tmHealthChanged = -9, + 136 FLOAT m_tmArmorChanged = -9, + 137 FLOAT m_tmAmmoChanged = -9, + + 138 FLOAT m_tmMinigunAutoFireStart = -1.0f, + + 150 FLOAT3D m_vLastStain = FLOAT3D(0,0,0), // where last stain was left + + // for mouse lag elimination via prescanning + 151 ANGLE3D m_aLastRotation = FLOAT3D(0,0,0), + 152 ANGLE3D m_aLastViewRotation = FLOAT3D(0,0,0), + 153 FLOAT3D m_vLastTranslation = FLOAT3D(0,0,0), + 154 ANGLE3D m_aLocalRotation = FLOAT3D(0,0,0), + 155 ANGLE3D m_aLocalViewRotation = FLOAT3D(0,0,0), + 156 FLOAT3D m_vLocalTranslation = FLOAT3D(0,0,0), + + +{ + ShellLaunchData ShellLaunchData_array; // array of data describing flying empty shells + INDEX m_iFirstEmptySLD; // index of last added empty shell + + ULONG ulButtonsNow; ULONG ulButtonsBefore; + ULONG ulNewButtons; + ULONG ulReleasedButtons; + + // listener + CSoundListener sliSound; + // light + CLightSource m_lsLightSource; + + TIME m_tmPredict; // time to predict the entity to + + // all messages in the inbox + CDynamicStackArray m_acmiMessages; + INDEX m_ctUnreadMessages; + + // statistics + PlayerStats m_psLevelStats; + PlayerStats m_psLevelTotal; + PlayerStats m_psGameStats; + PlayerStats m_psGameTotal; + + CModelObject m_moRender; // model object to render - this one can be customized +} + +components: + 1 class CLASS_PLAYER_WEAPONS "Classes\\PlayerWeapons.ecl", + 2 class CLASS_PLAYER_ANIMATOR "Classes\\PlayerAnimator.ecl", + 3 class CLASS_PLAYER_VIEW "Classes\\PlayerView.ecl", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 5 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + +// sounds +150 sound SOUND_WATER_ENTER "Sounds\\Player\\WaterEnter.wav", +151 sound SOUND_WATER_LEAVE "Sounds\\Player\\WaterLeave.wav", +152 sound SOUND_WALK_L "Sounds\\Player\\WalkL.wav", +153 sound SOUND_WALK_R "Sounds\\Player\\WalkR.wav", +154 sound SOUND_SWIM_L "Sounds\\Player\\SwimL.wav", +155 sound SOUND_SWIM_R "Sounds\\Player\\SwimR.wav", +156 sound SOUND_DIVE_L "Sounds\\Player\\Dive.wav", +157 sound SOUND_DIVE_R "Sounds\\Player\\Dive.wav", +158 sound SOUND_DIVEIN "Sounds\\Player\\DiveIn.wav", +159 sound SOUND_DIVEOUT "Sounds\\Player\\DiveOut.wav", +160 sound SOUND_DROWN "Sounds\\Player\\Drown.wav", +161 sound SOUND_INHALE0 "Sounds\\Player\\Inhale00.wav", +162 sound SOUND_JUMP "Sounds\\Player\\Jump.wav", +163 sound SOUND_LAND "Sounds\\Player\\Land.wav", +166 sound SOUND_DEATH "Sounds\\Player\\Death.wav", +167 sound SOUND_DEATHWATER "Sounds\\Player\\DeathWater.wav", +168 sound SOUND_WATERAMBIENT "Sounds\\Player\\Underwater.wav", +169 sound SOUND_WATERBUBBLES "Sounds\\Player\\Bubbles.wav", +170 sound SOUND_WATERWALK_L "Sounds\\Player\\WalkWaterL.wav", +171 sound SOUND_WATERWALK_R "Sounds\\Player\\WalkWaterR.wav", +172 sound SOUND_INHALE1 "Sounds\\Player\\Inhale01.wav", +173 sound SOUND_INHALE2 "Sounds\\Player\\Inhale02.wav", +174 sound SOUND_INFO "Sounds\\Player\\Info.wav", +175 sound SOUND_WALK_SAND_L "Sounds\\Player\\WalkSandL.wav", +176 sound SOUND_WALK_SAND_R "Sounds\\Player\\WalkSandR.wav", +//178 sound SOUND_HIGHSCORE "Sounds\\Player\\HighScore.wav", +180 sound SOUND_WOUNDWEAK "Sounds\\Player\\WoundWeak.wav", +181 sound SOUND_WOUNDMEDIUM "Sounds\\Player\\WoundMedium.wav", +182 sound SOUND_WOUNDSTRONG "Sounds\\Player\\WoundStrong.wav", +185 sound SOUND_WOUNDWATER "Sounds\\Player\\WoundWater.wav", + +// ************** FLESH PARTS ************** +210 model MODEL_FLESH "Models\\Effects\\Debris\\Flesh\\Flesh.mdl", +211 model MODEL_FLESH_APPLE "Models\\Effects\\Debris\\Fruits\\Apple.mdl", +212 model MODEL_FLESH_BANANA "Models\\Effects\\Debris\\Fruits\\Banana.mdl", +213 model MODEL_FLESH_BURGER "Models\\Effects\\Debris\\Fruits\\CheeseBurger.mdl", +214 model MODEL_FLESH_LOLLY "Models\\Effects\\Debris\\Fruits\\LollyPop.mdl", +215 model MODEL_FLESH_ORANGE "Models\\Effects\\Debris\\Fruits\\Orange.mdl", + +220 texture TEXTURE_FLESH_RED "Models\\Effects\\Debris\\Flesh\\FleshRed.tex", +221 texture TEXTURE_FLESH_GREEN "Models\\Effects\\Debris\\Flesh\\FleshGreen.tex", +222 texture TEXTURE_FLESH_APPLE "Models\\Effects\\Debris\\Fruits\\Apple.tex", +223 texture TEXTURE_FLESH_BANANA "Models\\Effects\\Debris\\Fruits\\Banana.tex", +224 texture TEXTURE_FLESH_BURGER "Models\\Effects\\Debris\\Fruits\\CheeseBurger.tex", +225 texture TEXTURE_FLESH_LOLLY "Models\\Effects\\Debris\\Fruits\\LollyPop.tex", +226 texture TEXTURE_FLESH_ORANGE "Models\\Effects\\Debris\\Fruits\\Orange.tex", + + +functions: + + void AddBouble( FLOAT3D vPos, FLOAT3D vSpeedRelative) + { + ShellLaunchData &sld = m_asldData[m_iFirstEmptySLD]; + sld.sld_vPos = vPos; + const FLOATmatrix3D &m = GetRotationMatrix(); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sld.sld_vUp = vUp; + sld.sld_vSpeed = vSpeedRelative*m; + sld.sld_tmLaunch = _pTimer->CurrentTick(); + sld.sld_estType = ESL_BUBBLE; + // move to next shell position + m_iFirstEmptySLD = (m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + + + void ClearShellLaunchData( void) + { + // clear flying shells data array + m_iFirstEmptySLD = 0; + for( INDEX iShell=0; iShellm_moRender); + m_psLevelStats = penOther->m_psLevelStats; + m_psLevelTotal = penOther->m_psLevelTotal; + m_psGameStats = penOther->m_psGameStats ; + m_psGameTotal = penOther->m_psGameTotal ; + + // if creating predictor + if (ulFlags©_PREDICTOR) + { + // copy positions of launched empty shells + memcpy( m_asldData, penOther->m_asldData, sizeof( m_asldData)); + m_iFirstEmptySLD = penOther->m_iFirstEmptySLD; + // all messages in the inbox + m_acmiMessages.Clear(); + m_ctUnreadMessages = 0; + //m_lsLightSource; + SetupLightSource(); //? is this ok !!!! + + // if normal copying + } else { + // copy messages + m_acmiMessages = penOther->m_acmiMessages; + m_ctUnreadMessages = penOther->m_ctUnreadMessages; + } + } + + // update smoothed (average latency) + void UpdateLatency(FLOAT tmLatencyNow) + { + TIME tmNow = _pTimer->GetHighPrecisionTimer().GetSeconds(); + + // if not enough time passed + if (tmNowIsPlayerLocal(this)) { + en_tmPing = m_tmLatency; + net_tmLatencyAvg = en_tmPing; + } + } + + // check character data for invalid values + void ValidateCharacter(void) + { + // if in single player or flyover + if (GetSP()->sp_bSinglePlayer) { + // always use default model + CPlayerSettings *pps = (CPlayerSettings *)en_pcCharacter.pc_aubAppearance; + memset(pps->ps_achModelFile, 0, sizeof(pps->ps_achModelFile)); + } + } + + void CheckHighScore(void) + { + // if not playing a demo + if (!_pNetwork->IsPlayingDemo()) { + // update our local high score with the external + if (plr_iHiScore>m_iHighScore) { + m_iHighScore = plr_iHiScore; + } + } + + // if current score is better than highscore + if (m_psGameStats.ps_iScore>m_iHighScore) { + // if it is a highscore greater than the last one beaten + if (m_iHighScore>m_iBeatenHighScore) { + // remember that it was beaten + m_iBeatenHighScore = m_iHighScore; + // tell that to player + m_soHighScore.Set3DParameters(25.0f, 5.0f, 1.0f, 1.0f); + //PlaySound(m_soHighScore, SOUND_HIGHSCORE, 0); !!!!####!!!! + } + } + } + + CTString GetPredictName(void) const + { + if (IsPredicted()) { + return "PREDICTED"; + } else if (IsPredictor()) { + return "predictor"; + } else if (GetFlags()&ENF_WILLBEPREDICTED){ + return "WILLBEPREDICTED"; + } else { + return "no prediction"; + } + } + /* Write to stream. */ + void Write_t( CTStream *ostr) // throw char * + { + CPlayerEntity::Write_t(ostr); + // save array of messages + ostr->WriteID_t("MSGS"); + INDEX ctMsg = m_acmiMessages.Count(); + (*ostr)<Write_t(&m_psLevelStats, sizeof(m_psLevelStats)); + ostr->Write_t(&m_psLevelTotal, sizeof(m_psLevelTotal)); + ostr->Write_t(&m_psGameStats , sizeof(m_psGameStats )); + ostr->Write_t(&m_psGameTotal , sizeof(m_psGameTotal )); + } + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CPlayerEntity::Read_t(istr); + // clear flying shells data array + ClearShellLaunchData(); + // load array of messages + istr->ExpectID_t("MSGS"); + INDEX ctMsg; + (*istr)>>ctMsg; + m_acmiMessages.Clear(); + m_ctUnreadMessages = 0; + if( ctMsg>0) { + m_acmiMessages.Push(ctMsg); + for(INDEX iMsg=0; iMsgRead_t(&m_psLevelStats, sizeof(m_psLevelStats)); + istr->Read_t(&m_psLevelTotal, sizeof(m_psLevelTotal)); + istr->Read_t(&m_psGameStats , sizeof(m_psGameStats )); + istr->Read_t(&m_psGameTotal , sizeof(m_psGameTotal )); + + // set your real appearance if possible + ValidateCharacter(); + CTString strDummy; + SetPlayerAppearance(&m_moRender, &en_pcCharacter, strDummy, /*bPreview=*/FALSE); + m_ulFlags |= PLF_SYNCWEAPON; + // setup light source + SetupLightSource(); + }; + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + }; + + // called by other entities to set time prediction parameter + void SetPredictionTime(TIME tmAdvance) // give time interval in advance to set + { + m_tmPredict = _pTimer->CurrentTick()+tmAdvance; + } + + // called by engine to get the upper time limit + TIME GetPredictionTime(void) // return moment in time up to which to predict this entity + { + return m_tmPredict; + } + + // get maximum allowed range for predicting this entity + FLOAT GetPredictionRange(void) + { + return cli_fPredictPlayersRange; + } + + // add to prediction any entities that this entity depends on + void AddDependentsToPrediction(void) + { + m_penWeapons->AddToPrediction(); + m_penAnimator->AddToPrediction(); + m_penView->AddToPrediction(); + m_pen3rdPersonView->AddToPrediction(); + } + + // get in-game time for statistics + TIME GetStatsInGameTimeLevel(void) + { + if(m_bEndOfLevel) { + return m_psLevelStats.ps_tmTime; + } else { + return _pNetwork->GetGameTime()-m_tmLevelStarted; + } + } + TIME GetStatsInGameTimeGame(void) + { + if(m_bEndOfLevel) { + return m_psGameStats.ps_tmTime; + } else { + return m_psGameStats.ps_tmTime + (_pNetwork->GetGameTime()-m_tmLevelStarted); + } + } + + FLOAT GetStatsRealWorldTime(void) + { + time_t timeNow; + if(m_bEndOfLevel) { + timeNow = m_iEndTime; + } else { + time(&timeNow); + } + return (FLOAT)difftime( timeNow, m_iStartTime); + } + + CTString GetStatsRealWorldStarted(void) + { + struct tm *newtime; + STUBBED("this isn't 64-bit clean"); + time_t t = (time_t) m_iStartTime; + newtime = localtime(&t); + + setlocale(LC_ALL, ""); + CTString strTimeline; + char achTimeLine[256]; + strftime( achTimeLine, sizeof(achTimeLine)-1, "%a %x %H:%M", newtime); + strTimeline = achTimeLine; + setlocale(LC_ALL, "C"); + return strTimeline; + } + + // fill in player statistics + export void GetStats( CTString &strStats, const CompStatType csType, INDEX ctCharsPerRow) + { + + // get proper type of stats + if( csType==CST_SHORT) { + GetShortStats(strStats); + } else { + ASSERT(csType==CST_DETAIL); + + strStats = "\n"; + _ctAlignWidth = Min(ctCharsPerRow, INDEX(60)); + + if (GetSP()->sp_bCooperative) { + if (GetSP()->sp_bSinglePlayer) { + GetDetailStatsSP(strStats, 0); + } else { + GetDetailStatsCoop(strStats); + } + } else { + GetDetailStatsDM(strStats); + } + } + } + + // get short one-line statistics - used for savegame descriptions and similar + void GetShortStats(CTString &strStats) + { + strStats.PrintF( TRANS("%s %s Score: %d Kills: %d/%d"), + (const char*)GetDifficultyString(), (const char*)TimeToString(GetStatsInGameTimeLevel()), + m_psLevelStats.ps_iScore, m_psLevelStats.ps_iKills, m_psLevelTotal.ps_iKills); + } + + // get detailed statistics for deathmatch game + void GetDetailStatsDM(CTString &strStats) + { + extern INDEX SetAllPlayersStats( INDEX iSortKey); + extern CPlayer *_apenPlayers[NET_MAXGAMEPLAYERS]; + // determine type of game + const BOOL bFragMatch = GetSP()->sp_bUseFrags; + + // fill players table + const INDEX ctPlayers = SetAllPlayersStats(bFragMatch?5:3); // sort by frags or by score + + // get time elapsed since the game start + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%s", (const char*)TRANS("TIME"), (const char*)TimeToString(_pNetwork->GetGameTime()))); + strStats+="\n"; + + // find maximum frags/score that one player has + INDEX iMaxFrags = LowerLimit(INDEX(0)); + INDEX iMaxScore = LowerLimit(INDEX(0)); + {for(INDEX iPlayer=0; iPlayerm_psLevelStats.ps_iKills); + iMaxScore = Max(iMaxScore, penPlayer->m_psLevelStats.ps_iScore); + }} + + // print game limits + const CSessionProperties &sp = *GetSP(); + if (sp.sp_iTimeLimit>0) { + FLOAT fTimeLeft = ClampDn(sp.sp_iTimeLimit*60.0f - _pNetwork->GetGameTime(), 0.0f); + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%s", TRANS("TIME LEFT"), (const char*)TimeToString(fTimeLeft))); + strStats+="\n"; + } + if (bFragMatch && sp.sp_iFragLimit>0) { + INDEX iFragsLeft = ClampDn(sp.sp_iFragLimit-iMaxFrags, INDEX(0)); + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%d", TRANS("FRAGS LEFT"), iFragsLeft)); + strStats+="\n"; + } + if (!bFragMatch && sp.sp_iScoreLimit>0) { + INDEX iScoreLeft = ClampDn(sp.sp_iScoreLimit-iMaxScore, INDEX(0)); + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%d", TRANS("SCORE LEFT"), iScoreLeft)); + strStats+="\n"; + } + strStats += "\n"; + + CTString strRank = TRANS("NO."); + CTString strFrag = bFragMatch ? TRANS("FRAGS"):TRANS("SCORE"); + CTString strPing = TRANS("PING"); + CTString strName = TRANS("PLAYER"); + INDEX ctRankChars = Max(strRank.Length(), INDEX(3)) ; + INDEX ctFragChars = Max(strFrag.Length(), INDEX(7)) ; + INDEX ctPingChars = Max(strPing.Length(), INDEX(5)) ; + INDEX ctNameChars = Max(strName.Length(), INDEX(20)); + + // header + strStats += "^cFFFFFF"; + strStats += PadStringRight(strRank, ctRankChars)+" "; + strStats += PadStringLeft (strFrag, ctFragChars)+" "; + strStats += PadStringLeft (strPing, ctPingChars)+" "; + strStats += PadStringRight(strName, ctNameChars)+" "; + strStats += "^r"; + strStats += "\n\n"; + {for(INDEX iPlayer=0; iPlayeren_tmPing*1000.0f); + INDEX iScore = bFragMatch ? penPlayer->m_psLevelStats.ps_iKills : penPlayer->m_psLevelStats.ps_iScore; + CTString strName = penPlayer->GetPlayerName(); + + strStats += PadStringRight(CTString(0, "%d", iPlayer+1), ctRankChars)+" "; + strStats += PadStringLeft (CTString(0, "%d", iScore), ctFragChars)+" "; + strStats += PadStringLeft (CTString(0, "%d", iPing), ctPingChars)+" "; + strStats += PadStringRight(strName, ctNameChars)+" "; + strStats += "\n"; + }} + } + + // get singleplayer statistics + void GetDetailStatsCoop(CTString &strStats) + { + // first put in your full stats + strStats += "^b"+CenterString(TRANS("YOUR STATS"))+"^r\n"; + strStats+="\n"; + GetDetailStatsSP(strStats, 1); + + // get stats from all players + extern INDEX SetAllPlayersStats( INDEX iSortKey); + extern CPlayer *_apenPlayers[NET_MAXGAMEPLAYERS]; + const INDEX ctPlayers = SetAllPlayersStats(3); // sort by score + + // for each player + PlayerStats psSquadLevel = PlayerStats(); + PlayerStats psSquadGame = PlayerStats(); + {for( INDEX iPlayer=0; iPlayerm_psLevelStats; + PlayerStats psGame = penPlayer->m_psGameStats ; + psSquadLevel.ps_iScore += psLevel.ps_iScore ; + psSquadLevel.ps_iKills += psLevel.ps_iKills ; + psSquadLevel.ps_iDeaths += psLevel.ps_iDeaths ; + psSquadLevel.ps_iSecrets += psLevel.ps_iSecrets ; + psSquadGame.ps_iScore += psGame.ps_iScore ; + psSquadGame.ps_iKills += psGame.ps_iKills ; + psSquadGame.ps_iDeaths += psGame.ps_iDeaths ; + psSquadGame.ps_iSecrets += psGame.ps_iSecrets ; + }} + + // add squad stats + strStats+="\n"; + strStats += "^b"+CenterString(TRANS("SQUAD TOTAL"))+"^r\n"; + strStats+="\n"; + strStats+=CTString(0, "^cFFFFFF%s^r", TranslateConst(en_pwoWorld->GetName(), 0)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("SCORE"), psSquadLevel.ps_iScore)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("DEATHS"), psSquadLevel.ps_iDeaths)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("KILLS"), psSquadLevel.ps_iKills, m_psLevelTotal.ps_iKills)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("SECRETS"), psSquadLevel.ps_iSecrets, m_psLevelTotal.ps_iSecrets)); + strStats+="\n"; + strStats+="\n"; + strStats+=CTString("^cFFFFFF")+TRANS("TOTAL")+"^r\n"; + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("SCORE"), psSquadGame.ps_iScore)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("DEATHS"), psSquadGame.ps_iDeaths)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("KILLS"), psSquadGame.ps_iKills, m_psGameTotal.ps_iKills)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("SECRETS"), psSquadGame.ps_iSecrets, m_psGameTotal.ps_iSecrets)); + strStats+="\n"; + strStats+="\n"; + + + strStats+="\n"; + strStats += "^b"+CenterString(TRANS("OTHER PLAYERS"))+"^r\n"; + strStats+="\n"; + + // for each player + {for(INDEX iPlayer=0; iPlayerGetPlayerName())+"^r\n\n"; + penPlayer->GetDetailStatsSP(strStats, 2); + strStats+="\n"; + }} + } + + // get singleplayer statistics + void GetDetailStatsSP(CTString &strStats, INDEX iCoopType) + { + if (iCoopType<=1) { + if (m_bEndOfGame) { + if (GetWorld()->wo_fnmFileName==plr_strLastLevel) { + strStats+=CTString(TRANS("^f4YOU HAVE FINISHED THE LIMITED EDITION!^F\n"))+ + TRANS("8 more levels are available in\nthe full version of\n'Serious Sam: The First Encounter'!\n\n"); + } else if (GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_EXTREME) { + strStats+=TRANS("^f4SERIOUS GAME FINISHED,\nMENTAL MODE IS NOW ENABLED!^F\n\n"); + } else if (GetSP()->sp_bMental) { + strStats+=TRANS("^f4YOU HAVE MASTERED THE GAME!^F\n\n"); + } + } + } + + if (iCoopType<=1) { + // report total score info + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%d", TRANS("TOTAL SCORE"), m_psGameStats.ps_iScore)); + strStats+="\n"; + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%s", TRANS("DIFFICULTY"), (const char*)GetDifficultyString())); + strStats+="\n"; + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%s", TRANS("STARTED"), (const char*)GetStatsRealWorldStarted())); + strStats+="\n"; + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%s", TRANS("PLAYING TIME"), (const char*)TimeToString(GetStatsRealWorldTime()))); + strStats+="\n"; + if( m_psGameStats.ps_iScore<=plr_iHiScore) { + strStats+=AlignString(CTString(0, "^cFFFFFF%s:^r\n%d", TRANS("HI-SCORE"), plr_iHiScore)); + } else { + strStats+=TRANS("YOU BEAT THE HI-SCORE!"); + } + strStats+="\n\n"; + } + + // report this level statistics + strStats+=CTString(0, "^cFFFFFF%s^r", TranslateConst(en_pwoWorld->GetName(), 0)); + strStats+="\n"; + if (iCoopType<=1) { + if( m_bEndOfLevel) { + strStats+=AlignString(CTString(0, " %s:\n%s", TRANS("ESTIMATED TIME"), (const char*)TimeToString(m_tmEstTime))); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("TIME BONUS"), m_iTimeScore)); + strStats+="\n"; + strStats+="\n"; + } +// } else { +// strStats+=CTString("^cFFFFFF")+TRANS("THIS LEVEL")+"^r\n"; + } + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("SCORE"), m_psLevelStats.ps_iScore)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("KILLS"), m_psLevelStats.ps_iKills, m_psLevelTotal.ps_iKills)); + strStats+="\n"; + if (iCoopType>=1) { + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("DEATHS"), m_psLevelStats.ps_iDeaths, m_psLevelTotal.ps_iDeaths)); + strStats+="\n"; + } + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("SECRETS"), m_psLevelStats.ps_iSecrets, m_psLevelTotal.ps_iSecrets)); + strStats+="\n"; + if (iCoopType<=1) { + strStats+=AlignString(CTString(0, " %s:\n%s", TRANS("TIME"), (const char*)TimeToString(GetStatsInGameTimeLevel()))); + strStats+="\n"; + } + strStats+="\n"; + + // report total game statistics + strStats+=CTString("^cFFFFFF")+TRANS("TOTAL")+"^r"; + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("SCORE"), m_psGameStats.ps_iScore)); + strStats+="\n"; + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("KILLS"), m_psGameStats.ps_iKills, m_psGameTotal.ps_iKills)); + strStats+="\n"; + if (iCoopType>=1) { + strStats+=AlignString(CTString(0, " %s:\n%d", TRANS("DEATHS"), m_psGameStats.ps_iDeaths, m_psGameTotal.ps_iDeaths)); + strStats+="\n"; + } + strStats+=AlignString(CTString(0, " %s:\n%d/%d", TRANS("SECRETS"), m_psGameStats.ps_iSecrets, m_psGameTotal.ps_iSecrets)); + strStats+="\n"; + if (iCoopType<=1) { + strStats+=AlignString(CTString(0, " %s:\n%s", TRANS("GAME TIME"),(const char*) TimeToString(GetStatsInGameTimeGame()))); + strStats+="\n"; + } + strStats+="\n"; + + // set per level outputs + if (iCoopType<=1) { + if(m_strLevelStats!="") { + strStats += CTString("^cFFFFFF")+TRANS("Per level statistics") +"^r\n\n" + m_strLevelStats; + } + } + } + + // provide info for GameSpy enumeration + void GetGameSpyPlayerInfo( INDEX iPlayer, CTString &strOut) + { + CTString strKey; + strKey.PrintF("\\player_%d\\%s", iPlayer, (const char*)GetPlayerName()); + strOut+=strKey; + if (GetSP()->sp_bUseFrags) { + strKey.PrintF("\\frags_%d\\%d", iPlayer, m_psLevelStats.ps_iKills); + strOut+=strKey; + } else { + strKey.PrintF("\\frags_%d\\%d", iPlayer, m_psLevelStats.ps_iScore); + strOut+=strKey; + } + strKey.PrintF("\\ping_%d\\%d", iPlayer, INDEX(ceil(en_tmPing*1000.0f))); + strOut+=strKey; + }; + + // check if message is in inbox + BOOL HasMessage( const CTFileName &fnmMessage) + { + ULONG ulHash = fnmMessage.GetHash(); + INDEX ctMsg = m_acmiMessages.Count(); + for(INDEX iMsg=0; iMsgCurrentTick()+2.0f; + m_soMessage.Set3DParameters(25.0f, 5.0f, 1.0f, 1.0f); + PlaySound(m_soMessage, SOUND_INFO, SOF_3D|SOF_VOLUMETRIC|SOF_LOCAL); + } + } + + void SayVoiceMessage(const CTFileName &fnmMessage) + { + if (GetSettings()->ps_ulFlags&PSF_NOQUOTES) { + return; + } + SetSpeakMouthPitch(); + PlaySound( m_soSpeech, fnmMessage, SOF_3D|SOF_VOLUMETRIC); + } + + // receive all messages in one directory - cheat + void CheatAllMessagesDir(const CTString &strDir) + { + // list the directory + CDynamicStackArray afnmDir; + MakeDirList(afnmDir, strDir, CTFileName(CTString("*.txt")), DLI_RECURSIVE); + + // for each file in the directory + for (INDEX i=0; iCurrentTick() > m_tmLastPicked+PICKEDREPORT_TIME) { + // kill the name + m_strPickedName = ""; + // reset picked mana + m_fPickedMana = 0; + } + // if different than last picked + if (m_strPickedName!=strName) { + // remember name + m_strPickedName = strName; + // reset picked ammount + m_fPickedAmmount = 0; + } + // increase ammount + m_fPickedAmmount+=fAmmount; + m_tmLastPicked = _pTimer->CurrentTick(); + } + + // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 1.0f; + lsNew.ls_colColor = C_WHITE; + lsNew.ls_rFallOff = 2.5f; + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = &m_aoLightAnimation; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + }; + + // play light animation + void PlayLightAnim(INDEX iAnim, ULONG ulFlags) { + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(iAnim, ulFlags); + } + }; + + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + if( cht_bDumpPlayerShading) + { + ANGLE3D a3dHPB; + DirectionVectorToAngles(-vLightDirection, a3dHPB); + UBYTE ubAR, ubAG, ubAB; + UBYTE ubCR, ubCG, ubCB; + ColorToRGB(colAmbient, ubAR, ubAG, ubAB); + ColorToRGB(colLight, ubCR, ubCG, ubCB); + CPrintF("Ambient: %d,%d,%d, Color: %d,%d,%d, Direction HPB (%g,%g,%g)\n", + ubAR, ubAG, ubAB, ubCR, ubCG, ubCB, a3dHPB(1), a3dHPB(2), a3dHPB(3)); + } + + return CPlayerEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + }; + + // get a different model object for rendering + CModelObject *GetModelForRendering(void) + { + // if not yet initialized + if(!(m_ulFlags&PLF_INITIALIZED)) { + // return base model + return GetModelObject(); + } + + // lerp player viewpoint + CPlacement3D plView; + plView.Lerp(en_plLastViewpoint, en_plViewpoint, _pTimer->GetLerpFactor()); + // body and head attachment animation + ((CPlayerAnimator&)*m_penAnimator).BodyAndHeadOrientation(plView); + ((CPlayerAnimator&)*m_penAnimator).OnPreRender(); + // synchronize your appearance with the default model + m_moRender.Synchronize(*GetModelObject()); + if (m_ulFlags&PLF_SYNCWEAPON) { + m_ulFlags &= ~PLF_SYNCWEAPON; + GetPlayerAnimator()->SyncWeapon(); + } + + FLOAT tmNow = _pTimer->GetLerpedCurrentTick(); + + FLOAT fFading = 1.0f; + if (m_tmFadeStart!=0) { + FLOAT fFactor = (tmNow-m_tmFadeStart)/5.0f; + fFactor = Clamp(fFactor, 0.0f, 1.0f); + fFading*=fFactor; + } + + // if invunerable after spawning + FLOAT tmSpawnInvulnerability = GetSP()->sp_tmSpawnInvulnerability; + if (tmSpawnInvulnerability>0 && tmNow-m_tmSpawnedGetEntityWithName("MusicHolder", 0); + } + } + + // update per-level stats + void UpdateLevelStats(void) + { + // clear stats for this level + m_psLevelStats = PlayerStats(); + + // get music holder + if (m_penMainMusicHolder==NULL) { + return; + } + CMusicHolder &mh = (CMusicHolder&)*m_penMainMusicHolder; + + // assure proper count enemies in current world + if (mh.m_ctEnemiesInWorld==0) { + mh.CountEnemies(); + } + // set totals for level and increment for game + m_psLevelTotal.ps_iKills = mh.m_ctEnemiesInWorld; + m_psGameTotal.ps_iKills += mh.m_ctEnemiesInWorld; + m_psLevelTotal.ps_iSecrets = mh.m_ctSecretsInWorld; + m_psGameTotal.ps_iSecrets += mh.m_ctSecretsInWorld; + } + + // check if there is fuss + BOOL IsFuss(void) + { + // if no music holder + if (m_penMainMusicHolder==NULL) { + // no fuss + return FALSE; + } + // if no enemies - no fuss + return ((CMusicHolder*)&*m_penMainMusicHolder)->m_cenFussMakers.Count()>0; + } + + void SetDefaultMouthPitch(void) + { + m_soMouth.Set3DParameters(50.0f, 10.0f, 1.0f, 1.0f); + } + void SetRandomMouthPitch(FLOAT fMin, FLOAT fMax) + { + m_soMouth.Set3DParameters(50.0f, 10.0f, 1.0f, Lerp(fMin, fMax, FRnd())); + } + void SetSpeakMouthPitch(void) + { + m_soSpeech.Set3DParameters(50.0f, 10.0f, 2.0f, 1.0f); + } + + void ApplyShaking(CPlacement3D &plViewer) + { + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + if (pwsc==NULL || pwsc->m_tmShakeStarted<0) { + return; + } + + TIME tm = _pTimer->GetLerpedCurrentTick()-pwsc->m_tmShakeStarted; + if (tm<0) { + return; + } + FLOAT fDistance = (plViewer.pl_PositionVector-pwsc->m_vShakePos).Length(); + FLOAT fIntensity = IntensityAtDistance(pwsc->m_fShakeFalloff, 0, fDistance); + FLOAT fShakeY = SinFast(tm*pwsc->m_tmShakeFrequencyY*360.0f)* + exp(-tm*(pwsc->m_fShakeFade))* + fIntensity*pwsc->m_fShakeIntensityY; + FLOAT fShakeB = SinFast(tm*pwsc->m_tmShakeFrequencyB*360.0f)* + exp(-tm*(pwsc->m_fShakeFade))* + fIntensity*pwsc->m_fShakeIntensityB; + FLOAT fShakeZ = SinFast(tm*pwsc->m_tmShakeFrequencyZ*360.0f)* + exp(-tm*(pwsc->m_fShakeFade))* + fIntensity*pwsc->m_fShakeIntensityZ; + plViewer.pl_PositionVector(2) += fShakeY; + plViewer.pl_PositionVector(3) += fShakeZ; + plViewer.pl_OrientationAngle(3) += fShakeB; + } + + COLOR GetWorldGlaring(void) + { + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + if (pwsc==NULL || pwsc->m_tmGlaringStarted<0) { + return 0; + } + TIME tm = _pTimer->GetLerpedCurrentTick(); + FLOAT fRatio = CalculateRatio(tm, pwsc->m_tmGlaringStarted, pwsc->m_tmGlaringEnded, + pwsc->m_fGlaringFadeInRatio, pwsc->m_fGlaringFadeOutRatio); + COLOR colResult = C_WHITE|(UBYTE(fRatio*255.0f)); + return colResult; + } + +/************************************************************ + * RENDER GAME VIEW * + ************************************************************/ + + // setup viewing parameters for viewing from player or camera + void SetupView(CDrawPort *pdp, CAnyProjection3D &apr, CEntity *&penViewer, + CPlacement3D &plViewer, COLOR &colBlend, BOOL bCamera) + { + // read the exact placement of the view for this tick + GetLerpedAbsoluteViewPlacement(plViewer); + ASSERT(IsValidFloat(plViewer.pl_OrientationAngle(1))&&IsValidFloat(plViewer.pl_OrientationAngle(2))&&IsValidFloat(plViewer.pl_OrientationAngle(3)) ); + // get current entity that the player views from + penViewer = GetViewEntity(); + + INDEX iViewState = m_iViewState; + + if (m_penCamera!=NULL && bCamera) { + iViewState = PVT_SCENECAMERA; + plViewer = m_penCamera->GetLerpedPlacement(); + penViewer = m_penCamera; + } + + // init projection parameters + CPerspectiveProjection3D prPerspectiveProjection; + plr_fFOV = Clamp( plr_fFOV, 1.0f, 160.0f); + ANGLE aFOV = plr_fFOV; + // disable zoom in deathmatch + if (!GetSP()->sp_bCooperative) { + aFOV = 90.0f; + } + if (m_pstState==PST_DIVE && iViewState == PVT_PLAYEREYES) { + TIME tmNow = _pTimer->GetLerpedCurrentTick(); + aFOV+=sin(tmNow*0.79f)*2.0f; + } + ApplyShaking(plViewer); + + colBlend = 0; + if (iViewState == PVT_SCENECAMERA) { + CCamera *pcm = (CCamera*)&*m_penCamera; + prPerspectiveProjection.FOVL() = + Lerp(pcm->m_fLastFOV, pcm->m_fFOV, _pTimer->GetLerpFactor()); + if (pcm->m_tmDelta>0.001f) { + FLOAT fFactor = (_pTimer->GetLerpedCurrentTick()-pcm->m_tmAtMarker)/pcm->m_tmDelta; + fFactor = Clamp( fFactor, 0.0f, 1.0f); + colBlend = LerpColor( pcm->m_colFade0, pcm->m_colFade1, fFactor); + } else { + colBlend = pcm->m_colFade0; + } + } else { + prPerspectiveProjection.FOVL() = aFOV; + } + prPerspectiveProjection.ScreenBBoxL() = FLOATaabbox2D( + FLOAT2D(0.0f, 0.0f), + FLOAT2D((FLOAT)pdp->GetWidth(), (FLOAT)pdp->GetHeight()) + ); + // determine front clip plane + plr_fFrontClipDistance = Clamp( plr_fFrontClipDistance, 0.05f, 0.30f); + FLOAT fFCD = plr_fFrontClipDistance; + // adjust front clip plane if swimming + if( m_pstState==PST_SWIM && iViewState==PVT_PLAYEREYES) { fFCD *= 0.6666f; } + prPerspectiveProjection.FrontClipDistanceL() = fFCD; + prPerspectiveProjection.AspectRatioL() = 1.0f; + // set up viewer position + apr = prPerspectiveProjection; + apr->ViewerPlacementL() = plViewer; + } + + // listen from a given viewer + void ListenFromEntity(CEntity *penListener, const CPlacement3D &plSound) + { + FLOATmatrix3D mRotation; + MakeRotationMatrixFast(mRotation, plSound.pl_OrientationAngle); + sliSound.sli_vPosition = plSound.pl_PositionVector; + sliSound.sli_mRotation = mRotation; + sliSound.sli_fVolume = 1.0f; + sliSound.sli_vSpeed = en_vCurrentTranslationAbsolute; + sliSound.sli_penEntity = penListener; + if (m_pstState == PST_DIVE) { + sliSound.sli_fFilter = 20.0f; + } else { + sliSound.sli_fFilter = 0.0f; + } + INDEX iEnv = 0; + + CBrushSector *pbsc = penListener->GetSectorFromPoint(plSound.pl_PositionVector); + + // for each sector around listener + if (pbsc!=NULL) { + iEnv = pbsc->GetEnvironmentType(); + } + + // get the environment + CEnvironmentType &et = GetWorld()->wo_aetEnvironmentTypes[iEnv]; + sliSound.sli_iEnvironmentType = et.et_iType; + sliSound.sli_fEnvironmentSize = et.et_fSize; + _pSound->Listen(sliSound); + } + + // render dummy view (not connected yet) + void RenderDummyView(CDrawPort *pdp) + { + // clear screen + pdp->Fill( C_BLACK|CT_OPAQUE); + + // if not single player + if (!GetSP()->sp_bSinglePlayer) { + // print a message + PIX pixDPWidth = pdp->GetWidth(); + PIX pixDPHeight = pdp->GetHeight(); + FLOAT fScale = (FLOAT)pixDPWidth/640.0f; + pdp->SetFont( _pfdDisplayFont); + pdp->SetTextScaling( fScale); + pdp->SetTextAspect( 1.0f); + CTString strMsg; + strMsg.PrintF(TRANS("%s connected"), (const char*)GetPlayerName()); + pdp->PutTextCXY( strMsg, pixDPWidth*0.5f, pixDPHeight*0.5f, C_GREEN|CT_OPAQUE); + } + } + + // render view from player + void RenderPlayerView(CDrawPort *pdp, BOOL bShowExtras) + { + // setup view settings + CAnyProjection3D apr; + CEntity *penViewer; + CPlacement3D plViewer; + COLOR colBlend; + SetupView(pdp, apr, penViewer, plViewer, colBlend, FALSE); + + // render the view + ASSERT(IsValidFloat(plViewer.pl_OrientationAngle(1))&&IsValidFloat(plViewer.pl_OrientationAngle(2))&&IsValidFloat(plViewer.pl_OrientationAngle(3))); + _ulPlayerRenderingMask = 1<GetWidth(); + PIX pixDPHeight = pdp->GetHeight(); + FLOAT fScale = (FLOAT)pixDPWidth/640.0f; + + // print center message + if (_pTimer->CurrentTick()SetFont( _pfdDisplayFont); + pdp->SetTextScaling( fScale); + pdp->SetTextAspect( 1.0f); + pdp->PutTextCXY( m_strCenterMessage, pixDPWidth*0.5f, pixDPHeight*0.85f, C_WHITE|0xDD); + // print picked item + } else if (_pTimer->CurrentTick()SetFont( _pfdDisplayFont); + pdp->SetTextScaling( fScale); + pdp->SetTextAspect( 1.0f); + CTString strPicked; + if (m_fPickedAmmount==0) { + strPicked = m_strPickedName; + } else { + strPicked.PrintF("%s +%d", (const char*)m_strPickedName, int(m_fPickedAmmount)); + } + pdp->PutTextCXY( strPicked, pixDPWidth*0.5f, pixDPHeight*0.82f, C_WHITE|0xDD); + if (!GetSP()->sp_bCooperative && !GetSP()->sp_bUseFrags && m_fPickedMana>=1) { + CTString strValue; + strValue.PrintF("%s +%d", TRANS("Value"), INDEX(m_fPickedMana)); + pdp->PutTextCXY( strValue, pixDPWidth*0.5f, pixDPHeight*0.85f, C_WHITE|0xDD); + } + } + + if (_pTimer->CurrentTick()SetFont( _pfdDisplayFont); + pdp->SetTextScaling( fScale); + pdp->SetTextAspect( 1.0f); + UBYTE ubA = int(sin(_pTimer->CurrentTick()*10.0f)*127+128); + pdp->PutTextCXY( TRANS("Analyzing..."), pixDPWidth*0.5f, pixDPHeight*0.2f, C_GREEN|ubA); + } + } + + // render view from camera + void RenderCameraView(CDrawPort *pdp, BOOL bListen) + { + CDrawPort dpCamera; + CDrawPort *pdpCamera = pdp; + if (m_penCamera!=NULL && ((CCamera&)*m_penCamera).m_bWideScreen) { + pdp->MakeWideScreen(&dpCamera); + pdpCamera = &dpCamera; + } + + pdp->Unlock(); + pdpCamera->Lock(); + + // setup view settings + CAnyProjection3D apr; + CEntity *penViewer; + CPlacement3D plViewer; + COLOR colBlend; + SetupView(pdpCamera, apr, penViewer, plViewer, colBlend, TRUE); + + // render the view + ASSERT(IsValidFloat(plViewer.pl_OrientationAngle(1))&&IsValidFloat(plViewer.pl_OrientationAngle(2))&&IsValidFloat(plViewer.pl_OrientationAngle(3))); + _ulPlayerRenderingMask = 1<Unlock(); + pdp->Lock(); + + // camera fading + if ((colBlend&CT_AMASK)!=0) { + pdp->Fill(colBlend); + } + + // print center message + if (_pTimer->CurrentTick()GetWidth(); + PIX pixDPHeight = pdp->GetHeight(); + FLOAT fScale = (FLOAT)pixDPWidth/640.0f; + pdp->SetFont( _pfdDisplayFont); + pdp->SetTextScaling( fScale); + pdp->SetTextAspect( 1.0f); + pdp->PutTextCXY( m_strCenterMessage, pixDPWidth*0.5f, pixDPHeight*0.85f, C_WHITE|0xDD); + } + } + + void RenderGameView(CDrawPort *pdp, void *pvUserData) + { + BOOL bShowExtras = (ULONG(pvUserData)&GRV_SHOWEXTRAS); + + // if not yet initialized + if(!(m_ulFlags&PLF_INITIALIZED) || (m_ulFlags&PLF_DONTRENDER)) { + // render dummy view on the right drawport + CDrawPort dpView(pdp, TRUE); + if(dpView.Lock()) { + RenderDummyView(&dpView); + dpView.Unlock(); + } + return; + } + + // if rendering real game view (not thumbnail, or similar) + if (pvUserData!=0) { + // if rendered a game view recently + CTimerValue tvNow = _pTimer->GetHighPrecisionTimer(); + if ((tvNow-_tvProbingLast).GetSeconds()<0.1) { + // allow probing + _pGfx->gl_bAllowProbing = TRUE; + } + _tvProbingLast = tvNow; + } + +// CPrintF("%s: render\n", GetPredictName()); + + // check for dualhead + BOOL bDualHead = + pdp->IsDualHead() && + GetSP()->sp_gmGameMode!=CSessionProperties::GM_FLYOVER && + m_penActionMarker==NULL; + + // if dualhead, or no camera active + if (bDualHead||m_penCamera==NULL) { + // make left player view + CDrawPort dpView(pdp, TRUE); + if(dpView.Lock()) { + // draw it + RenderPlayerView(&dpView, bShowExtras); + dpView.Unlock(); + } + } + + // if camera active + if (m_penCamera!=NULL) { + // make left or right camera view + CDrawPort dpView(pdp, m_penActionMarker!=NULL); + if(dpView.Lock()) { + // draw it, listen if not dualhead + RenderCameraView(&dpView, !bDualHead); + dpView.Unlock(); + } + // if camera is not active + } else { + // if dualhead + if (bDualHead) { + // render computer on secondary display + cmp_ppenDHPlayer = this; + } + } + }; + + + + +/************************************************************ + * PRE/DO/POST MOVING * + ************************************************************/ + + // premoving for soft player up-down movement + void PreMoving(void) { + /*CPrintF("pos(%s): %g,%g,%g\n", GetPredictName(), + GetPlacement().pl_PositionVector(1), + GetPlacement().pl_PositionVector(2), + GetPlacement().pl_PositionVector(3)); + */ + + ((CPlayerAnimator&)*m_penAnimator).StoreLast(); + CPlayerEntity::PreMoving(); + }; + + // do moving + void DoMoving(void) { + CPlayerEntity::DoMoving(); + ((CPlayerAnimator&)*m_penAnimator).AnimateBanking(); + + if (m_penView!=NULL) { + ((CPlayerView&)*m_penView).DoMoving(); + } + if (m_pen3rdPersonView!=NULL) { + ((CPlayerView&)*m_pen3rdPersonView).DoMoving(); + } + }; + + + // postmoving for soft player up-down movement + void PostMoving(void) + { + CPlayerEntity::PostMoving(); + // never allow a player to be removed from the list of movers + en_ulFlags &= ~ENF_INRENDERING; + + ((CPlayerAnimator&)*m_penAnimator).AnimateSoftEyes(); + //((CPlayerAnimator&)*m_penAnimator).AnimateRecoilPitch(); + + // slowly increase mana with time, faster if player is not moving + m_fManaFraction += + ClampDn( 1.0f-en_vCurrentTranslationAbsolute.Length()/20.0f, 0.0f) * 20.0f + * _pTimer->TickQuantum; + INDEX iNewMana = m_fManaFraction; + m_iMana += iNewMana; + m_fManaFraction -= iNewMana; + + // if in tourist mode + if (GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_TOURIST) { + // slowly increase health with time + FLOAT fHealth = GetHealth(); + FLOAT fTopHealth = TopHealth(); + if (fHealthTickQuantum, fTopHealth)); // one unit per second + } + } + + // update ray hit for weapon target + GetPlayerWeapons()->UpdateTargetingInfo(); + + if (m_pen3rdPersonView!=NULL) { + ((CPlayerView&)*m_pen3rdPersonView).PostMoving(); + } + if (m_penView!=NULL) { + ((CPlayerView&)*m_penView).PostMoving(); + } + + // if didn't have any action in this tick + if (!(m_ulFlags&PLF_APPLIEDACTION)) { + // means we are not connected + SetUnconnected(); + } + + // clear action indicator + m_ulFlags&=~PLF_APPLIEDACTION; + } + + // set player parameters for unconnected state (between the server loads and player reconnects) + void SetUnconnected(void) + { + if (m_ulFlags&PLF_NOTCONNECTED) { + return; + } + m_ulFlags |= PLF_NOTCONNECTED; + + // reset to a dummy state + ForceFullStop(); + SetPhysicsFlags(GetPhysicsFlags() & ~(EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY)); + SetCollisionFlags(GetCollisionFlags() & ~((ECBI_BRUSH|ECBI_MODEL)<BodyAnimationTemplate( + BODY_ANIM_NORMALWALK, BODY_ANIM_COLT_STAND, BODY_ANIM_SHOTGUN_STAND, BODY_ANIM_MINIGUN_STAND, + AOF_LOOPING|AOF_NORESTART); + } + + // set player parameters for connected state + void SetConnected(void) + { + if (!(m_ulFlags&PLF_NOTCONNECTED)) { + return; + } + m_ulFlags &= ~PLF_NOTCONNECTED; + + SetPhysicsFlags(GetPhysicsFlags() | (EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY)); + SetCollisionFlags(GetCollisionFlags() | ((ECBI_BRUSH|ECBI_MODEL)<0) { + CRC_AddFLOAT(ulCRC, m_fManaFraction); + } + CRC_AddFLOAT(ulCRC, m_fArmor); + } + + + // dump sync data to text file + void DumpSync_t(CTStream &strm, INDEX iExtensiveSyncCheck) // throw char * + { + CPlayerEntity::DumpSync_t(strm, iExtensiveSyncCheck); + strm.FPrintF_t("Score: %d\n", m_psLevelStats.ps_iScore); + strm.FPrintF_t("m_iMana: %d\n", m_iMana); + strm.FPrintF_t("m_fManaFraction: %g(%08x)\n", m_fManaFraction, (ULONG&)m_fManaFraction); + strm.FPrintF_t("m_fArmor: %g(%08x)\n", m_fArmor, (ULONG&)m_fArmor); + } + +/************************************************************ + * DAMAGE OVERRIDE (PLAYER HAS ARMOR) * + ************************************************************/ + + + // leave stain + virtual void LeaveStain( BOOL bGrow) + { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + + // on plane + if( GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + // if near to polygon and away from last stain point + if( (vPoint-GetPlacement().pl_PositionVector).Length()<0.5f + && (m_vLastStain-vPoint).Length()>1.0f ) { + m_vLastStain = vPoint; + FLOAT fStretch = box.Size().Length(); + ese.colMuliplier = C_WHITE|CT_OPAQUE; + // stain + if (bGrow) { + ese.betType = BET_BLOODSTAINGROW; + ese.vStretch = FLOAT3D( fStretch*1.5f, fStretch*1.5f, 1.0f); + } else { + ese.betType = BET_BLOODSTAIN; + ese.vStretch = FLOAT3D( fStretch*0.75f, fStretch*0.75f, 1.0f); + } + ese.vNormal = FLOAT3D( vPlaneNormal); + ese.vDirection = FLOAT3D( 0, 0, 0); + FLOAT3D vPos = vPoint+ese.vNormal/50.0f*(FRnd()+0.5f); + CEntityPointer penEffect = CreateEntity( CPlacement3D(vPos, ANGLE3D(0,0,0)), CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + } + }; + + + void DamageImpact(enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // if exploded + if (GetRenderType()!=RT_MODEL) { + // do nothing + return; + } + + if (dmtType == DMT_ABYSS || dmtType == DMT_SPIKESTAB) { + return; + } + + fDamageAmmount = Clamp(fDamageAmmount, 0.0f, 5000.0f); + + FLOAT fKickDamage = fDamageAmmount; + if( (dmtType == DMT_EXPLOSION) || (dmtType == DMT_IMPACT) || (dmtType == DMT_CANNONBALL_EXPLOSION) ) + { + fKickDamage*=1.5; + } + if (dmtType==DMT_DROWNING || dmtType==DMT_CLOSERANGE) { + fKickDamage /= 10; + } + + // get passed time since last damage + TIME tmNow = _pTimer->CurrentTick(); + TIME tmDelta = tmNow-m_tmLastDamage; + m_tmLastDamage = tmNow; + + // fade damage out + if (tmDelta>=_pTimer->TickQuantum*3) { + m_vDamage=FLOAT3D(0,0,0); + } + // add new damage + FLOAT3D vDirectionFixed; + if (vDirection.ManhattanNorm()>0.5f) { + vDirectionFixed = vDirection; + } else { + vDirectionFixed = -en_vGravityDir; + } + FLOAT3D vDamageOld = m_vDamage; + m_vDamage+=(vDirectionFixed/*-en_vGravityDir/2*/)*fKickDamage; + + FLOAT fOldLen = vDamageOld.Length(); + FLOAT fNewLen = m_vDamage.Length(); + FLOAT fOldRootLen = Sqrt(fOldLen); + FLOAT fNewRootLen = Sqrt(fNewLen); + + FLOAT fMassFactor = 200.0f/((EntityInfo*)GetEntityInfo())->fMass; + + if( !(en_ulFlags & ENF_ALIVE)) + { + fMassFactor /= 3; + } + + switch( dmtType) + { + case DMT_CLOSERANGE: + case DMT_DROWNING: + case DMT_IMPACT: + case DMT_BRUSH: + case DMT_BURNING: + // do nothing + break; + default: + { + if(fOldLen != 0.0f) + { + // cancel last push + GiveImpulseTranslationAbsolute( -vDamageOld/fOldRootLen*fMassFactor); + } + + /* + FLOAT3D vImpuls = m_vDamage/fNewRootLen*fMassFactor; + CPrintF( "Applied absolute translation impuls: (%g%g%g)\n", + vImpuls(1),vImpuls(2),vImpuls(3));*/ + + // push it back + GiveImpulseTranslationAbsolute( m_vDamage/fNewRootLen*fMassFactor); + } + } + + if( m_fMaxDamageAmmountCurrentTick()-_pTimer->TickQuantum*8 || + m_fSprayDamage+fDamageAmmount>50.0f)) { + + // spawn blood spray + CPlacement3D plSpray = CPlacement3D( vHitPoint, ANGLE3D(0, 0, 0)); + m_penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + m_penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + + if( m_fMaxDamageAmmount > 10.0f) + { + eSpawnSpray.fDamagePower = 3.0f; + } + else if(m_fSprayDamage+fDamageAmmount>50.0f) + { + eSpawnSpray.fDamagePower = 2.0f; + } + else + { + eSpawnSpray.fDamagePower = 1.0f; + } + + eSpawnSpray.sptType = SPT_BLOOD; + eSpawnSpray.fSizeMultiplier = 1.0f; + + // setup direction of spray + FLOAT3D vHitPointRelative = vHitPoint - GetPlacement().pl_PositionVector; + FLOAT3D vReflectingNormal; + GetNormalComponent( vHitPointRelative, en_vGravityDir, vReflectingNormal); + vReflectingNormal.Normalize(); + + vReflectingNormal(1)/=5.0f; + + FLOAT3D vProjectedComponent = vReflectingNormal*(vDirection%vReflectingNormal); + FLOAT3D vSpilDirection = vDirection-vProjectedComponent*2.0f-en_vGravityDir*0.5f; + + eSpawnSpray.vDirection = vSpilDirection; + eSpawnSpray.penOwner = this; + + // initialize spray + m_penSpray->Initialize( eSpawnSpray); + m_tmSpraySpawned = _pTimer->CurrentTick(); + m_fSprayDamage = 0.0f; + m_fMaxDamageAmmount = 0.0f; + } + m_fSprayDamage+=fDamageAmmount; + } + /* Receive damage */ + void ReceiveDamage( CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // don't harm yourself with knife or with rocket in easy/tourist mode + if( penInflictor==this && (dmtType==DMT_CLOSERANGE || + ((dmtType==DMT_EXPLOSION||dmtType==DMT_CANNONBALL_EXPLOSION||dmtType==DMT_PROJECTILE) && + GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY)) ) + { + return; + } + + // if not connected + if (m_ulFlags&PLF_NOTCONNECTED) { + // noone can harm you + return; + } + + // god mode -> no one can harm you + if( cht_bGod && CheatsEnabled() ) { return; } + + // if invunerable after spawning + FLOAT tmSpawnInvulnerability = GetSP()->sp_tmSpawnInvulnerability; + if (tmSpawnInvulnerability>0 && _pTimer->CurrentTick()-m_tmSpawnedsp_bFriendlyFire && GetSP()->sp_bCooperative) { + if (IsOfClass(penInflictor, "Player") && penInflictor!=this) { + return; + } + } + + // adjust for difficulty + FLOAT fDifficultyDamage = GetSP()->sp_fDamageStrength; + if( fDifficultyDamage<=1.0f || penInflictor!=this) { + fDamageAmmount *= fDifficultyDamage; + } + + // ignore zero damages + if (fDamageAmmount<=0) { + return; + } + + FLOAT fSubHealth, fSubArmor; + if( dmtType == DMT_DROWNING) { + // drowning + fSubHealth = fDamageAmmount; + } + else { + // damage and armor + fSubArmor = fDamageAmmount*2.0f/3.0f; // 2/3 on armor damage + fSubHealth = fDamageAmmount - fSubArmor; // 1/3 on health damage + m_fArmor -= fSubArmor; // decrease armor + if( m_fArmor<0) { // armor below zero -> add difference to health damage + fSubHealth -= m_fArmor; + m_fArmor = 0.0f; + } + } + + // if any damage + if( fSubHealth>0) { + // if camera is active + if (m_penCamera!=NULL) { + // if the camera has onbreak + CEntity *penOnBreak = ((CCamera&)*m_penCamera).m_penOnBreak; + if (penOnBreak!=NULL) { + // trigger it + SendToTarget(penOnBreak, EET_TRIGGER, this); + // if it doesn't + } else { + // just deactivate camera + m_penCamera = NULL; + } + } + + } + + // if the player is doing autoactions + if (m_penActionMarker!=NULL) { + // ignore all damage + return; + } + + DamageImpact(dmtType, fSubHealth, vHitPoint, vDirection); + + // receive damage + CPlayerEntity::ReceiveDamage( penInflictor, dmtType, fSubHealth, vHitPoint, vDirection); + + // red screen and hit translation + if( fDamageAmmount>1.0f) { +// !!!! this is obsolete, DamageImpact is used instead! + if( dmtType==DMT_EXPLOSION || dmtType==DMT_PROJECTILE || dmtType==DMT_BULLET + || dmtType==DMT_IMPACT || dmtType==DMT_CANNONBALL || dmtType==DMT_CANNONBALL_EXPLOSION) { +// GiveImpulseTranslationAbsolute( vDirection*(fDamageAmmount/7.5f) +// -en_vGravityDir*(fDamageAmmount/15.0f)); + } + if( GetFlags()&ENF_ALIVE) { + m_fDamageAmmount += fDamageAmmount; + m_tmWoundedTime = _pTimer->CurrentTick(); + } + } + + // yell (this hurts) + ESound eSound; + eSound.EsndtSound = SNDT_PLAYER; + eSound.penTarget = this; + SendEventInRange( eSound, FLOATaabbox3D( GetPlacement().pl_PositionVector, 10.0f)); + + // play hurting sound + if( dmtType==DMT_DROWNING) { + SetRandomMouthPitch( 0.9f, 1.1f); + PlaySound( m_soMouth, SOUND_DROWN, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("WoundWater");} + m_tmMouthSoundLast = _pTimer->CurrentTick(); + PlaySound( m_soLocalAmbientOnce, SOUND_WATERBUBBLES, SOF_3D|SOF_VOLUMETRIC|SOF_LOCAL); + m_soLocalAmbientOnce.Set3DParameters( 25.0f, 5.0f, 2.0f, Lerp(0.5f, 1.5f, FRnd()) ); + SpawnBubbles( 10+INDEX(FRnd()*10)); + } else if( m_fDamageAmmount>1.0f) { + // if not dead + if (GetFlags()&ENF_ALIVE) { + // determine corresponding sound + INDEX iSound; + const char *strIFeel = NULL; + if( m_fDamageAmmount<5.0f) { + iSound = SOUND_WOUNDWEAK; + strIFeel = "WoundWeak"; + } + else if( m_fDamageAmmount<25.0f) { + iSound = SOUND_WOUNDMEDIUM; + strIFeel = "WoundMedium"; + } + else { + iSound = SOUND_WOUNDSTRONG; + strIFeel = "WoundStrong"; + } + if( m_pstState==PST_DIVE) { + iSound = SOUND_WOUNDWATER; + strIFeel = "WoundWater"; + } // override for diving + SetRandomMouthPitch( 0.9f, 1.1f); + // give some pause inbetween screaming + TIME tmNow = _pTimer->CurrentTick(); + if( (tmNow-m_tmScreamTime) > 1.0f) { + m_tmScreamTime = tmNow; + PlaySound( m_soMouth, iSound, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect(strIFeel);} + } + } + } + }; + + // should this player blow up (spawn debris) + BOOL ShouldBlowUp(void) + { + // blow up if + return + // allowed + GetSP()->sp_bGibs && + // dead and + (GetHealth()<=0) && + // has received large enough damage lately and + (m_vDamage.Length() > _fBlowUpAmmount) && + // is not blown up already + GetRenderType()==RT_MODEL; + }; + + // spawn body parts + void BlowUp(void) + { + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(_fBlowUpAmmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + vNormalizedDamage *= 0.75f; + + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + const FLOAT fBlowUpSize = 2.0f; + + // readout blood type + const INDEX iBloodType = GetSP()->sp_iBlood; + // determine debris texture (color) + ULONG ulFleshTexture = TEXTURE_FLESH_GREEN; + ULONG ulFleshModel = MODEL_FLESH; + if( iBloodType==2) { ulFleshTexture = TEXTURE_FLESH_RED; } + // spawn debris + Debris_Begin( EIBT_FLESH, DPT_BLOODTRAIL, BET_BLOODSTAIN, fBlowUpSize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); + for( INDEX iDebris=0; iDebris<4; iDebris++) { + // flowerpower mode? + if( iBloodType==3) { + switch( IRnd()%5) { + case 1: { ulFleshModel = MODEL_FLESH_APPLE; ulFleshTexture = TEXTURE_FLESH_APPLE; break; } + case 2: { ulFleshModel = MODEL_FLESH_BANANA; ulFleshTexture = TEXTURE_FLESH_BANANA; break; } + case 3: { ulFleshModel = MODEL_FLESH_BURGER; ulFleshTexture = TEXTURE_FLESH_BURGER; break; } + case 4: { ulFleshModel = MODEL_FLESH_LOLLY; ulFleshTexture = TEXTURE_FLESH_LOLLY; break; } + default: { ulFleshModel = MODEL_FLESH_ORANGE; ulFleshTexture = TEXTURE_FLESH_ORANGE; break; } + } + } + Debris_Spawn( this, this, ulFleshModel, ulFleshTexture, 0, 0, 0, IRnd()%4, 0.5f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + } + + // leave a stain beneath + LeaveStain(FALSE); + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + + FLOAT fSpeedOrg = en_vCurrentTranslationAbsolute.Length(); + const FLOAT fSpeedMax = 30.0f; + if (fSpeedOrg>fSpeedMax) { + en_vCurrentTranslationAbsolute *= fSpeedMax/fSpeedOrg; + } + +// SetPhysicsFlags(EPF_MODEL_IMMATERIAL); +// SetCollisionFlags(ECF_IMMATERIAL); + }; + +/************************************************************ + * OVERRIDEN FUNCTIONS * + ************************************************************/ + /* Entity info */ + void *GetEntityInfo(void) { + switch (m_pstState) { + case PST_STAND: case PST_FALL: + return &eiPlayerGround; + break; + case PST_CROUCH: + return &eiPlayerCrouch; + break; + case PST_SWIM: case PST_DIVE: + return &eiPlayerSwim; + break; + } + return &eiPlayerGround; + }; + + + /* Receive item */ + BOOL ReceiveItem(const CEntityEvent &ee) + { + // *********** HEALTH *********** + if( ee.ee_slEvent == EVENTCODE_EHealth) + { + // determine old and new health values + FLOAT fHealthOld = GetHealth(); + FLOAT fHealthNew = fHealthOld + ((EHealth&)ee).fHealth; + if( ((EHealth&)ee).bOverTopHealth) { + fHealthNew = ClampUp( fHealthNew, MaxHealth()); + } else { + fHealthNew = ClampUp( fHealthNew, TopHealth()); + } + + // if value can be changed + if( ceil(fHealthNew) > ceil(fHealthOld)) { + // receive it + SetHealth(fHealthNew); + ItemPicked( TRANS("Health"), ((EHealth&)ee).fHealth); + m_iMana += (INDEX)(((EHealth&)ee).fHealth); + m_fPickedMana += ((EHealth&)ee).fHealth; + return TRUE; + } + } + + // *********** ARMOR *********** + else if( ee.ee_slEvent == EVENTCODE_EArmor) + { + // determine old and new health values + FLOAT fArmorOld = m_fArmor; + FLOAT fArmorNew = fArmorOld + ((EArmor&)ee).fArmor; + if( ((EArmor&)ee).bOverTopArmor) { + fArmorNew = ClampUp( fArmorNew, MaxArmor()); + } else { + fArmorNew = ClampUp( fArmorNew, TopArmor()); + } + // if value can be changed + if( ceil(fArmorNew) > ceil(fArmorOld)) { + // receive it + m_fArmor = fArmorNew; + ItemPicked( TRANS("Armor"), ((EArmor&)ee).fArmor); + m_iMana += (INDEX)(((EArmor&)ee).fArmor); + m_fPickedMana += ((EArmor&)ee).fArmor; + return TRUE; + } + } + + // *********** MESSAGE *********** + else if (ee.ee_slEvent == EVENTCODE_EMessageItem) { + EMessageItem &eMI = (EMessageItem &)ee; + ReceiveComputerMessage(eMI.fnmMessage, CMF_ANALYZE); + ItemPicked(TRANS("Ancient papyrus"), 0); + return TRUE; + } + + // *********** WEAPON *********** + else if (ee.ee_slEvent == EVENTCODE_EWeaponItem) { + return ((CPlayerWeapons&)*m_penWeapons).ReceiveWeapon(ee); + } + + // *********** AMMO *********** + else if (ee.ee_slEvent == EVENTCODE_EAmmoItem) { + return ((CPlayerWeapons&)*m_penWeapons).ReceiveAmmo(ee); + } + + else if (ee.ee_slEvent == EVENTCODE_EAmmoPackItem) { + return ((CPlayerWeapons&)*m_penWeapons).ReceivePackAmmo(ee); + } + // *********** KEYS *********** + else if (ee.ee_slEvent == EVENTCODE_EKey) { + // make key mask + ULONG ulKey = 1<sp_bCooperative && !GetSP()->sp_bSinglePlayer) { + CPrintF(TRANS("^cFFFFFF%s - %s^r\n"), (const char*)GetPlayerName(), (const char*)strKey); + } + + return TRUE; + } + } + + // nothing picked + return FALSE; + }; + + + + // Change Player view + void ChangePlayerView() + { + // change from eyes to 3rd person + if (m_iViewState == PVT_PLAYEREYES) { + // spawn 3rd person view camera + ASSERT(m_pen3rdPersonView == NULL); + if (m_pen3rdPersonView == NULL) { + m_pen3rdPersonView = CreateEntity(GetPlacement(), CLASS_PLAYER_VIEW); + EViewInit eInit; + eInit.penOwner = this; + eInit.penCamera = NULL; + eInit.vtView = VT_3RDPERSONVIEW; + eInit.bDeathFixed = FALSE; + m_pen3rdPersonView ->Initialize(eInit); + } + + m_iViewState = PVT_3RDPERSONVIEW; + + // change from 3rd person to eyes + } else if (m_iViewState == PVT_3RDPERSONVIEW) { + m_iViewState = PVT_PLAYEREYES; + + // kill 3rd person view + if (m_pen3rdPersonView != NULL) { + ((CPlayerView&)*m_pen3rdPersonView).SendEvent(EEnd()); + m_pen3rdPersonView = NULL; + } + } + }; + + // if computer is pressed + void ComputerPressed(void) + { + // call computer + if (cmp_ppenPlayer==NULL && _pNetwork->IsPlayerLocal(this)) { + cmp_ppenPlayer = this; + } + m_bComputerInvoked = TRUE; + // clear analyses message + m_tmAnalyseEnd = 0; + m_bPendingMessage = FALSE; + m_tmMessagePlay = 0; + } + + + + // if use is pressed + void UsePressed(BOOL bOrComputer) + { + // cast ray from weapon + CPlayerWeapons *penWeapons = GetPlayerWeapons(); + CEntity *pen = penWeapons->m_penRayHit; + BOOL bSomethingToUse = FALSE; + + // if hit + if (pen!=NULL) { + // check switch/messageholder relaying by moving brush + if (IsOfClass( pen, "Moving Brush")) { + if (((CMovingBrush&)*pen).m_penSwitch!=NULL) { + pen = ((CMovingBrush&)*pen).m_penSwitch; + } + } + + // if switch and near enough + if (IsOfClass( pen, "Switch") && penWeapons->m_fRayHitDistance < 2.0f) { + CSwitch &enSwitch = (CSwitch&)*pen; + // if switch is useable + if (enSwitch.m_bUseable) { + // send it a trigger event + SendToTarget(pen, EET_TRIGGER, this); + bSomethingToUse = TRUE; + } + } + + // if analyzable + if (IsOfClass( pen, "MessageHolder") + && penWeapons->m_fRayHitDistance<((CMessageHolder*)&*pen)->m_fDistance + && ((CMessageHolder*)&*pen)->m_bActive) { + const CTFileName &fnmMessage = ((CMessageHolder*)&*pen)->m_fnmMessage; + // if player doesn't have that message in database + if (!HasMessage(fnmMessage)) { + // add the message + ReceiveComputerMessage(fnmMessage, CMF_ANALYZE); + bSomethingToUse = TRUE; + } + } + } + // if nothing usable under cursor, and may call computer + if (!bSomethingToUse && bOrComputer) { + // call computer + ComputerPressed(); + } + } + + +/************************************************************ + * PLAYER ACTIONS * + ************************************************************/ + void SetGameEnd(void) + { + _pNetwork->SetGameFinished(); + // start console for first player possible + for(INDEX iPlayer=0; iPlayerIsPlayerLocal(pen)) { + cmp_ppenPlayer = (CPlayer*)pen; + } + } + } + } + // check if game should be finished + void CheckGameEnd(void) + { + BOOL bFinished = FALSE; + // if time limit is out + INDEX iTimeLimit = GetSP()->sp_iTimeLimit; + if (iTimeLimit>0 && _pTimer->CurrentTick()>=iTimeLimit*60.0f) { + bFinished = TRUE; + } + // if frag limit is out + INDEX iFragLimit = GetSP()->sp_iFragLimit; + if (iFragLimit>0 && m_psLevelStats.ps_iKills>=iFragLimit) { + bFinished = TRUE; + } + // if score limit is out + INDEX iScoreLimit = GetSP()->sp_iScoreLimit; + if (iScoreLimit>0 && m_psLevelStats.ps_iScore>=iScoreLimit) { + bFinished = TRUE; + } + + if (bFinished) { + SetGameEnd(); + } + } + + // Preapply the action packet for local mouselag elimination + void PreapplyAction( const CPlayerAction &paAction) + { + } + + // Called to apply player action to player entity each tick. + void ApplyAction( const CPlayerAction &paOriginal, FLOAT tmLatency) + { + if(!(m_ulFlags&PLF_INITIALIZED)) { return; } +// CPrintF("---APPLY: %g\n", paOriginal.pa_aRotation(1)); + + // if was not connected + if (m_ulFlags&PLF_NOTCONNECTED) { + // set connected state + SetConnected(); + } + // mark that the player is connected + m_ulFlags |= PLF_APPLIEDACTION; + + // make a copy of action for adjustments + CPlayerAction paAction = paOriginal; + //CPrintF("applying(%s-%08x): %g\n", GetPredictName(), int(paAction.pa_llCreated), + // paAction.pa_vTranslation(3)); + + // calculate delta from last received actions + ANGLE3D aDeltaRotation = paAction.pa_aRotation -m_aLastRotation; + ANGLE3D aDeltaViewRotation = paAction.pa_aViewRotation-m_aLastViewRotation; + //FLOAT3D vDeltaTranslation = paAction.pa_vTranslation -m_vLastTranslation; + m_aLastRotation = paAction.pa_aRotation; + m_aLastViewRotation = paAction.pa_aViewRotation; + //m_vLastTranslation = paAction.pa_vTranslation; + paAction.pa_aRotation = aDeltaRotation; + paAction.pa_aViewRotation = aDeltaViewRotation; + //paAction.pa_vTranslation = vDeltaTranslation; + + // adjust rotations per tick + paAction.pa_aRotation /= _pTimer->TickQuantum; + paAction.pa_aViewRotation /= _pTimer->TickQuantum; + + // adjust prediction for remote players only + CEntity *penMe = this; + if (IsPredictor()) { + penMe = penMe->GetPredicted(); + } + SetPredictable(!_pNetwork->IsPlayerLocal(penMe)); + + // check for end of game + if (!IsPredictor()) { + CheckGameEnd(); + } + + // limit speeds against abusing + paAction.pa_vTranslation(1) = Clamp( paAction.pa_vTranslation(1), -plr_fSpeedSide, plr_fSpeedSide); + paAction.pa_vTranslation(2) = Clamp( paAction.pa_vTranslation(2), -plr_fSpeedUp, plr_fSpeedUp); + paAction.pa_vTranslation(3) = Clamp( paAction.pa_vTranslation(3), -plr_fSpeedForward, plr_fSpeedBackward); + + // if speeds are like walking + if (Abs(paAction.pa_vTranslation(3))< plr_fSpeedForward/1.99f + &&Abs(paAction.pa_vTranslation(1))< plr_fSpeedSide/1.99f) { + // don't allow falling + en_fStepDnHeight = 1.5f; + + // if speeds are like running + } else { + // allow falling + en_fStepDnHeight = -1; + } + + // limit diagonal speed against abusing + FLOAT3D &v = paAction.pa_vTranslation; + FLOAT fDiag = Sqrt(v(1)*v(1)+v(3)*v(3)); + if (fDiag>0.01f) { + FLOAT fDiagLimited = Min(fDiag, plr_fSpeedForward); + FLOAT fFactor = fDiagLimited/fDiag; + v(1)*=fFactor; + v(3)*=fFactor; + } + + ulButtonsNow = paAction.pa_ulButtons; + ulButtonsBefore = m_ulLastButtons; + ulNewButtons = ulButtonsNow&~ulButtonsBefore; + ulReleasedButtons = (~ulButtonsNow)&(ulButtonsBefore); + + m_ulLastButtons = ulButtonsNow; // remember last buttons + en_plLastViewpoint = en_plViewpoint; // remember last view point for lerping + + // if alive + if (GetFlags() & ENF_ALIVE) { + // if not in auto-action mode + if (m_penActionMarker==NULL) { + // apply actions + AliveActions(paAction); + // if in auto-action mode + } else { + // do automatic actions + AutoActions(paAction); + } + // if not alive rotate camera view and rebirth on fire + } else { + DeathActions(paAction); + } + + if (Abs(_pTimer->CurrentTick()-m_tmAnalyseEnd)<_pTimer->TickQuantum*2) { + m_tmAnalyseEnd = 0; + m_bPendingMessage = TRUE; + m_tmMessagePlay = 0; + } + if (m_bPendingMessage && !IsFuss()) { + m_bPendingMessage = FALSE; + m_tmMessagePlay = _pTimer->CurrentTick()+1.0f; + m_tmAnimateInbox = _pTimer->CurrentTick(); + } + if (Abs(_pTimer->CurrentTick()-m_tmMessagePlay)<_pTimer->TickQuantum*2) { + m_bPendingMessage = FALSE; + m_tmAnalyseEnd = 0; + + if (!m_bComputerInvoked && GetSP()->sp_bSinglePlayer) { + PrintCenterMessage(this, this, + TRANS("Press USE to read the message!"), 5.0f, MSS_NONE); + } + } + + // wanna cheat a bit? + if (CheatsEnabled()) { + Cheats(); + } + + // if teleporting to marker (this cheat is enabled in all versions) + if (cht_iGoToMarker>0 && (GetFlags()&ENF_ALIVE)) { + // rebirth player, and it will teleport + m_iLastViewState = m_iViewState; + SendEvent(ERebirth()); + } + + // keep latency for eventual printout + UpdateLatency(tmLatency); + + // check if highscore has changed + CheckHighScore(); + }; + + + // Called when player is disconnected + void Disconnect(void) + { + // remember name + m_strName = GetPlayerName(); + // clear the character, so we don't get re-connected to same entity + en_pcCharacter = CPlayerCharacter(); + // make main loop exit + SendEvent(EDisconnected()); + }; + + // Called when player character is changed + void CharacterChanged(const CPlayerCharacter &pcNew) + { + // remember original character + CPlayerCharacter pcOrg = en_pcCharacter; + + // set the new character + en_pcCharacter = pcNew; + ValidateCharacter(); + + // if the name has changed + if (pcOrg.GetName()!=pcNew.GetName()) { + // report that + CPrintF(TRANS("%s is now known as %s\n"), + (const char*)pcOrg.GetNameForPrinting(), (const char*)pcNew.GetNameForPrinting()); + } + + // if the team has changed + if (pcOrg.GetTeam()!=pcNew.GetTeam()) { + // report that + CPrintF(TRANS("%s switched to team %s\n"), + (const char*) pcNew.GetNameForPrinting(), (const char*)pcNew.GetTeamForPrinting()); + } + + // if appearance changed + CPlayerSettings *ppsOrg = (CPlayerSettings *)pcOrg.pc_aubAppearance; + CPlayerSettings *ppsNew = (CPlayerSettings *)pcNew.pc_aubAppearance; + if (memcmp(ppsOrg->ps_achModelFile, ppsNew->ps_achModelFile, sizeof(ppsOrg->ps_achModelFile))!=0) { + // update your real appearance if possible + CTString strNewLook; + BOOL bSuccess = SetPlayerAppearance(&m_moRender, &en_pcCharacter, strNewLook, /*bPreview=*/FALSE); + // if succeeded + if (bSuccess) { + // report that + CPrintF(TRANS("%s now appears as %s\n"), + (const char*)pcNew.GetNameForPrinting(),(const char*) strNewLook); + // if failed + } else { + // report that + CPrintF(TRANS("Cannot change appearance for %s: setting '%s' is unavailable\n"), + (const char*)pcNew.GetNameForPrinting(), (const char*)ppsNew->GetModelFilename()); + } + // attach weapon to new appearance + GetPlayerAnimator()->SyncWeapon(); + } + + BOOL b3RDPersonOld = ppsOrg->ps_ulFlags&PSF_PREFER3RDPERSON; + BOOL b3RDPersonNew = ppsNew->ps_ulFlags&PSF_PREFER3RDPERSON; + if ((b3RDPersonOld && !b3RDPersonNew && m_iViewState==PVT_3RDPERSONVIEW) + ||(b3RDPersonNew && !b3RDPersonOld && m_iViewState==PVT_PLAYEREYES) ) { + ChangePlayerView(); + } + }; + + + // Alive actions + void AliveActions(const CPlayerAction &pa) + { + CPlayerAction paAction = pa; + + // if camera is active + if (m_penCamera!=NULL) { + // ignore keyboard/mouse/joystick commands + paAction.pa_vTranslation = FLOAT3D(0,0,0); + paAction.pa_aRotation = ANGLE3D(0,0,0); + paAction.pa_aViewRotation = ANGLE3D(0,0,0); + // if fire or use is pressed + if (ulNewButtons&(PLACT_FIRE|PLACT_USE)) { + // stop camera + m_penCamera=NULL; + } + } else { + ButtonsActions(paAction); + } + + // do the actions + ActiveActions(paAction); + + // if less than few seconds elapsed since last damage + FLOAT tmSinceWounding = _pTimer->CurrentTick() - m_tmWoundedTime; + if( tmSinceWounding<4.0f) { + // decrease damage ammount + m_fDamageAmmount *= 1.0f - tmSinceWounding/4.0f; + } else { + // reset damage ammount + m_fDamageAmmount = 0.0f; + } + } + + // Auto-actions + void AutoActions(const CPlayerAction &pa) + { + // if fire, use or computer is pressed + if (ulNewButtons&(PLACT_FIRE|PLACT_USE|PLACT_COMPUTER)) { + if (m_penCamera!=NULL) { + CEntity *penOnBreak = ((CCamera&)*m_penCamera).m_penOnBreak; + if (penOnBreak!=NULL) { + SendToTarget(penOnBreak, EET_TRIGGER, this); + } + } + } + + CPlayerAction paAction = pa; + // ignore keyboard/mouse/joystick commands + paAction.pa_vTranslation = FLOAT3D(0,0,0); + paAction.pa_aRotation = ANGLE3D(0,0,0); + paAction.pa_aViewRotation = ANGLE3D(0,0,0); + + // if moving towards the marker is enabled + if (m_fAutoSpeed>0) { + FLOAT3D vDelta = + m_penActionMarker->GetPlacement().pl_PositionVector- + GetPlacement().pl_PositionVector; + FLOAT fDistance = vDelta.Length(); + if (fDistance>0.1f) { + vDelta/=fDistance; + ANGLE aDH = GetRelativeHeading(vDelta); + + // if should hit the marker exactly + FLOAT fSpeed = m_fAutoSpeed; + if (GetActionMarker()->m_paaAction==PAA_RUNANDSTOP) { + // adjust speed + fSpeed = Min(fSpeed, fDistance/_pTimer->TickQuantum); + } + // adjust rotation + if (Abs(aDH)>5.0f) { + if (fSpeed>m_fAutoSpeed-0.1f) { + aDH = Clamp(aDH, -30.0f, 30.0f); + } + paAction.pa_aRotation = ANGLE3D(aDH/_pTimer->TickQuantum,0,0); + } + // set forward speed + paAction.pa_vTranslation = FLOAT3D(0,0,-fSpeed); + } + } else { + paAction.pa_vTranslation = m_vAutoSpeed; + } + + CPlayerActionMarker *ppam = GetActionMarker(); + ASSERT( ppam != NULL); + if( ppam->m_paaAction == PAA_LOGO_FIRE_MINIGUN) + { + if( m_tmMinigunAutoFireStart != -1) + { + FLOAT tmDelta = _pTimer->CurrentTick()-m_tmMinigunAutoFireStart; + FLOAT aDH=0.0f; + FLOAT aDP=0.0f; + if( tmDelta>=0.0f && tmDelta<=0.75f) + { + aDH = 0.0f; + } + else if( tmDelta>=0.75f) + { + FLOAT fDT = tmDelta-0.75f; + aDH = 1.0f*cos(fDT+PI/2.0f); + aDP = 0.5f*cos(fDT); + } + paAction.pa_aRotation = ANGLE3D(aDH/_pTimer->TickQuantum, aDP/_pTimer->TickQuantum,0); + } + } + + // do the actions + if (!(m_ulFlags&PLF_AUTOMOVEMENTS)) { + ActiveActions(paAction); + } + } + + void GetLerpedWeaponPosition( FLOAT3D vRel, CPlacement3D &pl) + { + pl = CPlacement3D( vRel, ANGLE3D(0,0,0)); + CPlacement3D plView; + GetLerpedAbsoluteViewPlacement(plView); + pl.RelativeToAbsolute( plView); + } + + void SpawnBubbles( INDEX ctBubbles) + { + for( INDEX iBouble=0; iBoublesp_bCooperative) + { + vTranslation*=1.30f; + } + + en_fAcceleration = plr_fAcceleration; + en_fDeceleration = plr_fDeceleration; + + if( !GetSP()->sp_bCooperative) + { + vTranslation(1)*=1.35f; + vTranslation(3)*=1.35f; + //en_fDeceleration *= 0.8f; + } + + CContentType &ctUp = GetWorld()->wo_actContentTypes[en_iUpContent]; + CContentType &ctDn = GetWorld()->wo_actContentTypes[en_iDnContent]; + + PlayerState pstWanted = PST_STAND; + BOOL bUpSwimable = (ctUp.ct_ulFlags&CTF_SWIMABLE) && en_fImmersionFactor<=0.99f; + BOOL bDnSwimable = (ctDn.ct_ulFlags&CTF_SWIMABLE) && en_fImmersionFactor>=0.5f; + + // if considerably inside swimable content + if (bUpSwimable || bDnSwimable) { + // allow jumping + m_ulFlags|=PLF_JUMPALLOWED; + //CPrintF("swimable %f", en_fImmersionFactor); + // if totaly inside + if (en_fImmersionFactor>=0.99f || bUpSwimable) { + // want to dive + pstWanted = PST_DIVE; + // if only partially inside + } else { + // want to swim + pstWanted = PST_SWIM; + } + // if not in swimable content + } else { + // if has reference + if (en_penReference!=NULL) { + // reset fall timer + m_fFallTime = 0.0f; + + // if no reference + } else { + // increase fall time + m_fFallTime += _pTimer->TickQuantum; + } + // if not wanting to jump + if (vTranslation(2)<0.1f) { + // allow jumping + m_ulFlags|=PLF_JUMPALLOWED; + } + + // if falling + if (m_fFallTime >= 0.5f) { + // wants to fall + pstWanted = PST_FALL; + // if not falling + } else { + // if holding down and really not in air + if (vTranslation(2)<-0.01f/* && m_fFallTime<0.5f*/) { + // wants to crouch + pstWanted = PST_CROUCH; + // if not holding down + } else { + // wants to stand + pstWanted = PST_STAND; + } + } + } + //CPrintF("c - %s w - %s", NameForState(m_pstState), NameForState(pstWanted)); + + // flying mode - rotate whole player + if (!(GetPhysicsFlags()&EPF_TRANSLATEDBYGRAVITY)) { + SetDesiredRotation(paAction.pa_aRotation); + StartModelAnim(PLAYER_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + SetDesiredTranslation(vTranslation); + // normal mode + } else { + PlayerState pstOld = m_pstState; + + // if different state needed + if (pstWanted!=m_pstState) { + // check state wanted + switch(pstWanted) { + // if wanting to stand + case PST_STAND: { + // if can stand here + if (ChangeCollisionBoxIndexNow(PLAYER_COLLISION_BOX_STAND)) { + en_plViewpoint.pl_PositionVector(2) = plr_fViewHeightStand; + if (m_pstState==PST_CROUCH) { + ((CPlayerAnimator&)*m_penAnimator).Rise(); + } else { + ((CPlayerAnimator&)*m_penAnimator).Stand(); + } + m_pstState = PST_STAND; + } + } break; + // if wanting to crouch + case PST_CROUCH: { + // if can crouch here + if (ChangeCollisionBoxIndexNow(PLAYER_COLLISION_BOX_CROUCH)) { + m_pstState = PST_CROUCH; + en_plViewpoint.pl_PositionVector(2) = plr_fViewHeightCrouch; + ((CPlayerAnimator&)*m_penAnimator).Crouch(); + } + } break; + // if wanting to swim + case PST_SWIM: { + // if can swim here + if (ChangeCollisionBoxIndexNow(PLAYER_COLLISION_BOX_SWIMSMALL)) { + ChangeCollisionBoxIndexWhenPossible(PLAYER_COLLISION_BOX_SWIM); + m_pstState = PST_SWIM; + en_plViewpoint.pl_PositionVector(2) = plr_fViewHeightSwim; + ((CPlayerAnimator&)*m_penAnimator).Swim(); + m_fSwimTime = _pTimer->CurrentTick(); + } + } break; + // if wanting to dive + case PST_DIVE: { + // if can dive here + if (ChangeCollisionBoxIndexNow(PLAYER_COLLISION_BOX_SWIMSMALL)) { + ChangeCollisionBoxIndexWhenPossible(PLAYER_COLLISION_BOX_SWIM); + m_pstState = PST_DIVE; + en_plViewpoint.pl_PositionVector(2) = plr_fViewHeightDive; + ((CPlayerAnimator&)*m_penAnimator).Swim(); + } + } break; + // if wanting to fall + case PST_FALL: { + // if can fall here + if (ChangeCollisionBoxIndexNow(PLAYER_COLLISION_BOX_STAND)) { + m_pstState = PST_FALL; + en_plViewpoint.pl_PositionVector(2) = plr_fViewHeightStand; + ((CPlayerAnimator&)*m_penAnimator).Fall(); + } + } break; + } + } + + // if state changed + if (m_pstState!=pstOld) { + // check water entering/leaving + BOOL bWasInWater = (pstOld==PST_SWIM||pstOld==PST_DIVE); + BOOL bIsInWater = (m_pstState==PST_SWIM||m_pstState==PST_DIVE); + // if entered water + if (bIsInWater && !bWasInWater) { + PlaySound(m_soBody, SOUND_WATER_ENTER, SOF_3D); + // if left water + } else if (!bIsInWater && bWasInWater) { + PlaySound(m_soBody, SOUND_WATER_LEAVE, SOF_3D); + m_tmOutOfWater = _pTimer->CurrentTick(); + //CPrintF("gotout "); + // if in water + } else if (bIsInWater) { + // if dived in + if (pstOld==PST_SWIM && m_pstState == PST_DIVE) { + PlaySound(m_soFootL, SOUND_DIVEIN, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("DiveIn");} + m_bMoveSoundLeft = TRUE; + m_tmMoveSound = _pTimer->CurrentTick(); + // if dived out + } else if (m_pstState==PST_SWIM && pstOld==PST_DIVE) { + PlaySound(m_soFootL, SOUND_DIVEOUT, SOF_3D); + m_bMoveSoundLeft = TRUE; + m_tmMoveSound = _pTimer->CurrentTick(); + } + } + // if just fell to ground + if (pstOld==PST_FALL && (m_pstState==PST_STAND||m_pstState==PST_CROUCH)) { + PlaySound(m_soFootL, SOUND_LAND, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("Land");} + } + // change ambience sounds + if (m_pstState==PST_DIVE) { + m_soLocalAmbientLoop.Set3DParameters(50.0f, 10.0f, 0.25f, 1.0f); + PlaySound(m_soLocalAmbientLoop, SOUND_WATERAMBIENT, + SOF_LOOP|SOF_3D|SOF_VOLUMETRIC|SOF_LOCAL); + } else if (pstOld==PST_DIVE) { + m_soLocalAmbientLoop.Stop(); + } + } + // if just jumped + if (en_tmJumped+_pTimer->TickQuantum>=_pTimer->CurrentTick() && + en_tmJumped<=_pTimer->CurrentTick() && en_penReference==NULL) { + // play jump sound + SetDefaultMouthPitch(); + PlaySound(m_soMouth, SOUND_JUMP, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("Jump");} + // disallow jumping + m_ulFlags&=~PLF_JUMPALLOWED; + } + + // set density + if (m_pstState == PST_SWIM || pstWanted == PST_SWIM + ||(pstWanted == PST_DIVE && m_pstState != pstWanted)) { + en_fDensity = 500.0f; // lower density than water + } else { + en_fDensity = 1000.0f; // same density as water + } + + if (_pTimer->CurrentTick()>=m_tmNextAmbientOnce) + { + if (m_pstState == PST_DIVE) + { + PlaySound(m_soLocalAmbientOnce, SOUND_WATERBUBBLES, + SOF_3D|SOF_VOLUMETRIC|SOF_LOCAL); + m_soLocalAmbientOnce.Set3DParameters(25.0f, 5.0f, 2.0f, Lerp(0.5f, 1.5f, FRnd()) ); + SpawnBubbles( 5+INDEX(FRnd()*5)); + } + m_tmNextAmbientOnce = _pTimer->CurrentTick()+5.0f+FRnd(); + } + + + // if crouching + if (m_pstState == PST_CROUCH) { + // go slower + vTranslation /= 2.5f; + // don't go down + vTranslation(2) = 0.0f; + } + + // if diving + if (m_pstState == PST_DIVE) { + // translate up/down with view pitch + FLOATmatrix3D mPitch; + MakeRotationMatrixFast(mPitch, FLOAT3D(0,en_plViewpoint.pl_OrientationAngle(2),0)); + FLOAT fZ = vTranslation(3); + vTranslation(3) = 0.0f; + vTranslation += FLOAT3D(0,0,fZ)*mPitch; + // if swimming + } else if (m_pstState == PST_SWIM) { + // translate down with view pitch if large + FLOATmatrix3D mPitch; + FLOAT fPitch = en_plViewpoint.pl_OrientationAngle(2); + if (fPitch>-30.0f) { + fPitch = 0; + } + MakeRotationMatrixFast(mPitch, FLOAT3D(0,fPitch,0)); + FLOAT fZ = vTranslation(3); + vTranslation(3) = 0.0f; + vTranslation += FLOAT3D(0,0,fZ)*mPitch; + } + + // if swimming or diving + if (m_pstState == PST_SWIM || m_pstState == PST_DIVE) { + // up/down is slower than on ground + vTranslation(2)*=0.5f; + } + + // if just started swimming + if (m_pstState == PST_SWIM && _pTimer->CurrentTick()CurrentTick()0) { + vTranslation(2) = 0.0f; + } + + // set translation + SetDesiredTranslation(vTranslation); + + // set pitch and banking from the normal rotation into the view rotation + en_plViewpoint.Rotate_HPB(ANGLE3D( + (ANGLE)((FLOAT)paAction.pa_aRotation(1)*_pTimer->TickQuantum), + (ANGLE)((FLOAT)paAction.pa_aRotation(2)*_pTimer->TickQuantum), + (ANGLE)((FLOAT)paAction.pa_aRotation(3)*_pTimer->TickQuantum))); + // pitch and banking boundaries + RoundViewAngle(en_plViewpoint.pl_OrientationAngle(2), PITCH_MAX); + RoundViewAngle(en_plViewpoint.pl_OrientationAngle(3), BANKING_MAX); + + // translation rotate player for heading + if (vTranslation.Length() > 0.1f) { + SetDesiredRotation(ANGLE3D(en_plViewpoint.pl_OrientationAngle(1)/_pTimer->TickQuantum, 0.0f, 0.0f)); + if (m_ulFlags&PLF_VIEWROTATIONCHANGED) { + m_ulFlags&=~PLF_VIEWROTATIONCHANGED; + FLOATmatrix3D mViewRot; + MakeRotationMatrixFast(mViewRot, ANGLE3D(en_plViewpoint.pl_OrientationAngle(1),0,0)); + FLOAT3D vTransRel = vTranslation*mViewRot; + SetDesiredTranslation(vTransRel); + } + en_plViewpoint.pl_OrientationAngle(1) = 0.0f; + + // rotate head, body and legs + } else { + m_ulFlags |= PLF_VIEWROTATIONCHANGED; + SetDesiredRotation(ANGLE3D(0.0f, 0.0f, 0.0f)); + ANGLE aDiff = en_plViewpoint.pl_OrientationAngle(1) - HEADING_MAX; + if (aDiff > 0.0f) { + SetDesiredRotation(ANGLE3D(aDiff/_pTimer->TickQuantum, 0.0f, 0.0f)); + } + aDiff = en_plViewpoint.pl_OrientationAngle(1) + HEADING_MAX; + if (aDiff < 0.0f) { + SetDesiredRotation(ANGLE3D(aDiff/_pTimer->TickQuantum, 0.0f, 0.0f)); + } + RoundViewAngle(en_plViewpoint.pl_OrientationAngle(1), HEADING_MAX); + } + + // play moving sounds + FLOAT fWantSpeed = en_vDesiredTranslationRelative.Length(); + FLOAT fGoesSpeed = en_vCurrentTranslationAbsolute.Length(); + BOOL bOnGround = (m_pstState == PST_STAND)||(m_pstState == PST_CROUCH); + BOOL bRunning = bOnGround && fWantSpeed>5.0f && fGoesSpeed>5.0f; + BOOL bWalking = bOnGround && !bRunning && fWantSpeed>2.0f && fGoesSpeed>2.0f; + BOOL bSwimming = (m_pstState == PST_SWIM) && fWantSpeed>2.0f && fGoesSpeed>2.0f; + BOOL bDiving = (m_pstState == PST_DIVE) && fWantSpeed>2.0f && fGoesSpeed>2.0f; + TIME tmNow = _pTimer->CurrentTick(); + INDEX iSoundWalkL = SOUND_WALK_L; + INDEX iSoundWalkR = SOUND_WALK_R; + if ((ctDn.ct_ulFlags&CTF_SWIMABLE) && en_fImmersionFactor>=0.1f) { + iSoundWalkL = SOUND_WATERWALK_L; + iSoundWalkR = SOUND_WATERWALK_R; + } else if (en_pbpoStandOn!=NULL && + en_pbpoStandOn->bpo_bppProperties.bpp_ubSurfaceType==SURFACE_SAND) { + iSoundWalkL = SOUND_WALK_SAND_L; + iSoundWalkR = SOUND_WALK_SAND_R; + } else if (en_pbpoStandOn!=NULL && + en_pbpoStandOn->bpo_bppProperties.bpp_ubSurfaceType==SURFACE_RED_SAND) { + iSoundWalkL = SOUND_WALK_SAND_L; + iSoundWalkR = SOUND_WALK_SAND_R; + } + else { + } + if (bRunning) { + if (tmNow>m_tmMoveSound+plr_fRunSoundDelay) { + m_tmMoveSound = tmNow; + m_bMoveSoundLeft = !m_bMoveSoundLeft; + if (m_bMoveSoundLeft) { + PlaySound(m_soFootL, iSoundWalkL, SOF_3D); + } else { + PlaySound(m_soFootR, iSoundWalkR, SOF_3D); + } + } + } else if (bWalking) { + if (tmNow>m_tmMoveSound+plr_fWalkSoundDelay) { + m_tmMoveSound = tmNow; + m_bMoveSoundLeft = !m_bMoveSoundLeft; + if (m_bMoveSoundLeft) { + PlaySound(m_soFootL, iSoundWalkL, SOF_3D); + } else { + PlaySound(m_soFootR, iSoundWalkR, SOF_3D); + } + } + } else if (bDiving) { + if (tmNow>m_tmMoveSound+plr_fDiveSoundDelay) { + m_tmMoveSound = tmNow; + m_bMoveSoundLeft = !m_bMoveSoundLeft; + if (m_bMoveSoundLeft) { + PlaySound(m_soFootL, SOUND_DIVE_L, SOF_3D); + } else { + PlaySound(m_soFootR, SOUND_DIVE_R, SOF_3D); + } + } + } else if (bSwimming) { + if (tmNow>m_tmMoveSound+plr_fSwimSoundDelay) { + m_tmMoveSound = tmNow; + m_bMoveSoundLeft = !m_bMoveSoundLeft; + if (m_bMoveSoundLeft) { + PlaySound(m_soFootL, SOUND_SWIM_L, SOF_3D); + } else { + PlaySound(m_soFootR, SOUND_SWIM_R, SOF_3D); + } + } + } + + // if player is almost out of air + TIME tmBreathDelay = tmNow-en_tmLastBreathed; + if (en_tmMaxHoldBreath-tmBreathDelay<20.0f) { + // play drowning sound once in a while + if (m_tmMouthSoundLast+2.0f aRound) { + aViewAngle = aRound; + } + if (aViewAngle < -aRound) { + aViewAngle = -aRound; + } + }; + + // Death actions + void DeathActions(const CPlayerAction &paAction) { + // set heading, pitch and banking from the normal rotation into the camera view rotation + if (m_penView!=NULL) { + ASSERT(IsPredicted()&&m_penView->IsPredicted()||IsPredictor()&&m_penView->IsPredictor()||!IsPredicted()&&!m_penView->IsPredicted()&&!IsPredictor()&&!m_penView->IsPredictor()); + en_plViewpoint.pl_PositionVector = FLOAT3D(0, 1, 0); + en_plViewpoint.pl_OrientationAngle += (ANGLE3D( + (ANGLE)((FLOAT)paAction.pa_aRotation(1)*_pTimer->TickQuantum), + (ANGLE)((FLOAT)paAction.pa_aRotation(2)*_pTimer->TickQuantum), + (ANGLE)((FLOAT)paAction.pa_aRotation(3)*_pTimer->TickQuantum))); + } + + // if death is finished and fire just released again and this is not a predictor + if (m_iMayRespawn==2 && (ulReleasedButtons&PLACT_FIRE) && !IsPredictor()) { + // if singleplayer + if( GetSP()->sp_bSinglePlayer) { + // load quick savegame + _pShell->Execute("gam_bQuickLoad=1;"); + // if deathmatch or similar + } else if( !GetSP()->sp_bCooperative) { + // rebirth + SendEvent(EEnd()); + // if cooperative + } else { + // if holding down reload button + if (m_ulLastButtons&PLACT_RELOAD) { + // forbid respawning in-place + m_ulFlags &= ~PLF_RESPAWNINPLACE; + } + // if playing on credits + if (GetSP()->sp_ctCredits!=0) { + // if playing on infinite credits or some credits left + if (GetSP()->sp_ctCredits==-1 || GetSP()->sp_ctCreditsLeft!=0) { + // decrement credits + if (GetSP()->sp_ctCredits!=-1) { + ((CSessionProperties*)GetSP())->sp_ctCreditsLeft--; + } + + // initiate respawn + CPrintF(TRANS("%s is riding the gun again\n"), (const char*)GetPlayerName()); + SendEvent(EEnd()); + + // report number of credits left + if (GetSP()->sp_ctCredits>0) { + if (GetSP()->sp_ctCreditsLeft==0) { + CPrintF(TRANS(" no more credits left!\n")); + } else { + CPrintF(TRANS(" %d credits left\n"), GetSP()->sp_ctCreditsLeft); + } + } + // if no more credits left + } else { + // report that you cannot respawn + CPrintF(TRANS("%s rests in peace - out of credits\n"), (const char*)GetPlayerName()); + } + } + } + } + // check fire released once after death + if (m_iMayRespawn==1 && !(ulButtonsNow&PLACT_FIRE)) { + m_iMayRespawn=2; + } + }; + + + // Buttons actions + void ButtonsActions( CPlayerAction &paAction) + { + // if selecting a new weapon select it + if((ulNewButtons&PLACT_SELECT_WEAPON_MASK)!=0) { + ESelectWeapon eSelect; + eSelect.iWeapon = (ulNewButtons&PLACT_SELECT_WEAPON_MASK)>>PLACT_SELECT_WEAPON_SHIFT; + ((CPlayerWeapons&)*m_penWeapons).SendEvent(eSelect); + } + + if(ulNewButtons&PLACT_WEAPON_NEXT) { + ESelectWeapon eSelect; + eSelect.iWeapon = -1; + ((CPlayerWeapons&)*m_penWeapons).SendEvent(eSelect); + } + if(ulNewButtons&PLACT_WEAPON_PREV) { + ESelectWeapon eSelect; + eSelect.iWeapon = -2; + ((CPlayerWeapons&)*m_penWeapons).SendEvent(eSelect); + } + if(ulNewButtons&PLACT_WEAPON_FLIP) { + ESelectWeapon eSelect; + eSelect.iWeapon = -3; + ((CPlayerWeapons&)*m_penWeapons).SendEvent(eSelect); + } + + // if fire is pressed + if (ulNewButtons&PLACT_FIRE) { + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EFireWeapon()); + } + // if fire is released + if (ulReleasedButtons&PLACT_FIRE) { + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EReleaseWeapon()); + } + // if reload is pressed + if (ulReleasedButtons&PLACT_RELOAD) { + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EReloadWeapon()); + } + + // if use is pressed + if (ulNewButtons&PLACT_USE) { + UsePressed(ulNewButtons&PLACT_COMPUTER); + // if computer is pressed + } else if (ulNewButtons&PLACT_COMPUTER) { + ComputerPressed(); + } + + // if 3rd person view is pressed + if (ulNewButtons&PLACT_3RD_PERSON_VIEW) { + ChangePlayerView(); + } + + // apply center view + if( ulButtonsNow&PLACT_CENTER_VIEW) { + // center view with speed of 45 degrees per 1/20 seconds + paAction.pa_aRotation(2) += Clamp( -en_plViewpoint.pl_OrientationAngle(2)/_pTimer->TickQuantum, -900.0f, +900.0f); + } + }; + + + // check if cheats can be active + BOOL CheatsEnabled(void) + { + return (GetSP()->sp_ctMaxPlayers==1||GetSP()->sp_bQuickTest) && m_penActionMarker==NULL; + } + + // Cheats + void Cheats(void) + { + BOOL bFlyOn = cht_bFly || cht_bGhost; + // fly mode + BOOL bIsFlying = !(GetPhysicsFlags() & EPF_TRANSLATEDBYGRAVITY); + if (bFlyOn && !bIsFlying) { + SetPhysicsFlags(GetPhysicsFlags() & ~(EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY)); + en_plViewpoint.pl_OrientationAngle = ANGLE3D(0, 0, 0); + } else if (!bFlyOn && bIsFlying) { + SetPhysicsFlags(GetPhysicsFlags() | EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY); + en_plViewpoint.pl_OrientationAngle = ANGLE3D(0, 0, 0); + } + + // ghost mode + BOOL bIsGhost = !(GetCollisionFlags() & ((ECBI_BRUSH|ECBI_MODEL)<ps_ulFlags&PSF_SHARPTURNING) && + _pNetwork->IsPlayerLocal((CPlayer*)GetPredictionTail()); + + // lerp player viewpoint + FLOAT fLerpFactor = _pTimer->GetLerpFactor(); + plView.Lerp(en_plLastViewpoint, en_plViewpoint, fLerpFactor); + + // moving banking and soft eyes + ((CPlayerAnimator&)*m_penAnimator).ChangeView(plView); + // body and head attachment animation + ((CPlayerAnimator&)*m_penAnimator).BodyAndHeadOrientation(plView); + + // return player eyes view + if (m_iViewState == PVT_PLAYEREYES) { + CPlacement3D plPosLerped = GetLerpedPlacement(); + if (bSharpTurning) { + // get your prediction tail + CPlayer *pen = (CPlayer*)GetPredictionTail(); + // add local rotation + plView.pl_OrientationAngle = pen->en_plViewpoint.pl_OrientationAngle + (pen->m_aLocalRotation-pen->m_aLastRotation); + // make sure it doesn't go out of limits + RoundViewAngle(plView.pl_OrientationAngle(2), PITCH_MAX); + RoundViewAngle(plView.pl_OrientationAngle(3), BANKING_MAX); + + // compensate for rotations that happen to the player without his/hers will + // (rotating brushes, weird gravities...) + // (these need to be lerped) + ANGLE3D aCurr = pen->GetPlacement().pl_OrientationAngle; + ANGLE3D aLast = pen->en_plLastPlacement.pl_OrientationAngle; + ANGLE3D aDesired = pen->en_aDesiredRotationRelative*_pTimer->TickQuantum; + FLOATmatrix3D mCurr; MakeRotationMatrixFast(mCurr, aCurr); + FLOATmatrix3D mLast; MakeRotationMatrixFast(mLast, aLast); + FLOATmatrix3D mDesired; MakeRotationMatrixFast(mDesired, aDesired); + mDesired = en_mRotation*(mDesired*!en_mRotation); + FLOATmatrix3D mForced = !mDesired*mCurr*!mLast; // = aCurr-aLast-aDesired; + ANGLE3D aForced; DecomposeRotationMatrixNoSnap(aForced, mForced); + if (aForced.MaxNorm()<1E-2) { + aForced = ANGLE3D(0,0,0); + } + FLOATquat3D qForced; qForced.FromEuler(aForced); + FLOATquat3D qZero; qZero.FromEuler(ANGLE3D(0,0,0)); + FLOATquat3D qLerped = Slerp(fLerpFactor, qZero, qForced); + FLOATmatrix3D m; + qLerped.ToMatrix(m); + m=m*mDesired*mLast; + DecomposeRotationMatrixNoSnap(plPosLerped.pl_OrientationAngle, m); + } + plView.RelativeToAbsoluteSmooth(plPosLerped); + // 3rd person view + } else if (m_iViewState == PVT_3RDPERSONVIEW) { + plView = m_pen3rdPersonView->GetLerpedPlacement(); + // camera view for player auto actions + } else if (m_iViewState == PVT_PLAYERAUTOVIEW) { + plView = m_penView->GetLerpedPlacement(); + // camera view for stored sequences + } else { + ASSERTALWAYS("Unknown player view"); + } + }; + + // Get current entity that the player views from. + CEntity *GetViewEntity(void) { + // player eyes + if (m_iViewState == PVT_PLAYEREYES) { + return this; + // 3rd person view + } else if (m_iViewState == PVT_3RDPERSONVIEW) { + if (((CPlayerView&)*m_pen3rdPersonView).m_fDistance>2.0f) { + return m_pen3rdPersonView; + } else { + return this; + } + // camera + } else if (m_iViewState == PVT_PLAYERAUTOVIEW) { + if (((CPlayerView&)*m_penView).m_fDistance>2.0f) { + return m_penView; + } else { + return this; + } + // invalid view + } else { + ASSERTALWAYS("Unknown player view"); + return NULL; + } + }; + + + // Draw player interface on screen. + void RenderHUD( CPerspectiveProjection3D &prProjection, CDrawPort *pdp, + FLOAT3D vViewerLightDirection, COLOR colViewerLight, COLOR colViewerAmbient, + BOOL bRenderWeapon) + { + // render weapon models if needed + BOOL bRenderModels = _pShell->GetINDEX("gfx_bRenderModels"); + if( hud_bShowWeapon && bRenderModels) { + // render weapons only if view is from player eyes + ((CPlayerWeapons&)*m_penWeapons).RenderWeaponModel(prProjection, pdp, + vViewerLightDirection, colViewerLight, colViewerAmbient, bRenderWeapon); + } + + // render crosshair + CPlacement3D plView; + if (m_iViewState == PVT_PLAYEREYES) { + // player view + plView = en_plViewpoint; + plView.RelativeToAbsolute(GetPlacement()); + } else if (m_iViewState == PVT_3RDPERSONVIEW) { + // camera view + plView = ((CPlayerView&)*m_pen3rdPersonView).GetPlacement(); + } + ((CPlayerWeapons&)*m_penWeapons).RenderCrosshair(prProjection, pdp, plView); + + // get your prediction tail + CPlayer *pen = (CPlayer*)GetPredictionTail(); + // do screen blending + ULONG ulR=255, ulG=0, ulB=0; // red for wounding + ULONG ulA = pen->m_fDamageAmmount*5.0f; + + // if less than few seconds elapsed since last damage + FLOAT tmSinceWounding = _pTimer->CurrentTick() - pen->m_tmWoundedTime; + if( tmSinceWounding<4.0f) { + // decrease damage ammount + if( tmSinceWounding<0.001f) { ulA = (ulA+64)/2; } + } + + // add rest of blend ammount + ulA = ClampUp( ulA, (ULONG)224); + if (m_iViewState == PVT_PLAYEREYES) { + pdp->dp_ulBlendingRA += ulR*ulA; + pdp->dp_ulBlendingGA += ulG*ulA; + pdp->dp_ulBlendingBA += ulB*ulA; + pdp->dp_ulBlendingA += ulA; + } + + // add world glaring + { + COLOR colGlare = GetWorldGlaring(); + UBYTE ubR, ubG, ubB, ubA; + ColorToRGBA(colGlare, ubR, ubG, ubB, ubA); + if (ubA!=0) { + pdp->dp_ulBlendingRA += ULONG(ubR)*ULONG(ubA); + pdp->dp_ulBlendingGA += ULONG(ubG)*ULONG(ubA); + pdp->dp_ulBlendingBA += ULONG(ubB)*ULONG(ubA); + pdp->dp_ulBlendingA += ULONG(ubA); + } + } + + // do all queued screen blendings + pdp->BlendScreen(); + + // render status info line (if needed) + if( hud_bShowInfo) { + // get player or its predictor + BOOL bSnooping = FALSE; + CPlayer *penHUDPlayer = this; + if (penHUDPlayer->IsPredicted()) { + penHUDPlayer = (CPlayer *)penHUDPlayer->GetPredictor(); + } + + // check if snooping is needed + CPlayerWeapons *pen = (CPlayerWeapons*)&*penHUDPlayer->m_penWeapons; + TIME tmDelta = _pTimer->CurrentTick() - pen->m_tmSnoopingStarted; + if( tmDeltam_penTargeting!=NULL); + penHUDPlayer = (CPlayer*)&*pen->m_penTargeting; + bSnooping = TRUE; + } + DrawHUD( penHUDPlayer, pdp, bSnooping); + } + } + + +/************************************************************ + * SPECIAL FUNCTIONS * + ************************************************************/ + // try to find start marker for deathmatch (re)spawning + CEntity *GetDeathmatchStartMarker(void) + { + // get number of markers + CTString strPlayerStart = "Player Start - "; + INDEX ctMarkers = _pNetwork->GetNumberOfEntitiesWithName(strPlayerStart); + // if none + if (ctMarkers==0) { + // fail + return NULL; + } + // if only one + if (ctMarkers==1) { + // get that one + return _pNetwork->GetEntityWithName(strPlayerStart, 0); + } + // if at least two markers found... + + // create tables of markers and their distances from players + CStaticArray amdMarkers; + amdMarkers.New(ctMarkers); + // for each marker + {for(INDEX iMarker=0; iMarkerGetEntityWithName(strPlayerStart, iMarker); + if (amdMarkers[iMarker].md_ppm==NULL) { + return NULL; // (if there is any invalidity, fail completely) + } + // get min distance from any player + FLOAT fMinD = UpperLimit(0.0f); + for (INDEX iPlayer=0; iPlayerGetPlacement().pl_PositionVector- + ppl->GetPlacement().pl_PositionVector).Length(); + if (fD=amdMarkers[ctMarkers-1].md_fMinD); + // choose marker among one of the 50% farthest + INDEX ctFarMarkers = ctMarkers/2; + ASSERT(ctFarMarkers>0); + INDEX iStartMarker = IRnd()%ctFarMarkers; + // find first next marker that was not used lately + INDEX iMarker=iStartMarker; + FOREVER{ + if (_pTimer->CurrentTick()>amdMarkers[iMarker].md_ppm->m_tmLastSpawned+1.0f) { + break; + } + iMarker = (iMarker+1)%ctMarkers; + if (iMarker==iStartMarker) { + break; + } + } + // return that + return amdMarkers[iMarker].md_ppm; + } +/************************************************************ + * INITIALIZE PLAYER * + ************************************************************/ + void InitializePlayer() { + // set viewpoint position inside the entity + en_plViewpoint.pl_OrientationAngle = ANGLE3D(0,0,0); + en_plViewpoint.pl_PositionVector = FLOAT3D(0.0f, plr_fViewHeightStand, 0.0f); + en_plLastViewpoint = en_plViewpoint; + + // clear properties + m_ulFlags &= PLF_INITIALIZED|PLF_LEVELSTARTED|PLF_RESPAWNINPLACE; // must not clear initialized flag + m_fFallTime = 0.0f; + m_pstState = PST_STAND; + m_fDamageAmmount = 0.0f; + m_tmWoundedTime = 0.0f; + + // initialize animator + ((CPlayerAnimator&)*m_penAnimator).Initialize(); + // restart weapons if needed + GetPlayerWeapons()->SendEvent(EStart()); + + // set flags + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL|((ECBI_PLAYER)<sp_bCooperative && !GetSP()->sp_bSinglePlayer) { + INDEX iRow = iPlayer/4; + INDEX iCol = iPlayer%4; + vOffsetRel = FLOAT3D(-3.0f+iCol*2.0f, fOffsetY, -3.0f+iRow*2.0f); + } + + return vOffsetRel; + } + +void TeleportPlayer(enum WorldLinkType EwltType) + { + INDEX iLevel = -1; + CTString strLevelName = GetWorld()->wo_fnmFileName.FileName(); + strLevelName.ScanF("%02d_", &iLevel); + if (iLevel>0) { + ((CSessionProperties*)GetSP())->sp_ulLevelsMask|=1<<(iLevel-1); + } + + // find player index + INDEX iPlayer = GetMyPlayerIndex(); + // player placement + CPlacement3D plSet = GetPlacement(); + // teleport in dummy space to avoid auto teleport frag + Teleport(CPlacement3D(FLOAT3D(32000.0f+100.0f*iPlayer, 32000.0f, 0), ANGLE3D(0, 0, 0))); + // force yourself to standing state + ForceCollisionBoxIndexChange(PLAYER_COLLISION_BOX_STAND); + en_plViewpoint.pl_PositionVector(2) = plr_fViewHeightStand; + ((CPlayerAnimator&)*m_penAnimator).m_bDisableAnimating = FALSE; + ((CPlayerAnimator&)*m_penAnimator).Stand(); + m_pstState = PST_STAND; + + // create offset from marker + FLOAT3D vOffsetRel = GetTeleportingOffset(); + + // no player start initially + BOOL bSetHealth = FALSE; // for getting health from marker + BOOL bAdjustHealth = FALSE; // for getting adjusting health to 50-100 interval + CEntity *pen = NULL; + if (GetSP()->sp_bCooperative) { + if (cht_iGoToMarker>=0) { + // try to find fast go marker + CTString strPlayerStart; + strPlayerStart.PrintF("Player Start - %d", (INDEX)cht_iGoToMarker); + pen = _pNetwork->GetEntityWithName(strPlayerStart, 0); + pen->SendEvent(ETrigger()); + cht_iGoToMarker = -1; + bSetHealth = TRUE; + bAdjustHealth = FALSE; + // if there is coop respawn marker + } else if (m_penMainMusicHolder!=NULL && !(m_ulFlags&PLF_CHANGINGLEVEL)) { + CMusicHolder *pmh = (CMusicHolder *)&*m_penMainMusicHolder; + if (pmh->m_penRespawnMarker!=NULL) { + // get it + pen = pmh->m_penRespawnMarker; + bSetHealth = TRUE; + bAdjustHealth = FALSE; + } + } + + // if quick start is enabled (in wed) + if (pen==NULL && GetSP()->sp_bQuickTest && m_strGroup=="") { + // try to find quick start marker + CTString strPlayerStart; + strPlayerStart.PrintF("Player Quick Start"); + pen = _pNetwork->GetEntityWithName(strPlayerStart, 0); + bSetHealth = TRUE; + bAdjustHealth = FALSE; + } + // if no start position yet + if (pen==NULL) { + // try to find normal start marker + CTString strPlayerStart; + strPlayerStart.PrintF("Player Start - %s", (const char*)m_strGroup); + pen = _pNetwork->GetEntityWithName(strPlayerStart, 0); + if (m_strGroup=="") { + bSetHealth = TRUE; + bAdjustHealth = FALSE; + } else { + if (EwltType==WLT_FIXED) { + bSetHealth = FALSE; + bAdjustHealth = TRUE; + } else { + bSetHealth = FALSE; + bAdjustHealth = FALSE; + } + } + } + // if no start position yet + if (pen==NULL) { + // try to find normal start marker without group anyway + CTString strPlayerStart; + strPlayerStart.PrintF("Player Start - "); + pen = _pNetwork->GetEntityWithName(strPlayerStart, 0); + bSetHealth = TRUE; + bAdjustHealth = FALSE; + } + } else { + bSetHealth = TRUE; + bAdjustHealth = FALSE; + // try to find start marker by random + pen = GetDeathmatchStartMarker(); + if (pen!=NULL) { + ((CPlayerMarker&)*pen).m_tmLastSpawned = _pTimer->CurrentTick(); + } + } + + // if respawning in place + if (m_ulFlags&PLF_RESPAWNINPLACE) { + m_ulFlags &= ~PLF_RESPAWNINPLACE; + // set default params + SetHealth(TopHealth()); + m_iMana = GetSP()->sp_iInitialMana; + m_fArmor = 0.0f; + // teleport where you were when you were killed + Teleport(CPlacement3D(m_vDied, m_aDied)); + + // if start marker is found + } else if (pen!=NULL) { + // if there is no respawn marker yet + if (m_penMainMusicHolder!=NULL) { + CMusicHolder *pmh = (CMusicHolder *)&*m_penMainMusicHolder; + if (pmh->m_penRespawnMarker==NULL) { + // set it + pmh->m_penRespawnMarker = pen; + } + } + + CPlayerMarker &CpmStart = (CPlayerMarker&)*pen; + // set player characteristics + if (bSetHealth) { + SetHealth(CpmStart.m_fHealth/100.0f*TopHealth()); + m_iMana = GetSP()->sp_iInitialMana; + m_fArmor = CpmStart.m_fShield; + } else if (bAdjustHealth) { + FLOAT fHealth = GetHealth(); + FLOAT fTopHealth = TopHealth(); + if( fHealth < fTopHealth) { + SetHealth(ClampUp(fHealth+fTopHealth/2.0f, fTopHealth)); + } + } + + // if should start in computer + if (CpmStart.m_bStartInComputer && GetSP()->sp_bSinglePlayer) { + // mark that + if (_pNetwork->IsPlayerLocal(this)) { + cmp_ppenPlayer = this; + } + cmp_bInitialStart = TRUE; + } + + // start with first message linked to the marker + CMessageHolder *penMessage = (CMessageHolder *)&*CpmStart.m_penMessage; + // while there are some messages to add + while (penMessage!=NULL && IsOfClass(penMessage, "MessageHolder")) { + const CTFileName &fnmMessage = penMessage->m_fnmMessage; + // if player doesn't have that message in database + if (!HasMessage(fnmMessage)) { + // add the message + ReceiveComputerMessage(fnmMessage, 0); + } + // go to next message holder in list + penMessage = (CMessageHolder *)&*penMessage->m_penNext; + } + + // set weapons + if (!GetSP()->sp_bCooperative) { + ((CPlayerWeapons&)*m_penWeapons).InitializeWeapons(CpmStart.m_iGiveWeapons, 0, 0, + CpmStart.m_fMaxAmmoRatio); + } else { + ((CPlayerWeapons&)*m_penWeapons).InitializeWeapons(CpmStart.m_iGiveWeapons, CpmStart.m_iTakeWeapons, + GetSP()->sp_bInfiniteAmmo?0:CpmStart.m_iTakeAmmo, CpmStart.m_fMaxAmmoRatio); + } + // start position relative to link + if (EwltType == WLT_RELATIVE) { + plSet.AbsoluteToRelative(_SwcWorldChange.plLink); // relative to link position + plSet.RelativeToAbsolute(CpmStart.GetPlacement()); // absolute to start marker position + Teleport(plSet); + // fixed start position + } else if (EwltType == WLT_FIXED) { + CPlacement3D plNew = CpmStart.GetPlacement(); + vOffsetRel*=CpmStart.en_mRotation; + plNew.pl_PositionVector += vOffsetRel; + Teleport(plNew); + // error -> teleport to zero + } else { + ASSERTALWAYS("Unknown world link type"); + Teleport(CPlacement3D(FLOAT3D(0, 0, 0)+vOffsetRel, ANGLE3D(0, 0, 0))); + } + // if there is a start trigger target + if(CpmStart.m_penTarget!=NULL) { + SendToTarget(CpmStart.m_penTarget, EET_TRIGGER, this); + } + + // default start position + } else { + // set player characteristics + SetHealth(TopHealth()); + m_iMana = GetSP()->sp_iInitialMana; + m_fArmor = 0.0f; + // set weapons + ((CPlayerWeapons&)*m_penWeapons).InitializeWeapons(0, 0, 0, 0); + // start position + Teleport(CPlacement3D(FLOAT3D(0, 0, 0)+vOffsetRel, ANGLE3D(0, 0, 0))); + } + // send teleport event to all entities in range + SendEventInRange(ETeleport(), FLOATaabbox3D(GetPlacement().pl_PositionVector, 200.0f)); + // stop moving + ForceFullStop(); + + // remember maximum health + m_fMaxHealth = TopHealth(); + + // if in singleplayer mode + if (GetSP()->sp_bSinglePlayer && GetSP()->sp_gmGameMode!=CSessionProperties::GM_FLYOVER) { + // save quick savegame + _pShell->Execute("gam_bQuickSave=1;"); + } + // remember level start time + if (!(m_ulFlags&PLF_LEVELSTARTED)) { + m_ulFlags |= PLF_LEVELSTARTED; + m_tmLevelStarted = _pNetwork->GetGameTime(); + } + // reset model appearance + CTString strDummy; + SetPlayerAppearance(GetModelObject(), NULL, strDummy, /*bPreview=*/FALSE); + ValidateCharacter(); + SetPlayerAppearance(&m_moRender, &en_pcCharacter, strDummy, /*bPreview=*/FALSE); + GetPlayerAnimator()->SetWeapon(); + m_ulFlags |= PLF_SYNCWEAPON; + + // spawn teleport effect + SpawnTeleport(); + // return from editor model (if was fragged into pieces) + SwitchToModel(); + m_tmSpawned = _pTimer->CurrentTick(); + + en_tmLastBreathed = _pTimer->CurrentTick()+0.1f; // do not take breath when spawned in air + }; + + // note: set estimated time in advance + void RecordEndOfLevelData(void) + { + // must not be called multiple times + ASSERT(!m_bEndOfLevel); + // clear analyses message + m_tmAnalyseEnd = 0; + m_bPendingMessage = FALSE; + m_tmMessagePlay = 0; + // mark end of level + m_iMayRespawn = 0; + m_bEndOfLevel = TRUE; + // remember end time + time_t t; + time(&t); + m_iEndTime = (INDEX)t; + // add time score + TIME tmLevelTime = _pTimer->CurrentTick()-m_tmLevelStarted; + m_psLevelStats.ps_tmTime = tmLevelTime; + m_psGameStats.ps_tmTime += tmLevelTime; + FLOAT fTimeDelta = ClampDn(floor(m_tmEstTime)-floor(tmLevelTime), 0.0); + m_iTimeScore = floor(fTimeDelta*100.0f); + m_psLevelStats.ps_iScore+=m_iTimeScore; + m_psGameStats.ps_iScore+=m_iTimeScore; + + // record stats for this level and add to global table + CTString strStats; + strStats.PrintF(TRANS("%s\n Time: %s\n Score: %9d\n Kills: %03d/%03d\n Secrets: %02d/%02d\n"), + (const char*)TranslateConst(en_pwoWorld->GetName(), 0), (const char*)TimeToString(tmLevelTime), + m_psLevelStats.ps_iScore, + m_psLevelStats.ps_iKills, m_psLevelTotal.ps_iKills, + m_psLevelStats.ps_iSecrets, m_psLevelTotal.ps_iSecrets); + m_strLevelStats += strStats; + } + + // spawn teleport effect + void SpawnTeleport(void) + { + // if in singleplayer + if (GetSP()->sp_bSinglePlayer) { + // no spawn effects + return; + } + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_TELEPORT; + ese.vNormal = FLOAT3D(0,1,0); + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm()*2; + ese.vStretch = FLOAT3D(fEntitySize, fEntitySize, fEntitySize); + CEntityPointer penEffect = CreateEntity(GetPlacement(), CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + + + + // render particles + void RenderParticles(void) + { + // render empty shells + Particles_EmptyShells( this, m_asldData); + + if (Particle_GetViewer()==this) { + Particles_ViewerLocal(this); + } + + // spirit particles + if( m_tmSpiritStart != 0.0f) + { + Particles_Appearing(this, m_tmSpiritStart); + } + } + + void TeleportToAutoMarker(CPlayerActionMarker *ppam) + { + // if we are in coop + if (GetSP()->sp_bCooperative && !GetSP()->sp_bSinglePlayer) { + // for each player + for(INDEX iPlayer=0; iPlayerGetPlacement(); + FLOAT3D vOffsetRel = ppl->GetTeleportingOffset(); + pl.pl_PositionVector += vOffsetRel*ppam->en_mRotation; + ppl->Teleport(pl, FALSE); + // remember new respawn place + ppl->m_vDied = pl.pl_PositionVector; + ppl->m_aDied = pl.pl_OrientationAngle; + } + } + + // otherwise + } else { + // put yourself at marker + CPlacement3D pl = ppam->GetPlacement(); + FLOAT3D vOffsetRel = GetTeleportingOffset(); + pl.pl_PositionVector += vOffsetRel*ppam->en_mRotation; + Teleport(pl, FALSE); + } + } + + // check whether this time we respawn in place or on marker + void CheckDeathForRespawnInPlace(EDeath eDeath) + { + // if respawning in place is not allowed + if (!GetSP()->sp_bRespawnInPlace) { + // skip further checks + return; + } + // if killed by a player or enemy + CEntity *penKiller = eDeath.eLastDamage.penInflictor; + if (IsOfClass(penKiller, "Player") || IsDerivedFromClass(penKiller, "Enemy Base")) { + // mark for respawning in place + m_ulFlags |= PLF_RESPAWNINPLACE; + m_vDied = GetPlacement().pl_PositionVector; + m_aDied = GetPlacement().pl_OrientationAngle; + } + } + +procedures: +/************************************************************ + * WOUNDED * + ************************************************************/ + Wounded(EDamage eDamage) { + return; + }; + + +/************************************************************ + * WORLD CHANGE * + ************************************************************/ + WorldChange() { + // if in single player + if (GetSP()->sp_bSinglePlayer) { + // mark world as visited + CTString strDummy("1"); + SaveStringVar(GetWorld()->wo_fnmFileName.NoExt()+".vis", strDummy); + } + // find music holder on new world + FindMusicHolder(); + // store group name + m_strGroup = _SwcWorldChange.strGroup; + TeleportPlayer((WorldLinkType)_SwcWorldChange.iType); + // setup light source + SetupLightSource(); + + // update per-level stats + UpdateLevelStats(); + m_ulFlags |= PLF_INITIALIZED; + m_ulFlags &= ~PLF_CHANGINGLEVEL; + return; + }; + + WorldChangeDead() + { + // forbid respawning in-place when changing levels while dead + m_ulFlags &= ~PLF_RESPAWNINPLACE; + // if in single player + if (GetSP()->sp_bSinglePlayer) { + // mark world as visited + CTString strDummy("1"); + SaveStringVar(GetWorld()->wo_fnmFileName.NoExt()+".vis", strDummy); + } + // find music holder on new world + FindMusicHolder(); + // store group name + + autocall Rebirth() EReturn; + + // setup light source + SetupLightSource(); + + // update per-level stats + UpdateLevelStats(); + m_ulFlags |= PLF_INITIALIZED; + m_ulFlags &= ~PLF_CHANGINGLEVEL; + return; + } + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EDeath eDeath) { + // stop firing when dead + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EReleaseWeapon()); + // stop all looping ifeel effects + if(_pNetwork->IsPlayerLocal(this)) + { + IFeel_StopEffect("Minigun_rotate"); + } + + // if in single player, or if this is a predictor entity + if (GetSP()->sp_bSinglePlayer || IsPredictor()) { + // do not print anything + NOTHING; + // if in cooperative, but not single player + } else if (GetSP()->sp_bCooperative) { + // just print death message, no score updating + PrintPlayerDeathMessage(this, eDeath); + // check whether this time we respawn in place or on marker + CheckDeathForRespawnInPlace(eDeath); + // increase number of deaths + m_psLevelStats.ps_iDeaths += 1; + m_psGameStats.ps_iDeaths += 1; + // if not in cooperative, and not single player + } else { + // print death message + PrintPlayerDeathMessage(this, eDeath); + // get the killer pointer + CEntity *penKiller = eDeath.eLastDamage.penInflictor; + // initially, not killed by a player + CPlayer *pplKillerPlayer = NULL; + + // if killed by some entity + if (penKiller!=NULL) { + // if killed by player + if (IsOfClass(penKiller, "Player")) { + // if someone other then you + if (penKiller!=this) { + pplKillerPlayer = (CPlayer*)penKiller; + EReceiveScore eScore; + eScore.iPoints = m_iMana; + eDeath.eLastDamage.penInflictor->SendEvent(eScore); + eDeath.eLastDamage.penInflictor->SendEvent(EKilledEnemy()); + // if it was yourself + } else { + m_psLevelStats.ps_iScore -= m_iMana; + m_psGameStats.ps_iScore -= m_iMana; + m_psLevelStats.ps_iKills -= 1; + m_psGameStats.ps_iKills -= 1; + } + // if killed by non-player + } else { + m_psLevelStats.ps_iScore -= m_iMana; + m_psGameStats.ps_iScore -= m_iMana; + m_psLevelStats.ps_iKills -= 1; + m_psGameStats.ps_iKills -= 1; + } + // if killed by NULL (shouldn't happen, but anyway) + } else { + m_psLevelStats.ps_iScore -= m_iMana; + m_psGameStats.ps_iScore -= m_iMana; + m_psLevelStats.ps_iKills -= 1; + m_psGameStats.ps_iKills -= 1; + } + + // if playing scorematch + if (!GetSP()->sp_bUseFrags) { + // if killed by a player + if (pplKillerPlayer!=NULL) { + // print how much that player gained + CPrintF(TRANS(" %s: +%d points\n"), (const char*)pplKillerPlayer->GetPlayerName(), m_iMana); + // if it was a suicide, or an accident + } else { + // print how much you lost + CPrintF(TRANS(" %s: -%d points\n"), (const char*)GetPlayerName(), m_iMana); + } + } + + // increase number of deaths + m_psLevelStats.ps_iDeaths += 1; + m_psGameStats.ps_iDeaths += 1; + } + + // store last view + m_iLastViewState = m_iViewState; + + // mark player as death + SetFlags(GetFlags()&~ENF_ALIVE); + // stop player + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + SetDesiredRotation(ANGLE3D(0.0f, 0.0f, 0.0f)); + + // remove weapon from hand + ((CPlayerAnimator&)*m_penAnimator).RemoveWeapon(); + // kill weapon animations + GetPlayerWeapons()->SendEvent(EStop()); + + // if in deathmatch + if (!GetSP()->sp_bCooperative) { + // drop current weapon as item so others can pick it + GetPlayerWeapons()->DropWeapon(); + } + + + // play death + INDEX iAnim1; + INDEX iAnim2; + if (m_pstState == PST_SWIM || m_pstState == PST_DIVE) { + iAnim1 = PLAYER_ANIM_DEATH_UNDERWATER; + iAnim2 = BODY_ANIM_DEATH_UNDERWATER; + } else if (eDeath.eLastDamage.dmtType==DMT_SPIKESTAB) { + iAnim1 = PLAYER_ANIM_DEATH_SPIKES; + iAnim2 = BODY_ANIM_DEATH_SPIKES; + } else if (eDeath.eLastDamage.dmtType==DMT_ABYSS) { + iAnim1 = PLAYER_ANIM_ABYSSFALL; + iAnim2 = BODY_ANIM_ABYSSFALL; + } else { + FLOAT3D vFront; + GetHeadingDirection(0, vFront); + FLOAT fDamageDir = m_vDamage%vFront; + if (fDamageDir<0) { + if (Abs(fDamageDir)<10.0f) { + iAnim1 = PLAYER_ANIM_DEATH_EASYFALLBACK; + iAnim2 = BODY_ANIM_DEATH_EASYFALLBACK; + } else { + iAnim1 = PLAYER_ANIM_DEATH_BACK; + iAnim2 = BODY_ANIM_DEATH_BACK; + } + } else { + if (Abs(fDamageDir)<10.0f) { + iAnim1 = PLAYER_ANIM_DEATH_EASYFALLFORWARD; + iAnim2 = BODY_ANIM_DEATH_EASYFALLFORWARD; + } else { + iAnim1 = PLAYER_ANIM_DEATH_FORWARD; + iAnim2 = BODY_ANIM_DEATH_FORWARD; + } + } + } + en_plViewpoint.pl_OrientationAngle = ANGLE3D(0,0,0); + StartModelAnim(iAnim1, 0); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(iAnim2, 0); + + // set physic flags + SetPhysicsFlags(EPF_MODEL_CORPSE); + SetCollisionFlags(ECF_CORPSE); + + // set density to float out of water + en_fDensity = 400.0f; + + // play sound + if (m_pstState==PST_DIVE) { + SetDefaultMouthPitch(); + PlaySound(m_soMouth, SOUND_DEATHWATER, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("DeathWater");} + } else { + SetDefaultMouthPitch(); + PlaySound(m_soMouth, SOUND_DEATH, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("Death");} + } + + // initialize death camera view + ASSERT(m_penView == NULL); + if (m_penView == NULL) { + m_penView = CreateEntity(GetPlacement(), CLASS_PLAYER_VIEW); + EViewInit eInit; + eInit.penOwner = this; + eInit.penCamera = NULL; + eInit.vtView = VT_PLAYERDEATH; + eInit.bDeathFixed = eDeath.eLastDamage.dmtType==DMT_ABYSS; + m_penView->Initialize(eInit); + } + + if (ShouldBlowUp()) { + BlowUp(); + } else { + // leave a stain beneath + LeaveStain(TRUE); + } + + m_iMayRespawn = 0; + // wait for anim of death + wait (1.2f) { + on (EBegin) : { + // set new view status + m_iViewState = PVT_PLAYERAUTOVIEW; + resume; + } + // when anim is finished + on (ETimer) : { + // allow respawning + m_iMayRespawn = 1; + resume; + } + // when damaged + on (EDamage eDamage) : { + if (eDamage.dmtType==DMT_ABYSS) { + if (m_penView!=NULL) { + ((CPlayerView*)&*m_penView)->m_bFixed = TRUE; + } + } + // if should blow up now (and not already blown up) + if (ShouldBlowUp()) { + // do it + BlowUp(); + } + resume; + } + on (EDeath) : { resume; } + // if player pressed fire + on (EEnd) : { + // NOTE: predictors must never respawn since player markers for respawning are not predicted + // if this is not predictor + if (!IsPredictor()) { + // stop waiting + stop; + } + } + // if autoaction is received + on (EAutoAction eAutoAction) : { + // if we are in coop + if (GetSP()->sp_bCooperative && !GetSP()->sp_bSinglePlayer) { + // if the marker is teleport marker + if (eAutoAction.penFirstMarker!=NULL && + ((CPlayerActionMarker*)&*eAutoAction.penFirstMarker)->m_paaAction == PAA_TELEPORT) { + // teleport there + TeleportToAutoMarker((CPlayerActionMarker*)&*eAutoAction.penFirstMarker); + } + } + // ignore the actions + resume; + } + on (EDisconnected) : { pass; } + on (EReceiveScore) : { pass; } + on (EPreLevelChange) : { pass; } + on (EPostLevelChange) : { pass; } + otherwise() : { resume; } + } + + return ERebirth(); + }; + + TheEnd() { + // if not playing demo + if (!_pNetwork->IsPlayingDemo()) { + // record high score in single player only + if (GetSP()->sp_bSinglePlayer) { + _pShell->Execute("gam_iRecordHighScore=0;"); + } + } + // if current difficulty is serious + if (GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_EXTREME) { + // activate the mental mode + _pShell->Execute("sam_bMentalActivated=1;"); + } + + // stop firing when end + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EReleaseWeapon()); + + // mark player as dead + SetFlags(GetFlags()&~ENF_ALIVE); + // stop player + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + SetDesiredRotation(ANGLE3D(0.0f, 0.0f, 0.0f)); + + // look straight + StartModelAnim(PLAYER_ANIM_STAND, 0); + ((CPlayerAnimator&)*m_penAnimator).BodyAnimationTemplate( + BODY_ANIM_NORMALWALK, BODY_ANIM_COLT_STAND, BODY_ANIM_SHOTGUN_STAND, BODY_ANIM_MINIGUN_STAND, + AOF_LOOPING|AOF_NORESTART); + + en_plViewpoint.pl_OrientationAngle = ANGLE3D(0,0,0); + + // call computer + m_bEndOfGame = TRUE; + SetGameEnd(); + + wait () { + on (EBegin) : { resume; } + on (EReceiveScore) : { pass; } + on (ECenterMessage) : { pass; } + otherwise() : { resume; } + } + }; + +/************************************************************ + * R E B I R T H * + ************************************************************/ + FirstInit() { + // restore last view + m_iViewState = m_iLastViewState; + + // stop and kill camera + if (m_penView != NULL) { + ((CPlayerView&)*m_penView).SendEvent(EEnd()); + m_penView = NULL; + } + + FindMusicHolder(); + + // update per-level stats + UpdateLevelStats(); + + // initialize player (from PlayerMarker) + InitializePlayer(); + + // add statistics message + ReceiveComputerMessage(CTFILENAME("Data\\Messages\\Statistics\\Statistics.txt"), CMF_READ); + + if (GetSettings()->ps_ulFlags&PSF_PREFER3RDPERSON) { + ChangePlayerView(); + } + + return; + }; + + Rebirth() { + // restore last view + m_iViewState = m_iLastViewState; + // clear ammunition + if (!(m_ulFlags&PLF_RESPAWNINPLACE)) { + GetPlayerWeapons()->ClearWeapons(); + } + + // stop and kill camera + if (m_penView != NULL) { + ((CPlayerView&)*m_penView).SendEvent(EEnd()); + m_penView = NULL; + } + + FindMusicHolder(); + + // initialize player (from PlayerMarker) + InitializePlayer(); + + return EReturn(); + }; + + + // auto action - go to current marker + AutoGoToMarker(EVoid) + { + ULONG ulFlags = AOF_LOOPING|AOF_NORESTART; + + INDEX iAnim = GetModelObject()->GetAnim(); + if( iAnim!=PLAYER_ANIM_STAND) + { + ulFlags |= AOF_SMOOTHCHANGE; + } + + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyWalkAnimation(); + if (m_fAutoSpeed>plr_fSpeedForward/2) { + StartModelAnim(PLAYER_ANIM_RUN, ulFlags); + } else { + StartModelAnim(PLAYER_ANIM_NORMALWALK, ulFlags); + } + + // while not at marker + while ( + (m_penActionMarker->GetPlacement().pl_PositionVector- + GetPlacement().pl_PositionVector).Length()>1.0f) { + // wait a bit + autowait(_pTimer->TickQuantum); + } + + // return to auto-action loop + return EReturn(); + } + + // auto action - go to current marker and stop there + AutoGoToMarkerAndStop(EVoid) + { + ULONG ulFlags = AOF_LOOPING|AOF_NORESTART; + + INDEX iAnim = GetModelObject()->GetAnim(); + if( iAnim!=PLAYER_ANIM_STAND) + { + ulFlags |= AOF_SMOOTHCHANGE; + } + + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyWalkAnimation(); + if (m_fAutoSpeed>plr_fSpeedForward/2) { + StartModelAnim(PLAYER_ANIM_RUN, ulFlags); + } else { + StartModelAnim(PLAYER_ANIM_NORMALWALK, ulFlags); + } + + // while not at marker + while ( + (m_penActionMarker->GetPlacement().pl_PositionVector- + GetPlacement().pl_PositionVector).Length()>m_fAutoSpeed*_pTimer->TickQuantum*2.00f) { + // wait a bit + autowait(_pTimer->TickQuantum); + } + // disable auto speed + m_fAutoSpeed = 0.0f; + + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyStillAnimation(); + StartModelAnim(PLAYER_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + + // stop moving + ForceFullStop(); + + // return to auto-action loop + return EReturn(); + } + + // auto action - use an item + AutoUseItem(EVoid) + { + + // start pulling the item + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyPullItemAnimation(); + //StartModelAnim(PLAYER_ANIM_STATUE_PULL, 0); + + autowait(0.2f); + + // item appears + CPlayerActionMarker *ppam = GetActionMarker(); + if (IsOfClass(ppam->m_penItem, "KeyItem")) { + CModelObject &moItem = ppam->m_penItem->GetModelObject()->GetAttachmentModel(0)->amo_moModelObject; + GetPlayerAnimator()->SetItem(&moItem); + } + + autowait(2.20f-0.2f); + + // the item is in place + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyRemoveItem(); + // if marker points to a trigger + if (GetActionMarker()->m_penTrigger!=NULL) { + // trigger it + SendToTarget(GetActionMarker()->m_penTrigger, EET_TRIGGER, this); + } + + // fake that player has passed through the door controller + if (GetActionMarker()->m_penDoorController!=NULL) { + EPass ePass; + ePass.penOther = this; + GetActionMarker()->m_penDoorController->SendEvent(ePass); + } + + autowait(3.25f-2.20f); + + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyRemoveItem(); + + // return to auto-action loop + return EReturn(); + } + + // auto action - pick an item + AutoPickItem(EVoid) + { + + // start pulling the item + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyPickItemAnimation(); + StartModelAnim(PLAYER_ANIM_KEYLIFT, 0); + + autowait(1.2f); + + // if marker points to a trigger + if (GetActionMarker()->m_penTrigger!=NULL) { + // trigger it + SendToTarget(GetActionMarker()->m_penTrigger, EET_TRIGGER, this); + } + + // item appears + CPlayerActionMarker *ppam = GetActionMarker(); + if (IsOfClass(ppam->m_penItem, "KeyItem")) { + CModelObject &moItem = ppam->m_penItem->GetModelObject()->GetAttachmentModel(0)->amo_moModelObject; + GetPlayerAnimator()->SetItem(&moItem); + EPass ePass; + ePass.penOther = this; + ppam->m_penItem->SendEvent(ePass); + } + + autowait(3.6f-1.2f+GetActionMarker()->m_tmWait); + + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyRemoveItem(); + + // return to auto-action loop + return EReturn(); + } + + AutoFallDown(EVoid) + { + StartModelAnim(PLAYER_ANIM_BRIDGEFALLPOSE, 0); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_BRIDGEFALLPOSE, 0); + + autowait(GetActionMarker()->m_tmWait); + + // return to auto-action loop + return EReturn(); + } + + AutoFallToAbys(EVoid) + { + StartModelAnim(PLAYER_ANIM_ABYSSFALL, AOF_LOOPING); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_ABYSSFALL, AOF_LOOPING); + + autowait(GetActionMarker()->m_tmWait); + + // return to auto-action loop + return EReturn(); + } + + // auto action - look around + AutoLookAround(EVoid) + { + StartModelAnim(PLAYER_ANIM_BACKPEDAL, 0); + m_vAutoSpeed = FLOAT3D(0,0,plr_fSpeedForward/4/0.75f); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_NORMALWALK, 0); + + autowait(GetModelObject()->GetCurrentAnimLength()/2); + + m_vAutoSpeed = FLOAT3D(0,0,0); + + // start looking around + StartModelAnim(PLAYER_ANIM_STAND, 0); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_LOOKAROUND, 0); + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + + // wait given time + autowait(moBody.GetCurrentAnimLength()+0.1f); + + // return to auto-action loop + return EReturn(); + } + + AutoTeleport(EVoid) + { + // teleport there + TeleportToAutoMarker(GetActionMarker()); + + // return to auto-action loop + return EReturn(); + } + + AutoAppear(EVoid) + { + // hide the model + SwitchToEditorModel(); + + // put it at marker + Teleport(GetActionMarker()->GetPlacement()); + // make it rotate in spawnpose + SetPhysicsFlags(GetPhysicsFlags() & ~(EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY)); + m_ulFlags|=PLF_AUTOMOVEMENTS; + SetDesiredRotation(ANGLE3D(60,0,0)); + StartModelAnim(PLAYER_ANIM_SPAWNPOSE, AOF_LOOPING); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_SPAWNPOSE, AOF_LOOPING); + + // start stardust appearing + m_tmSpiritStart = _pTimer->CurrentTick(); + // wait till it appears + autowait(5); + + // start model appearing + SwitchToModel(); + m_tmFadeStart = _pTimer->CurrentTick(); + // wait till it appears + autowait(5); + // fixate full opacity + COLOR colAlpha = GetModelObject()->mo_colBlendColor; + GetModelObject()->mo_colBlendColor = colAlpha|0xFF; + + // put it to normal state + SetPhysicsFlags(GetPhysicsFlags() | EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY); + SetDesiredRotation(ANGLE3D(0,0,0)); + m_ulFlags&=~PLF_AUTOMOVEMENTS; + + // play animation to fall down + StartModelAnim(PLAYER_ANIM_SPAWN_FALLDOWN, 0); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_SPAWN_FALLDOWN, 0); + + autowait(GetModelObject()->GetCurrentAnimLength()); + + // play animation to get up + StartModelAnim(PLAYER_ANIM_SPAWN_GETUP, AOF_SMOOTHCHANGE); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_SPAWN_GETUP, AOF_SMOOTHCHANGE); + + autowait(GetModelObject()->GetCurrentAnimLength()); + + // return to auto-action loop + return EReturn(); + } + + TravellingInBeam() + { + // put it at marker + Teleport(GetActionMarker()->GetPlacement()); + // make it rotate in spawnpose + SetPhysicsFlags(GetPhysicsFlags() & ~(EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY)); + m_ulFlags|=PLF_AUTOMOVEMENTS; + SetDesiredRotation(ANGLE3D(60,0,0)); + SetDesiredTranslation(ANGLE3D(0,20.0f,0)); + StartModelAnim(PLAYER_ANIM_SPAWNPOSE, AOF_LOOPING); + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_SPAWNPOSE, AOF_LOOPING); + // wait till it appears + autowait(8.0f); + // switch to model + SwitchToEditorModel(); + // return to auto-action loop + return EReturn(); + } + + LogoFireMinigun(EVoid) + { + // put it at marker + CPlacement3D pl = GetActionMarker()->GetPlacement(); + pl.pl_PositionVector += FLOAT3D(0, 0.01f, 0)*GetActionMarker()->en_mRotation; + Teleport(pl); + en_plViewpoint.pl_OrientationAngle(1) = 20.0f; + en_plLastViewpoint.pl_OrientationAngle = en_plViewpoint.pl_OrientationAngle; + + // stand in pose + StartModelAnim(PLAYER_ANIM_INTRO, AOF_LOOPING); + // remember time for rotating view start + m_tmMinigunAutoFireStart = _pTimer->CurrentTick(); + // wait some time for fade in and to look from left to right with out fireing + //autowait(0.75f); + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EFireWeapon()); + autowait(2.5f); + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EReleaseWeapon()); + + // stop minigun shaking + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_MINIGUN_STAND, 0); + + autowait(0.5f); + + // ---------- Apply shake + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer != NULL) + { + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + pwsc->m_tmShakeStarted = _pTimer->CurrentTick(); + pwsc->m_vShakePos = GetPlacement().pl_PositionVector; + pwsc->m_fShakeFalloff = 250.0f; + pwsc->m_fShakeFade = 3.0f; + + pwsc->m_fShakeIntensityZ = 0.1f*2.0f; + pwsc->m_tmShakeFrequencyZ = 5.0f; + pwsc->m_fShakeIntensityY = 0.0f; + pwsc->m_fShakeIntensityB = 0.0f; + +/* + pwsc->m_fShakeIntensityY = 0.1f*2.0f; + pwsc->m_tmShakeFrequencyY = 5.0f; + pwsc->m_fShakeIntensityB = 2.5f*1.5f; + pwsc->m_tmShakeFrequencyB = 7.2f; + */ + } + + // stop rotating body + m_tmMinigunAutoFireStart = -1; + autowait(10.0f); + + return EReturn(); + } + + AutoStoreWeapon(EVoid) + { + // store current weapon slowly + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.BodyAnimationTemplate(BODY_ANIM_WAIT, + BODY_ANIM_COLT_REDRAWSLOW, BODY_ANIM_SHOTGUN_REDRAWSLOW, BODY_ANIM_MINIGUN_REDRAWSLOW, + 0); + autowait(plan.m_fBodyAnimTime); + + m_iAutoOrgWeapon = ((CPlayerWeapons&)*m_penWeapons).m_iCurrentWeapon; + ((CPlayerWeapons&)*m_penWeapons).m_iCurrentWeapon = WEAPON_NONE; + ((CPlayerWeapons&)*m_penWeapons).m_iWantedWeapon = WEAPON_NONE; + + // sync apperances + GetPlayerAnimator()->SyncWeapon(); + // remove weapon attachment + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.m_iWeaponLast = m_iAutoOrgWeapon; + plan.RemoveWeapon(); + GetPlayerAnimator()->SyncWeapon(); + + ((CPlayerWeapons&)*m_penWeapons).m_iCurrentWeapon = (WeaponType) m_iAutoOrgWeapon; + plan.BodyAnimationTemplate(BODY_ANIM_WAIT, + BODY_ANIM_COLT_DEACTIVATETOWALK, BODY_ANIM_SHOTGUN_DEACTIVATETOWALK, BODY_ANIM_MINIGUN_DEACTIVATETOWALK, AOF_SMOOTHCHANGE); + ((CPlayerWeapons&)*m_penWeapons).m_iCurrentWeapon = WEAPON_NONE; + + autowait(plan.m_fBodyAnimTime); + + // return to auto-action loop + return EReturn(); + } + + // perform player auto actions + DoAutoActions(EVoid) + { + // don't look up/down + en_plViewpoint.pl_OrientationAngle = ANGLE3D(0,0,0); + // disable playeranimator animating + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.m_bDisableAnimating = TRUE; + + // while there is some marker + while (m_penActionMarker!=NULL && IsOfClass(m_penActionMarker, "PlayerActionMarker")) { + + // if should wait + if (GetActionMarker()->m_paaAction==PAA_WAIT) { + // play still anim + CModelObject &moBody = GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(BODY_ANIM_WAIT, AOF_NORESTART|AOF_LOOPING); + // wait given time + autowait(GetActionMarker()->m_tmWait); + + // if should teleport here + } else if (GetActionMarker()->m_paaAction==PAA_APPEARING) { + autocall AutoAppear() EReturn; + } else if (GetActionMarker()->m_paaAction==PAA_TRAVELING_IN_BEAM) { + autocall TravellingInBeam() EReturn; + } else if (GetActionMarker()->m_paaAction==PAA_LOGO_FIRE_MINIGUN) { + autocall LogoFireMinigun() EReturn; + // if should appear here + } else if (GetActionMarker()->m_paaAction==PAA_TELEPORT) { + autocall AutoTeleport() EReturn; + + // if should wait for trigger + } else if (GetActionMarker()->m_paaAction==PAA_WAITFOREVER) { + // wait forever + wait() { + on (EBegin) : { resume; } + otherwise() : { pass; } + } + // if should store weapon + } else if (GetActionMarker()->m_paaAction==PAA_STOREWEAPON) { + autocall AutoStoreWeapon() EReturn; + + // if should draw weapon + } else if (GetActionMarker()->m_paaAction==PAA_DRAWWEAPON) { + // order playerweapons to select best weapon + ESelectWeapon eSelect; + eSelect.iWeapon = -4; + ((CPlayerWeapons&)*m_penWeapons).SendEvent(eSelect); + + // if should wait + } else if (GetActionMarker()->m_paaAction==PAA_LOOKAROUND) { + autocall AutoLookAround() EReturn; + + // if should use item + } else if (GetActionMarker()->m_paaAction==PAA_USEITEM) { + // use it + autocall AutoUseItem() EReturn; + + // if should pick item + } else if (GetActionMarker()->m_paaAction==PAA_PICKITEM) { + // pick it + autocall AutoPickItem() EReturn; + + // if falling from bridge + } else if (GetActionMarker()->m_paaAction==PAA_FALLDOWN) { + // fall + autocall AutoFallDown() EReturn; + + // if releasing player + } else if (GetActionMarker()->m_paaAction==PAA_RELEASEPLAYER) { + if (m_penCamera!=NULL) { + ((CCamera*)&*m_penCamera)->m_bStopMoving=TRUE; + } + m_penCamera = NULL; + // if currently not having any weapon in hand + if (GetPlayerWeapons()->m_iCurrentWeapon == WEAPON_NONE) { + // order playerweapons to select best weapon + ESelectWeapon eSelect; + eSelect.iWeapon = -4; + ((CPlayerWeapons&)*m_penWeapons).SendEvent(eSelect); + } + // sync weapon, just in case + m_ulFlags |= PLF_SYNCWEAPON; + m_tmSpiritStart = 0; + + // if start computer + } else if (GetActionMarker()->m_paaAction==PAA_STARTCOMPUTER) { + // mark that + if (_pNetwork->IsPlayerLocal(this) && GetSP()->sp_bSinglePlayer) { + cmp_ppenPlayer = this; + cmp_bInitialStart = TRUE; + } + + // if start introscroll + } else if (GetActionMarker()->m_paaAction==PAA_STARTINTROSCROLL) { + _pShell->Execute("sam_iStartCredits=1;"); + + // if start credits + } else if (GetActionMarker()->m_paaAction==PAA_STARTCREDITS) { + _pShell->Execute("sam_iStartCredits=2;"); + + // if stop scroller + } else if (GetActionMarker()->m_paaAction==PAA_STOPSCROLLER) { + _pShell->Execute("sam_iStartCredits=-1;"); + + // if should run to the marker + } else if (GetActionMarker()->m_paaAction==PAA_RUN) { + // go to it + m_fAutoSpeed = plr_fSpeedForward*GetActionMarker()->m_fSpeed; + autocall AutoGoToMarker() EReturn; + + // if should run to the marker and stop exactly there + } else if (GetActionMarker()->m_paaAction==PAA_RUNANDSTOP) { + // go to it + m_fAutoSpeed = plr_fSpeedForward*GetActionMarker()->m_fSpeed; + autocall AutoGoToMarkerAndStop() EReturn; + + // if should record end-of-level stats + } else if (GetActionMarker()->m_paaAction==PAA_RECORDSTATS) { + + if ((GetSP()->sp_bSinglePlayer || GetSP()->sp_bPlayEntireGame)) { + // remeber estimated time + m_tmEstTime = GetActionMarker()->m_tmWait; + // record stats + RecordEndOfLevelData(); + } else { + SetGameEnd(); + } + + // if should show statistics to the player + } else if (GetActionMarker()->m_paaAction==PAA_SHOWSTATS) { + // !! FIXUP for the 'half' edition of the first encounter + if (GetWorld()->wo_fnmFileName==plr_strLastLevel) { + jump TheEnd(); + } + + // call computer + if (cmp_ppenPlayer==NULL && _pNetwork->IsPlayerLocal(this) && GetSP()->sp_bSinglePlayer) { + m_bEndOfLevel = TRUE; + cmp_ppenPlayer = this; + m_ulFlags|=PLF_DONTRENDER; + while(m_bEndOfLevel) { + wait(_pTimer->TickQuantum) { + on (ETimer) : { stop; } + on (EReceiveScore) : { pass; } + on (ECenterMessage) : { pass; } + otherwise() : { resume; } + } + } + m_ulFlags&=!PLF_DONTRENDER; + } + // if end of entire game + } else if (GetActionMarker()->m_paaAction==PAA_ENDOFGAME) { + + // record stats + jump TheEnd(); + } else if (GetActionMarker()->m_paaAction==PAA_NOGRAVITY) { + SetPhysicsFlags(GetPhysicsFlags() & ~(EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY)); + if( GetActionMarker()->GetParent() != NULL) + { + SetParent(GetActionMarker()->GetParent()); + } + } else if (GetActionMarker()->m_paaAction==PAA_TURNONGRAVITY) { + SetPhysicsFlags(GetPhysicsFlags()|EPF_TRANSLATEDBYGRAVITY|EPF_ORIENTEDBYGRAVITY); + SetParent(NULL); + } + else if (TRUE) { + ASSERT(FALSE); + } + + // if marker points to a trigger + if (GetActionMarker()->m_penTrigger!=NULL && + GetActionMarker()->m_paaAction!=PAA_PICKITEM) { + // trigger it + SendToTarget(GetActionMarker()->m_penTrigger, EET_TRIGGER, this); + } + + // get next marker + m_penActionMarker = GetActionMarker()->m_penTarget; + } + + // must clear marker, in case it was invalid + m_penActionMarker = NULL; + + // enable playeranimator animating + CPlayerAnimator &plan = (CPlayerAnimator&)*m_penAnimator; + plan.m_bDisableAnimating = FALSE; + + // return to main loop + return EVoid(); + } +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid evoid) + { + // remember start time + time_t t; + time(&t); + m_iStartTime = (INDEX)t; + + m_ctUnreadMessages = 0; + SetFlags(GetFlags()|ENF_CROSSESLEVELS|ENF_NOTIFYLEVELCHANGE); + InitAsEditorModel(); + + // set default model for physics etc + CTString strDummy; + SetPlayerAppearance(GetModelObject(), NULL, strDummy, /*bPreview=*/FALSE); + // set your real appearance if possible + ValidateCharacter(); + SetPlayerAppearance(&m_moRender, &en_pcCharacter, strDummy, /*bPreview=*/FALSE); + + // if unsuccessful + if (GetModelObject()->GetData()==NULL) { + // never proceed with initialization - player cannot work + return; + } + + //const FLOAT fSize = 2.1f/1.85f; + //GetModelObject()->StretchModel(FLOAT3D(fSize, fSize, fSize)); + ModelChangeNotify(); + + // wait a bit to allow other entities to start + wait(0.2f) { // this is 4 ticks, it has to be at least more than musicchanger for enemy counting + on (EBegin) : { resume; } + on (ETimer) : { stop; } + on (EDisconnected) : { + Destroy(); + return; + } + } + + // do not use predictor if not yet initialized + if (IsPredictor()) { // !!!!#### + Destroy(); + return; + } + + // appear + SwitchToModel(); + m_ulFlags|=PLF_INITIALIZED; + + // set initial vars + en_tmMaxHoldBreath = 60.0f; + en_fDensity = 1000.0f; // same density as water - to be able to dive freely + + ModelChangeNotify(); + + // spawn weapons + m_penWeapons = CreateEntity(GetPlacement(), CLASS_PLAYER_WEAPONS); + EWeaponsInit eInitWeapons; + eInitWeapons.penOwner = this; + m_penWeapons->Initialize(eInitWeapons); + + // spawn animator + m_penAnimator = CreateEntity(GetPlacement(), CLASS_PLAYER_ANIMATOR); + EAnimatorInit eInitAnimator; + eInitAnimator.penPlayer = this; + m_penAnimator->Initialize(eInitAnimator); + + // set sound default parameters + m_soMouth.Set3DParameters(50.0f, 10.0f, 1.0f, 1.0f); + m_soFootL.Set3DParameters(20.0f, 2.0f, 1.0f, 1.0f); + m_soFootR.Set3DParameters(20.0f, 2.0f, 1.0f, 1.0f); + m_soBody.Set3DParameters(25.0f, 5.0f, 1.0f, 1.0f); + m_soMessage.Set3DParameters(25.0f, 5.0f, 1.0f, 1.0f); + + // setup light source + SetupLightSource(); + + // set light animation if available + try { + m_aoLightAnimation.SetData_t(CTFILENAME("Animations\\BasicEffects.ani")); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load Animations\\BasicEffects.ani: %s"), strError); + } + PlayLightAnim(LIGHT_ANIM_NONE, 0); + + wait() { + on (EBegin) : { call FirstInit(); } + on (ERebirth) : { call Rebirth(); } + on (EDeath eDeath) : { call Death(eDeath); } + on (EDamage eDamage) : { call Wounded(eDamage); } + on (EPreLevelChange) : { + m_ulFlags&=~PLF_INITIALIZED; + m_ulFlags|=PLF_CHANGINGLEVEL; + m_ulFlags &= ~PLF_LEVELSTARTED; + resume; + } + on (EPostLevelChange) : { + if (GetSP()->sp_bSinglePlayer || (GetFlags()&ENF_ALIVE)) { + call WorldChange(); + } else { + call WorldChangeDead(); + } + } + on (ETakingBreath eTakingBreath ) : { + SetDefaultMouthPitch(); + if (eTakingBreath.fBreathDelay<0.2f) { + PlaySound(m_soMouth, SOUND_INHALE0, SOF_3D); + } else if (eTakingBreath.fBreathDelay<0.8f) { + PlaySound(m_soMouth, SOUND_INHALE1, SOF_3D); + } else { + PlaySound(m_soMouth, SOUND_INHALE2, SOF_3D); + } + resume; + } + on (ECameraStart eStart) : { + m_penCamera = eStart.penCamera; + // stop player + if (m_penActionMarker==NULL) { + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + SetDesiredRotation(ANGLE3D(0.0f, 0.0f, 0.0f)); + } + // stop firing + ((CPlayerWeapons&)*m_penWeapons).SendEvent(EReleaseWeapon()); + resume; + } + on (ECameraStop eCameraStop) : { + if (m_penCamera==eCameraStop.penCamera) { + m_penCamera = NULL; + } + resume; + } + on (ECenterMessage eMsg) : { + m_strCenterMessage = eMsg.strMessage; + m_tmCenterMessageEnd = _pTimer->CurrentTick()+eMsg.tmLength; + if (eMsg.mssSound==MSS_INFO) { + m_soMessage.Set3DParameters(25.0f, 5.0f, 1.0f, 1.0f); + PlaySound(m_soMessage, SOUND_INFO, SOF_3D|SOF_VOLUMETRIC|SOF_LOCAL); + } + resume; + } + on (EComputerMessage eMsg) : { + ReceiveComputerMessage(eMsg.fnmMessage, CMF_ANALYZE); + resume; + } + on (EVoiceMessage eMsg) : { + SayVoiceMessage(eMsg.fnmMessage); + resume; + } + on (EAutoAction eAutoAction) : { + // remember first marker + m_penActionMarker = eAutoAction.penFirstMarker; + // do the actions + call DoAutoActions(); + } + on (EReceiveScore eScore) : { + m_psLevelStats.ps_iScore += eScore.iPoints; + m_psGameStats.ps_iScore += eScore.iPoints; + m_iMana += eScore.iPoints*GetSP()->sp_fManaTransferFactor; + CheckHighScore(); + resume; + } + on (EKilledEnemy) : { + m_psLevelStats.ps_iKills += 1; + m_psGameStats.ps_iKills += 1; + resume; + } + on (ESecretFound) : { + m_psLevelStats.ps_iSecrets += 1; + m_psGameStats.ps_iSecrets += 1; + resume; + } + // EEnd should not arrive here + on (EEnd) : { + ASSERT(FALSE); + resume; + } + // if player is disconnected + on (EDisconnected) : { + // exit the loop + stop; + } + // support for jumping using bouncers + on (ETouch eTouch) : { + if (IsOfClass(eTouch.penOther, "Bouncer")) { + JumpFromBouncer(this, eTouch.penOther); + // play jump sound + SetDefaultMouthPitch(); + PlaySound(m_soMouth, SOUND_JUMP, SOF_3D); + if(_pNetwork->IsPlayerLocal(this)) {IFeel_PlayEffect("Jump");} + } + resume; + } + } + + // we get here if the player is disconnected from the server + + // if we have some keys + if (!IsPredictor() && m_ulKeys!=0) { + // find first live player + CPlayer *penNextPlayer = NULL; + for(INDEX iPlayer=0; iPlayerGetFlags()&ENF_ALIVE) && !(pen->GetFlags()&ENF_DELETED) ) { + penNextPlayer = pen; + } + } + + // if any found + if (penNextPlayer!=NULL) { + // transfer keys to that player + CPrintF(TRANS("%s leaving, all keys transfered to %s\n"), + (const char*)m_strName, (const char*)penNextPlayer->GetPlayerName()); + penNextPlayer->m_ulKeys |= m_ulKeys; + } + } + + // spawn teleport effect + SpawnTeleport(); + + // cease to exist + m_penWeapons->Destroy(); + m_penAnimator->Destroy(); + if (m_penView!=NULL) { + m_penView->Destroy(); + } + if (m_pen3rdPersonView!=NULL) { + m_pen3rdPersonView->Destroy(); + } + Destroy(); + return; + }; +}; diff --git a/Sources/Entities/PlayerActionMarker.es b/Sources/Entities/PlayerActionMarker.es new file mode 100644 index 0000000..34e6609 --- /dev/null +++ b/Sources/Entities/PlayerActionMarker.es @@ -0,0 +1,107 @@ +407 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; +uses "Entities/Player"; + +enum PlayerAutoAction { + 1 PAA_RUN "Run", // run to this marker + 2 PAA_WAIT "Wait", // wait given time + 3 PAA_USEITEM "UseItem", // use some item here + 4 PAA_STOREWEAPON "StoreWeapon", // put current weapon away + 5 PAA_DRAWWEAPON "DrawWeapon", // put current weapon back in hand + 6 PAA_LOOKAROUND "LookAround", // wait given time and look around + 7 PAA_RUNANDSTOP "RunAndStop", // run to this marker and stop at it + 8 PAA_RECORDSTATS "RecordStats", // before end of level animation - record statistics + 9 PAA_ENDOFGAME "EndOfGame", // the game has ended - go to computer, then to menu + 10 PAA_SHOWSTATS "ShowStats", // after end of level animation - show statistics + 11 PAA_APPEARING "Appearing", // appearing with stardust effect + 12 PAA_WAITFOREVER "WaitForever", // wait trigger + 13 PAA_TELEPORT "Teleport", // teleport to new location + 14 PAA_PICKITEM "PickItem", // pick item + 15 PAA_FALLDOWN "FallDown", // falling from broken bridge + 16 PAA_FALLTOABYSS "FallToAbyss", // falling down into an abyss + 17 PAA_RELEASEPLAYER "ReleasePlayer", // return control to player from camera and similar + 18 PAA_STARTCOMPUTER "StartComputer", // invoke netricsa + 19 PAA_TRAVELING_IN_BEAM "TravelingInBeam", // traveling in space shpi beam + 20 PAA_LOGO_FIRE_MINIGUN "LogoFireMinigun", // fire minigun in logo sequence + 21 PAA_STARTCREDITS "StartCredits", // start credits printout + 22 PAA_STARTINTROSCROLL "StartIntroScroll", // start intro text scroll + 23 PAA_STOPSCROLLER "StopScroller", // stop intro scroll, or end-of-game credits + 24 PAA_NOGRAVITY "NoGravity", // deactivate gravity influence for player + 25 PAA_TURNONGRAVITY "TurnOnGravity", // turn on gravity +}; + +class CPlayerActionMarker: CMarker { +name "PlayerActionMarker"; +thumbnail "Thumbnails\\PlayerActionMarker.tbn"; + +properties: + 1 enum PlayerAutoAction m_paaAction "Action" 'A' = PAA_RUN, // what to do here + 2 FLOAT m_tmWait "Wait" 'W' = 0.0f, // how long to wait (if wait action) + 3 CEntityPointer m_penDoorController "Door for item" 'D', // where to use the item (if use action) + 4 CEntityPointer m_penTrigger "Trigger" 'G', // triggered when player gets here + 5 FLOAT m_fSpeed "Speed" 'S' = 1.0f, // how fast to run towards marker + 6 CEntityPointer m_penItem "Item to pick" 'I', + +components: + 1 model MODEL_MARKER "Models\\Editor\\PlayerActionMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\PlayerActionMarker.tex", + +functions: + const CTString &GetDescription(void) const { + CTString strAction = PlayerAutoAction_enum.NameForValue(INDEX(m_paaAction)); + if (m_penTarget==NULL) { + ((CTString&)m_strDescription).PrintF("%s (%s)->", (const char*)m_strName, (const char*)strAction); + } else { + ((CTString&)m_strDescription).PrintF("%s (%s)->%s", (const char*)m_strName, (const char*)strAction, + (const char*)m_penTarget->GetName()); + } + return m_strDescription; + } + + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\PlayerActionMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + // if triggered + if (ee.ee_slEvent==EVENTCODE_ETrigger) { + ETrigger &eTrigger = (ETrigger &)ee; + // if triggered by a player + if( IsDerivedFromClass(eTrigger.penCaused, "Player")) { + // send it event to start auto actions from here + EAutoAction eAutoAction; + eAutoAction.penFirstMarker = this; + eTrigger.penCaused->SendEvent(eAutoAction); + } + return TRUE; + } + return FALSE; + } + + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + m_tmWait = ClampDn(m_tmWait, 0.05f); + + return; + } +}; + diff --git a/Sources/Entities/PlayerAnimator.es b/Sources/Entities/PlayerAnimator.es new file mode 100644 index 0000000..1ec5529 --- /dev/null +++ b/Sources/Entities/PlayerAnimator.es @@ -0,0 +1,1550 @@ +406 +%{ +#include "Entities/StdH/StdH.h" + +#include "Models/Player/SeriousSam/Player.h" +#include "Models/Player/SeriousSam/Body.h" +#include "Models/Player/SeriousSam/Head.h" + +#include "Models/Weapons/Knife/KnifeItem.h" +#include "Models/Weapons/Colt/ColtItem.h" +#include "Models/Weapons/Colt/ColtMain.h" +#include "Models/Weapons/SingleShotgun/SingleShotgunItem.h" +#include "Models/Weapons/SingleShotgun/Barrels.h" +#include "Models/Weapons/DoubleShotgun/DoubleShotgunItem.h" +#include "Models/Weapons/DoubleShotgun/Dshotgunbarrels.h" +#include "Models/Weapons/TommyGun/TommyGunItem.h" +#include "Models/Weapons/TommyGun/Body.h" +#include "Models/Weapons/MiniGun/MiniGunItem.h" +#include "Models/Weapons/MiniGun/Body.h" +#include "Models/Weapons/GrenadeLauncher/GrenadeLauncherItem.h" +#include "Models/Weapons/RocketLauncher/RocketLauncherItem.h" +//#include "Models/Weapons/Pipebomb/StickItem.h" +//#include "Models/Weapons/Flamer/FlamerItem.h" +#include "Models/Weapons/Laser/LaserItem.h" +//#include "Models/Weapons/GhostBuster/GhostBusterItem.h" +//#include "Models/Weapons/GhostBuster/Effect01.h" +#include "Models/Weapons/Cannon/Cannon.h" +%} + +uses "Entities/Player"; +uses "Entities/PlayerWeapons"; + +// input parameter for animator +event EAnimatorInit { + CEntityPointer penPlayer, // player owns it +}; + +%{ +// animator action +enum AnimatorAction { + AA_JUMPDOWN = 0, + AA_CROUCH, + AA_RISE, + AA_PULLWEAPON, + AA_ATTACK, +}; + +// fire flare specific +#define FLARE_NONE 0 +#define FLARE_REMOVE 1 +#define FLARE_ADD 2 + + +extern FLOAT plr_fBreathingStrength; +extern FLOAT plr_fViewDampFactor; +extern FLOAT plr_fViewDampLimitGroundUp; +extern FLOAT plr_fViewDampLimitGroundDn; +extern FLOAT plr_fViewDampLimitWater; +extern FLOAT wpn_fRecoilSpeed[17]; +extern FLOAT wpn_fRecoilLimit[17]; +extern FLOAT wpn_fRecoilDampUp[17]; +extern FLOAT wpn_fRecoilDampDn[17]; +extern FLOAT wpn_fRecoilOffset[17]; +extern FLOAT wpn_fRecoilFactorP[17]; +extern FLOAT wpn_fRecoilFactorZ[17]; + + +void CPlayerAnimator_Precache(ULONG ulAvailable) +{ + CDLLEntityClass *pdec = &CPlayerAnimator_DLLClass; + + pdec->PrecacheTexture(TEX_REFL_BWRIPLES01 ); + pdec->PrecacheTexture(TEX_REFL_BWRIPLES02 ); + pdec->PrecacheTexture(TEX_REFL_LIGHTMETAL01 ); + pdec->PrecacheTexture(TEX_REFL_LIGHTBLUEMETAL01); + pdec->PrecacheTexture(TEX_REFL_DARKMETAL ); + pdec->PrecacheTexture(TEX_REFL_PURPLE01 ); + pdec->PrecacheTexture(TEX_SPEC_WEAK ); + pdec->PrecacheTexture(TEX_SPEC_MEDIUM ); + pdec->PrecacheTexture(TEX_SPEC_STRONG ); + pdec->PrecacheModel(MODEL_FLARE02); + pdec->PrecacheTexture(TEXTURE_FLARE02); + pdec->PrecacheModel(MODEL_GOLDAMON); + pdec->PrecacheTexture(TEXTURE_GOLDAMON); + pdec->PrecacheTexture(TEX_REFL_GOLD01); + pdec->PrecacheClass(CLASS_REMINDER); + + // precache shells that drop when firing + extern void CPlayerWeaponsEffects_Precache(void); + CPlayerWeaponsEffects_Precache(); + + // precache weapons player has + if ( ulAvailable&(1<<(WEAPON_KNIFE-1)) ) { + pdec->PrecacheModel(MODEL_KNIFE ); + pdec->PrecacheTexture(TEXTURE_KNIFE); + } + + if ( ulAvailable&(1<<(WEAPON_COLT-1)) ) { + pdec->PrecacheModel(MODEL_COLT ); + pdec->PrecacheModel(MODEL_COLTCOCK ); + pdec->PrecacheModel(MODEL_COLTMAIN ); + pdec->PrecacheModel(MODEL_COLTBULLETS ); + pdec->PrecacheTexture(TEXTURE_COLTMAIN ); + pdec->PrecacheTexture(TEXTURE_COLTBULLETS ); + pdec->PrecacheTexture(TEXTURE_COLTBULLETS ); + } + + if ( ulAvailable&(1<<(WEAPON_SINGLESHOTGUN-1)) ) { + pdec->PrecacheModel(MODEL_SINGLESHOTGUN ); + pdec->PrecacheModel(MODEL_SS_SLIDER ); + pdec->PrecacheModel(MODEL_SS_HANDLE ); + pdec->PrecacheModel(MODEL_SS_BARRELS ); + pdec->PrecacheTexture(TEXTURE_SS_HANDLE); + pdec->PrecacheTexture(TEXTURE_SS_BARRELS); + } + + if ( ulAvailable&(1<<(WEAPON_DOUBLESHOTGUN-1)) ) { + pdec->PrecacheModel(MODEL_DOUBLESHOTGUN ); + pdec->PrecacheModel(MODEL_DS_HANDLE ); + pdec->PrecacheModel(MODEL_DS_BARRELS ); + pdec->PrecacheModel(MODEL_DS_SWITCH ); + pdec->PrecacheTexture(TEXTURE_DS_HANDLE ); + pdec->PrecacheTexture(TEXTURE_DS_BARRELS ); + pdec->PrecacheTexture(TEXTURE_DS_SWITCH ); + } + + if ( ulAvailable&(1<<(WEAPON_TOMMYGUN-1)) ) { + pdec->PrecacheModel(MODEL_TOMMYGUN ); + pdec->PrecacheModel(MODEL_TG_BODY ); + pdec->PrecacheModel(MODEL_TG_SLIDER ); + pdec->PrecacheTexture(TEXTURE_TG_BODY ); + } + + if ( ulAvailable&(1<<(WEAPON_MINIGUN-1)) ) { + pdec->PrecacheModel(MODEL_MINIGUN ); + pdec->PrecacheModel(MODEL_MG_BARRELS ); + pdec->PrecacheModel(MODEL_MG_BODY ); + pdec->PrecacheModel(MODEL_MG_ENGINE ); + pdec->PrecacheTexture(TEXTURE_MG_BODY ); + pdec->PrecacheTexture(TEXTURE_MG_BARRELS ); + } + + if ( ulAvailable&(1<<(WEAPON_ROCKETLAUNCHER-1)) ) { + pdec->PrecacheModel(MODEL_ROCKETLAUNCHER ); + pdec->PrecacheModel(MODEL_RL_BODY ); + pdec->PrecacheModel(MODEL_RL_ROTATINGPART ); + pdec->PrecacheModel(MODEL_RL_ROCKET ); + pdec->PrecacheTexture(TEXTURE_RL_BODY ); + pdec->PrecacheTexture(TEXTURE_RL_ROCKET); + pdec->PrecacheTexture(TEXTURE_RL_ROTATINGPART); + } + + if ( ulAvailable&(1<<(WEAPON_GRENADELAUNCHER-1)) ) { + pdec->PrecacheModel(MODEL_GRENADELAUNCHER ); + pdec->PrecacheModel(MODEL_GL_BODY ); + pdec->PrecacheModel(MODEL_GL_MOVINGPART ); + pdec->PrecacheModel(MODEL_GL_GRENADE ); + pdec->PrecacheTexture(TEXTURE_GL_BODY ); + pdec->PrecacheTexture(TEXTURE_GL_MOVINGPART ); + } + +/* + if ( ulAvailable&(1<<(WEAPON_PIPEBOMB-1)) ) { + pdec->PrecacheModel(MODEL_PIPEBOMB_STICK ); + pdec->PrecacheModel(MODEL_PB_BUTTON ); + pdec->PrecacheModel(MODEL_PB_SHIELD ); + pdec->PrecacheModel(MODEL_PB_STICK ); + pdec->PrecacheModel(MODEL_PB_BOMB ); + pdec->PrecacheTexture(TEXTURE_PB_STICK ); + pdec->PrecacheTexture(TEXTURE_PB_BOMB ); + } + + if ( ulAvailable&(1<<(WEAPON_FLAMER-1)) ) { + pdec->PrecacheModel(MODEL_FLAMER ); + pdec->PrecacheModel(MODEL_FL_BODY ); + pdec->PrecacheModel(MODEL_FL_RESERVOIR); + pdec->PrecacheModel(MODEL_FL_FLAME ); + pdec->PrecacheTexture(TEXTURE_FL_BODY ); + pdec->PrecacheTexture(TEXTURE_FL_FLAME); + } + */ + + if ( ulAvailable&(1<<(WEAPON_LASER-1)) ) { + pdec->PrecacheModel(MODEL_LASER ); + pdec->PrecacheModel(MODEL_LS_BODY ); + pdec->PrecacheModel(MODEL_LS_BARREL ); + pdec->PrecacheTexture(TEXTURE_LS_BODY ); + pdec->PrecacheTexture(TEXTURE_LS_BARREL); + } +/* + if ( ulAvailable&(1<<(WEAPON_GHOSTBUSTER-1)) ) { + pdec->PrecacheModel(MODEL_GHOSTBUSTER ); + pdec->PrecacheModel(MODEL_GB_BODY ); + pdec->PrecacheModel(MODEL_GB_ROTATOR ); + pdec->PrecacheModel(MODEL_GB_EFFECT1 ); + pdec->PrecacheModel(MODEL_GB_EFFECT1FLARE ); + pdec->PrecacheTexture(TEXTURE_GB_ROTATOR ); + pdec->PrecacheTexture(TEXTURE_GB_BODY ); + pdec->PrecacheTexture(TEXTURE_GB_LIGHTNING); + pdec->PrecacheTexture(TEXTURE_GB_FLARE ); + } +*/ + if ( ulAvailable&(1<<(WEAPON_IRONCANNON-1)) /*|| + ulAvailable&(1<<(WEAPON_NUKECANNON-1)) */) { + pdec->PrecacheModel(MODEL_CANNON ); + pdec->PrecacheModel(MODEL_CN_BODY ); +// pdec->PrecacheModel(MODEL_CN_NUKEBOX); +// pdec->PrecacheModel(MODEL_CN_LIGHT); + pdec->PrecacheTexture(TEXTURE_CANNON); + } +} +%} + +class export CPlayerAnimator: CRationalEntity { +name "Player Animator"; +thumbnail ""; +features "CanBePredictable"; + +properties: + 1 CEntityPointer m_penPlayer, // player which owns it + + 5 BOOL m_bReference=FALSE, // player has reference (floor) + 6 FLOAT m_fLastActionTime = 0.0f, // last action time for boring weapon animations + 7 INDEX m_iContent = 0, // content type index + 8 BOOL m_bWaitJumpAnim = FALSE, // wait legs anim (for jump end) + 9 BOOL m_bCrouch = FALSE, // player crouch state + 10 BOOL m_iCrouchDownWait = FALSE, // wait for crouch down + 11 BOOL m_iRiseUpWait = FALSE, // wait for rise up + 12 BOOL m_bChangeWeapon = FALSE, // wait for weapon change + 13 BOOL m_bSwim = FALSE, // player in water + 14 INDEX m_iFlare = FLARE_REMOVE, // 0-none, 1-remove, 2-add + 15 INDEX m_iSecondFlare = FLARE_REMOVE, // 0-none, 1-remove, 2-add + 16 BOOL m_bAttacking = FALSE, // currently firing weapon/swinging knife + 19 FLOAT m_tmAttackingDue = -1.0f, // when firing animation is due + 17 FLOAT m_tmFlareAdded = -1.0f, // for better flare add/remove + 18 BOOL m_bDisableAnimating = FALSE, + +// player soft eyes on Y axis + 20 FLOAT3D m_vLastPlayerPosition = FLOAT3D(0,0,0), // last player position for eyes movement + 21 FLOAT m_fEyesYLastOffset = 0.0f, // eyes offset from player position + 22 FLOAT m_fEyesYOffset = 0.0f, + 23 FLOAT m_fEyesYSpeed = 0.0f, // eyes speed + 27 FLOAT m_fWeaponYLastOffset = 0.0f, // eyes offset from player position + 28 FLOAT m_fWeaponYOffset = 0.0f, + 29 FLOAT m_fWeaponYSpeed = 0.0f, // eyes speed + // recoil pitch +// 24 FLOAT m_fRecoilLastOffset = 0.0f, // eyes offset from player position +// 25 FLOAT m_fRecoilOffset = 0.0f, +// 26 FLOAT m_fRecoilSpeed = 0.0f, // eyes speed + +// player banking when moving + 30 BOOL m_bMoving = FALSE, + 31 FLOAT m_fMoveLastBanking = 0.0f, + 32 FLOAT m_fMoveBanking = 0.0f, + 33 BOOL m_iMovingSide = 0, + 34 BOOL m_bSidestepBankingLeft = FALSE, + 35 BOOL m_bSidestepBankingRight = FALSE, + 36 FLOAT m_fSidestepLastBanking = 0.0f, + 37 FLOAT m_fSidestepBanking = 0.0f, + 38 INDEX m_iWeaponLast = -1, + 39 FLOAT m_fBodyAnimTime = -1.0f, + +{ + CModelObject *pmoModel; +} + +components: + 1 class CLASS_REMINDER "Classes\\Reminder.ecl", +// ************** KNIFE ************** + 20 model MODEL_KNIFE "Models\\Weapons\\Knife\\KnifeItem.mdl", + 22 texture TEXTURE_KNIFE "Models\\Weapons\\Knife\\KnifeItem.tex", + +// ************** COLT ************** + 30 model MODEL_COLT "Models\\Weapons\\Colt\\ColtItem.mdl", + 31 model MODEL_COLTCOCK "Models\\Weapons\\Colt\\ColtCock.mdl", + 32 model MODEL_COLTMAIN "Models\\Weapons\\Colt\\ColtMain.mdl", + 33 model MODEL_COLTBULLETS "Models\\Weapons\\Colt\\ColtBullets.mdl", + 34 texture TEXTURE_COLTBULLETS "Models\\Weapons\\Colt\\ColtBullets.tex", + 35 texture TEXTURE_COLTMAIN "Models\\Weapons\\Colt\\ColtMain.tex", + 36 texture TEXTURE_COLTCOCK "Models\\Weapons\\Colt\\ColtCock.tex", + +// ************** SINGLE SHOTGUN ************ + 40 model MODEL_SINGLESHOTGUN "Models\\Weapons\\SingleShotgun\\SingleShotgunItem.mdl", + 41 model MODEL_SS_SLIDER "Models\\Weapons\\SingleShotgun\\Slider.mdl", + 42 model MODEL_SS_HANDLE "Models\\Weapons\\SingleShotgun\\Handle.mdl", + 43 model MODEL_SS_BARRELS "Models\\Weapons\\SingleShotgun\\Barrels.mdl", + 44 texture TEXTURE_SS_HANDLE "Models\\Weapons\\SingleShotgun\\Handle.tex", + 45 texture TEXTURE_SS_BARRELS "Models\\Weapons\\SingleShotgun\\Barrels.tex", + +// ************** DOUBLE SHOTGUN ************** + 50 model MODEL_DOUBLESHOTGUN "Models\\Weapons\\DoubleShotgun\\DoubleShotgunItem.mdl", + 51 model MODEL_DS_HANDLE "Models\\Weapons\\DoubleShotgun\\Dshotgunhandle.mdl", + 52 model MODEL_DS_BARRELS "Models\\Weapons\\DoubleShotgun\\Dshotgunbarrels.mdl", + 54 model MODEL_DS_SWITCH "Models\\Weapons\\DoubleShotgun\\Switch.mdl", + 56 texture TEXTURE_DS_HANDLE "Models\\Weapons\\DoubleShotgun\\Handle.tex", + 57 texture TEXTURE_DS_BARRELS "Models\\Weapons\\DoubleShotgun\\Barrels.tex", + 58 texture TEXTURE_DS_SWITCH "Models\\Weapons\\DoubleShotgun\\Switch.tex", + +// ************** TOMMYGUN ************** + 70 model MODEL_TOMMYGUN "Models\\Weapons\\TommyGun\\TommyGunItem.mdl", + 71 model MODEL_TG_BODY "Models\\Weapons\\TommyGun\\Body.mdl", + 72 model MODEL_TG_SLIDER "Models\\Weapons\\TommyGun\\Slider.mdl", + 73 texture TEXTURE_TG_BODY "Models\\Weapons\\TommyGun\\Body.tex", + +// ************** MINIGUN ************** + 80 model MODEL_MINIGUN "Models\\Weapons\\MiniGun\\MiniGunItem.mdl", + 81 model MODEL_MG_BARRELS "Models\\Weapons\\MiniGun\\Barrels.mdl", + 82 model MODEL_MG_BODY "Models\\Weapons\\MiniGun\\Body.mdl", + 83 model MODEL_MG_ENGINE "Models\\Weapons\\MiniGun\\Engine.mdl", + 84 texture TEXTURE_MG_BODY "Models\\Weapons\\MiniGun\\Body.tex", + 99 texture TEXTURE_MG_BARRELS "Models\\Weapons\\MiniGun\\Barrels.tex", + +// ************** ROCKET LAUNCHER ************** + 90 model MODEL_ROCKETLAUNCHER "Models\\Weapons\\RocketLauncher\\RocketLauncherItem.mdl", + 91 model MODEL_RL_BODY "Models\\Weapons\\RocketLauncher\\Body.mdl", + 92 texture TEXTURE_RL_BODY "Models\\Weapons\\RocketLauncher\\Body.tex", + 93 model MODEL_RL_ROTATINGPART "Models\\Weapons\\RocketLauncher\\RotatingPart.mdl", + 94 texture TEXTURE_RL_ROTATINGPART "Models\\Weapons\\RocketLauncher\\RotatingPart.tex", + 95 model MODEL_RL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.mdl", + 96 texture TEXTURE_RL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.tex", + +// ************** GRENADE LAUNCHER ************** +100 model MODEL_GRENADELAUNCHER "Models\\Weapons\\GrenadeLauncher\\GrenadeLauncherItem.mdl", +101 model MODEL_GL_BODY "Models\\Weapons\\GrenadeLauncher\\Body.mdl", +102 model MODEL_GL_MOVINGPART "Models\\Weapons\\GrenadeLauncher\\MovingPipe.mdl", +103 model MODEL_GL_GRENADE "Models\\Weapons\\GrenadeLauncher\\GrenadeBack.mdl", +104 texture TEXTURE_GL_BODY "Models\\Weapons\\GrenadeLauncher\\Body.tex", +105 texture TEXTURE_GL_MOVINGPART "Models\\Weapons\\GrenadeLauncher\\MovingPipe.tex", + +/* +// ************** PIPEBOMB ************** +110 model MODEL_PIPEBOMB_STICK "Models\\Weapons\\Pipebomb\\StickItem.mdl", +112 model MODEL_PB_BUTTON "Models\\Weapons\\Pipebomb\\Button.mdl", +113 model MODEL_PB_SHIELD "Models\\Weapons\\Pipebomb\\Shield.mdl", +114 model MODEL_PB_STICK "Models\\Weapons\\Pipebomb\\Stick.mdl", +115 model MODEL_PB_BOMB "Models\\Weapons\\Pipebomb\\Bomb.mdl", +116 texture TEXTURE_PB_STICK "Models\\Weapons\\Pipebomb\\Stick.tex", +117 texture TEXTURE_PB_BOMB "Models\\Weapons\\Pipebomb\\Bomb.tex", +*/ +/* +// ************** FLAMER ************** +130 model MODEL_FLAMER "Models\\Weapons\\Flamer\\FlamerItem.mdl", +131 model MODEL_FL_BODY "Models\\Weapons\\Flamer\\Body.mdl", +132 model MODEL_FL_RESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.mdl", +133 model MODEL_FL_FLAME "Models\\Weapons\\Flamer\\Flame.mdl", +134 texture TEXTURE_FL_BODY "Models\\Weapons\\Flamer\\Body.tex", +135 texture TEXTURE_FL_FLAME "Models\\Weapons\\Flamer\\Flame.tex", +136 texture TEXTURE_FL_FUELRESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.tex", +*/ +// ************** LASER ************** +140 model MODEL_LASER "Models\\Weapons\\Laser\\LaserItem.mdl", +141 model MODEL_LS_BODY "Models\\Weapons\\Laser\\Body.mdl", +142 model MODEL_LS_BARREL "Models\\Weapons\\Laser\\Barrel.mdl", +143 texture TEXTURE_LS_BODY "Models\\Weapons\\Laser\\Body.tex", +144 texture TEXTURE_LS_BARREL "Models\\Weapons\\Laser\\Barrel.tex", + +// ************** GHOSTBUSTER ************** +/* +150 model MODEL_GHOSTBUSTER "Models\\Weapons\\GhostBuster\\GhostBusterItem.mdl", +151 model MODEL_GB_BODY "Models\\Weapons\\GhostBuster\\Body.mdl", +152 model MODEL_GB_ROTATOR "Models\\Weapons\\GhostBuster\\Rotator.mdl", +153 model MODEL_GB_EFFECT1 "Models\\Weapons\\GhostBuster\\Effect01.mdl", +154 model MODEL_GB_EFFECT1FLARE "Models\\Weapons\\GhostBuster\\EffectFlare01.mdl", +155 texture TEXTURE_GB_ROTATOR "Models\\Weapons\\GhostBuster\\Rotator.tex", +156 texture TEXTURE_GB_BODY "Models\\Weapons\\GhostBuster\\Body.tex", +157 texture TEXTURE_GB_LIGHTNING "Models\\Weapons\\GhostBuster\\Lightning.tex", +158 texture TEXTURE_GB_FLARE "Models\\Weapons\\GhostBuster\\EffectFlare.tex", +*/ +// ************** CANNON ************** +170 model MODEL_CANNON "Models\\Weapons\\Cannon\\Cannon.mdl", +171 model MODEL_CN_BODY "Models\\Weapons\\Cannon\\Body.mdl", +173 texture TEXTURE_CANNON "Models\\Weapons\\Cannon\\Body.tex", +//174 model MODEL_CN_NUKEBOX "Models\\Weapons\\Cannon\\NukeBox.mdl", +//175 model MODEL_CN_LIGHT "Models\\Weapons\\Cannon\\Light.mdl", + +// ************** AMON STATUE ************** +180 model MODEL_GOLDAMON "Models\\Ages\\Egypt\\Gods\\Amon\\AmonGold.mdl", +181 texture TEXTURE_GOLDAMON "Models\\Ages\\Egypt\\Gods\\Amon\\AmonGold.tex", + +// ************** REFLECTIONS ************** +200 texture TEX_REFL_BWRIPLES01 "Models\\ReflectionTextures\\BWRiples01.tex", +201 texture TEX_REFL_BWRIPLES02 "Models\\ReflectionTextures\\BWRiples02.tex", +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", +203 texture TEX_REFL_LIGHTBLUEMETAL01 "Models\\ReflectionTextures\\LightBlueMetal01.tex", +204 texture TEX_REFL_DARKMETAL "Models\\ReflectionTextures\\DarkMetal.tex", +205 texture TEX_REFL_PURPLE01 "Models\\ReflectionTextures\\Purple01.tex", +206 texture TEX_REFL_GOLD01 "Models\\ReflectionTextures\\Gold01.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + +// ************** FLARES ************** +250 model MODEL_FLARE02 "Models\\Effects\\Weapons\\Flare02\\Flare.mdl", +251 texture TEXTURE_FLARE02 "Models\\Effects\\Weapons\\Flare02\\Flare.tex", + + +functions: + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CRationalEntity::Read_t(istr); + } + + void Precache(void) + { + INDEX iAvailableWeapons = ((CPlayerWeapons&)*(((CPlayer&)*m_penPlayer).m_penWeapons)).m_iAvailableWeapons; + CPlayerAnimator_Precache(iAvailableWeapons); + } + + CPlayer *GetPlayer(void) + { + return ((CPlayer*)&*m_penPlayer); + } + CModelObject *GetBody(void) + { + CAttachmentModelObject *pamoBody = GetPlayer()->GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO); + if (pamoBody==NULL) { + return NULL; + } + return &pamoBody->amo_moModelObject; + } + CModelObject *GetBodyRen(void) + { + CAttachmentModelObject *pamoBody = GetPlayer()->m_moRender.GetAttachmentModel(PLAYER_ATTACHMENT_TORSO); + if (pamoBody==NULL) { + return NULL; + } + return &pamoBody->amo_moModelObject; + } + + // Set components + void SetComponents(CModelObject *mo, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) { + // model data + mo->SetData(GetModelDataForComponent(ulIDModel)); + // texture data + mo->mo_toTexture.SetData(GetTextureDataForComponent(ulIDTexture)); + // reflection texture data + if (ulIDReflectionTexture>0) { + mo->mo_toReflection.SetData(GetTextureDataForComponent(ulIDReflectionTexture)); + } else { + mo->mo_toReflection.SetData(NULL); + } + // specular texture data + if (ulIDSpecularTexture>0) { + mo->mo_toSpecular.SetData(GetTextureDataForComponent(ulIDSpecularTexture)); + } else { + mo->mo_toSpecular.SetData(NULL); + } + // bump texture data + if (ulIDBumpTexture>0) { + mo->mo_toBump.SetData(GetTextureDataForComponent(ulIDBumpTexture)); + } else { + mo->mo_toBump.SetData(NULL); + } + ModelChangeNotify(); + }; + + // Add attachment model + void AddAttachmentModel(CModelObject *mo, INDEX iAttachment, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) { + SetComponents(&mo->AddAttachmentModel(iAttachment)->amo_moModelObject, ulIDModel, + ulIDTexture, ulIDReflectionTexture, ulIDSpecularTexture, ulIDBumpTexture); + }; + + // Add weapon attachment + void AddWeaponAttachment(INDEX iAttachment, ULONG ulIDModel, ULONG ulIDTexture, + ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) { + AddAttachmentModel(pmoModel, iAttachment, ulIDModel, ulIDTexture, + ulIDReflectionTexture, ulIDSpecularTexture, ulIDBumpTexture); + }; + + // set active attachment (model) + void SetAttachment(INDEX iAttachment) { + pmoModel = &(pmoModel->GetAttachmentModel(iAttachment)->amo_moModelObject); + }; + + // synchronize any possible weapon attachment(s) with default appearance + void SyncWeapon(void) + { + CModelObject *pmoBodyRen = GetBodyRen(); + CModelObject *pmoBodyDef = GetBody(); + // for each weapon attachment + for (INDEX iWeapon = BODY_ATTACHMENT_COLT_RIGHT; iWeapon<=BODY_ATTACHMENT_ITEM; iWeapon++) { + CAttachmentModelObject *pamoWeapDef = pmoBodyDef->GetAttachmentModel(iWeapon); + CAttachmentModelObject *pamoWeapRen = pmoBodyRen->GetAttachmentModel(iWeapon); + // if it doesn't exist in either + if (pamoWeapRen==NULL && pamoWeapDef==NULL) { + // just skip it + NOTHING; + + // if exists only in rendering model + } else if (pamoWeapRen!=NULL && pamoWeapDef==NULL) { + // remove it from rendering + delete pamoWeapRen; + + // if exists only in default + } else if (pamoWeapRen==NULL && pamoWeapDef!=NULL) { + // add it to rendering + pamoWeapRen = pmoBodyRen->AddAttachmentModel(iWeapon); + pamoWeapRen->amo_plRelative = pamoWeapDef->amo_plRelative; + pamoWeapRen->amo_moModelObject.Copy(pamoWeapDef->amo_moModelObject); + + // if exists in both + } else { + // just synchronize + pamoWeapRen->amo_plRelative = pamoWeapDef->amo_plRelative; + pamoWeapRen->amo_moModelObject.Synchronize(pamoWeapDef->amo_moModelObject); + } + } + } + + // set weapon + void SetWeapon(void) { + INDEX iWeapon = ((CPlayerWeapons&)*(((CPlayer&)*m_penPlayer).m_penWeapons)).m_iCurrentWeapon; + m_iWeaponLast = iWeapon; + CPlayer &pl = (CPlayer&)*m_penPlayer; + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + switch (iWeapon) { + // *********** KNIFE *********** + case WEAPON_KNIFE: + AddWeaponAttachment(BODY_ATTACHMENT_KNIFE, MODEL_KNIFE, + TEXTURE_KNIFE, TEX_REFL_BWRIPLES02, TEX_SPEC_WEAK, 0); + break; + + // *********** DOUBLE COLT *********** + case WEAPON_DOUBLECOLT: + AddWeaponAttachment(BODY_ATTACHMENT_COLT_LEFT, MODEL_COLT, TEXTURE_COLTMAIN, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_COLT_LEFT); + AddWeaponAttachment(COLTITEM_ATTACHMENT_BULLETS, MODEL_COLTBULLETS, + TEXTURE_COLTBULLETS, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(COLTITEM_ATTACHMENT_COCK, MODEL_COLTCOCK, + TEXTURE_COLTCOCK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(COLTITEM_ATTACHMENT_BODY, MODEL_COLTMAIN, + TEXTURE_COLTMAIN, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + SetAttachment(COLTITEM_ATTACHMENT_BODY); + AddWeaponAttachment(COLTMAIN_ATTACHMENT_FLARE, MODEL_FLARE02, TEXTURE_FLARE02, 0, 0, 0); + // reset to player body + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + + // *********** COLT *********** + case WEAPON_COLT: + AddWeaponAttachment(BODY_ATTACHMENT_COLT_RIGHT, MODEL_COLT, TEXTURE_COLTMAIN, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_COLT_RIGHT); + AddWeaponAttachment(COLTITEM_ATTACHMENT_BULLETS, MODEL_COLTBULLETS, + TEXTURE_COLTBULLETS, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(COLTITEM_ATTACHMENT_COCK, MODEL_COLTCOCK, + TEXTURE_COLTCOCK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(COLTITEM_ATTACHMENT_BODY, MODEL_COLTMAIN, + TEXTURE_COLTMAIN, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + SetAttachment(COLTITEM_ATTACHMENT_BODY); + AddWeaponAttachment(COLTMAIN_ATTACHMENT_FLARE, MODEL_FLARE02, TEXTURE_FLARE02, 0, 0, 0); + break; + + // *********** SINGLE SHOTGUN *********** + case WEAPON_SINGLESHOTGUN: + AddWeaponAttachment(BODY_ATTACHMENT_SINGLE_SHOTGUN, MODEL_SINGLESHOTGUN, TEXTURE_SS_HANDLE, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_SINGLE_SHOTGUN); + AddWeaponAttachment(SINGLESHOTGUNITEM_ATTACHMENT_BARRELS, MODEL_SS_BARRELS, + TEXTURE_SS_BARRELS, TEX_REFL_DARKMETAL, TEX_SPEC_WEAK, 0); + AddWeaponAttachment(SINGLESHOTGUNITEM_ATTACHMENT_HANDLE, MODEL_SS_HANDLE, + TEXTURE_SS_HANDLE, TEX_REFL_DARKMETAL, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(SINGLESHOTGUNITEM_ATTACHMENT_SLIDER, MODEL_SS_SLIDER, + TEXTURE_SS_BARRELS, TEX_REFL_DARKMETAL, TEX_SPEC_MEDIUM, 0); + SetAttachment(SINGLESHOTGUNITEM_ATTACHMENT_BARRELS); + AddWeaponAttachment(BARRELS_ATTACHMENT_FLARE, MODEL_FLARE02, TEXTURE_FLARE02, 0, 0, 0); + break; + + // *********** DOUBLE SHOTGUN *********** + case WEAPON_DOUBLESHOTGUN: + AddWeaponAttachment(BODY_ATTACHMENT_DOUBLE_SHOTGUN, MODEL_DOUBLESHOTGUN, TEXTURE_DS_HANDLE, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_DOUBLE_SHOTGUN); + AddWeaponAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_BARRELS, MODEL_DS_BARRELS, + TEXTURE_DS_BARRELS, TEX_REFL_BWRIPLES01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_HANDLE, MODEL_DS_HANDLE, + TEXTURE_DS_HANDLE, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_SWITCH, MODEL_DS_SWITCH, + TEXTURE_DS_SWITCH, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + SetAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_BARRELS); + AddWeaponAttachment(DSHOTGUNBARRELS_ATTACHMENT_FLARE, MODEL_FLARE02, TEXTURE_FLARE02, 0, 0, 0); + break; + + + // *********** TOMMYGUN *********** + case WEAPON_TOMMYGUN: + AddWeaponAttachment(BODY_ATTACHMENT_TOMMYGUN, MODEL_TOMMYGUN, TEXTURE_TG_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_TOMMYGUN); + AddWeaponAttachment(TOMMYGUNITEM_ATTACHMENT_BODY, MODEL_TG_BODY, TEXTURE_TG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(TOMMYGUNITEM_ATTACHMENT_SLIDER, MODEL_TG_SLIDER, TEXTURE_TG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + SetAttachment(TOMMYGUNITEM_ATTACHMENT_BODY); + AddWeaponAttachment(BODY_ATTACHMENT_FLARE, MODEL_FLARE02, TEXTURE_FLARE02, 0, 0, 0); + break; + + // *********** MINIGUN *********** + case WEAPON_MINIGUN: + AddWeaponAttachment(BODY_ATTACHMENT_MINIGUN, MODEL_MINIGUN, TEXTURE_MG_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_MINIGUN); + AddWeaponAttachment(MINIGUNITEM_ATTACHMENT_BARRELS, MODEL_MG_BARRELS, TEXTURE_MG_BARRELS, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(MINIGUNITEM_ATTACHMENT_BODY, MODEL_MG_BODY, TEXTURE_MG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(MINIGUNITEM_ATTACHMENT_ENGINE, MODEL_MG_ENGINE, TEXTURE_MG_BARRELS, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + SetAttachment(MINIGUNITEM_ATTACHMENT_BODY); + AddWeaponAttachment(BODY_ATTACHMENT_FLARE, MODEL_FLARE02, TEXTURE_FLARE02, 0, 0, 0); + break; + + // *********** ROCKET LAUNCHER *********** + case WEAPON_ROCKETLAUNCHER: + AddWeaponAttachment(BODY_ATTACHMENT_ROCKET_LAUNCHER, MODEL_ROCKETLAUNCHER, TEXTURE_RL_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_ROCKET_LAUNCHER); + AddWeaponAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_BODY, MODEL_RL_BODY, TEXTURE_RL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROTATINGPART, MODEL_RL_ROTATINGPART, TEXTURE_RL_ROTATINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET1, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET2, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET3, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET4, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; + + // *********** GRENADE LAUNCHER *********** + case WEAPON_GRENADELAUNCHER: + AddWeaponAttachment(BODY_ATTACHMENT_GRENADE_LAUNCHER, MODEL_GRENADELAUNCHER, TEXTURE_GL_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_GRENADE_LAUNCHER); + AddWeaponAttachment(GRENADELAUNCHERITEM_ATTACHMENT_BODY, MODEL_GL_BODY, TEXTURE_GL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(GRENADELAUNCHERITEM_ATTACHMENT_MOVING_PART, MODEL_GL_MOVINGPART, TEXTURE_GL_MOVINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(GRENADELAUNCHERITEM_ATTACHMENT_GRENADE, MODEL_GL_GRENADE, TEXTURE_GL_MOVINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; + +/* // *********** PIPEBOMB *********** + case WEAPON_PIPEBOMB: + AddWeaponAttachment(BODY_ATTACHMENT_COLT_RIGHT, MODEL_PIPEBOMB_STICK, TEXTURE_PB_STICK, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_COLT_RIGHT); + AddWeaponAttachment(STICKITEM_ATTACHMENT_STICK, MODEL_PB_STICK, TEXTURE_PB_STICK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(STICKITEM_ATTACHMENT_SHIELD, MODEL_PB_SHIELD, TEXTURE_PB_STICK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(STICKITEM_ATTACHMENT_BUTTON, MODEL_PB_BUTTON, TEXTURE_PB_STICK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + // reset to player body + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + AddWeaponAttachment(BODY_ATTACHMENT_COLT_LEFT, MODEL_PB_BOMB, TEXTURE_PB_BOMB, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + break; + + // *********** FLAMER *********** + case WEAPON_FLAMER: + AddWeaponAttachment(BODY_ATTACHMENT_FLAMER, MODEL_FLAMER, TEXTURE_FL_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_FLAMER); + AddWeaponAttachment(FLAMERITEM_ATTACHMENT_BODY, MODEL_FL_BODY, TEXTURE_FL_BODY, TEX_REFL_BWRIPLES02, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(FLAMERITEM_ATTACHMENT_FUEL, MODEL_FL_RESERVOIR, TEXTURE_FL_FUELRESERVOIR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(FLAMERITEM_ATTACHMENT_FLAME, MODEL_FL_FLAME, TEXTURE_FL_FLAME, 0, 0, 0); + break; +*/ + // *********** LASER *********** + case WEAPON_LASER: + AddWeaponAttachment(BODY_ATTACHMENT_LASER, MODEL_LASER, TEXTURE_LS_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_LASER); + AddWeaponAttachment(LASERITEM_ATTACHMENT_BODY, MODEL_LS_BODY, TEXTURE_LS_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(LASERITEM_ATTACHMENT_LEFTUP, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(LASERITEM_ATTACHMENT_LEFTDOWN, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(LASERITEM_ATTACHMENT_RIGHTUP, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(LASERITEM_ATTACHMENT_RIGHTDOWN, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; + +/* + // *********** GHOSTBUSTER *********** + case WEAPON_GHOSTBUSTER: { + AddWeaponAttachment(BODY_ATTACHMENT_LASER, MODEL_GHOSTBUSTER, TEXTURE_GB_BODY, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_LASER); + AddWeaponAttachment(GHOSTBUSTERITEM_ATTACHMENT_BODY, MODEL_GB_BODY, TEXTURE_GB_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(GHOSTBUSTERITEM_ATTACHMENT_ROTATOR, MODEL_GB_ROTATOR, TEXTURE_GB_ROTATOR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddWeaponAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT01, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddWeaponAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT02, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddWeaponAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT03, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddWeaponAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT04, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + CModelObject *pmo = pmoModel; + SetAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT01); + AddWeaponAttachment(EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmoModel = pmo; + SetAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT02); + AddWeaponAttachment(EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmoModel = pmo; + SetAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT03); + AddWeaponAttachment(EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmoModel = pmo; + SetAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT04); + AddWeaponAttachment(EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + break; } +*/ + // *********** CANNON *********** + case WEAPON_IRONCANNON: +// case WEAPON_NUKECANNON: + AddWeaponAttachment(BODY_ATTACHMENT_CANNON, MODEL_CANNON, TEXTURE_CANNON, 0, 0, 0); + SetAttachment(BODY_ATTACHMENT_CANNON); + AddWeaponAttachment(CANNON_ATTACHMENT_BODY, MODEL_CN_BODY, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); +// AddWeaponAttachment(CANNON_ATTACHMENT_NUKEBOX, MODEL_CN_NUKEBOX, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); +// AddWeaponAttachment(CANNON_ATTACHMENT_LIGHT, MODEL_CN_LIGHT, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; + } + // sync apperances + SyncWeapon(); + }; + + // set item + void SetItem(CModelObject *pmo) { + pmoModel = &(GetPlayer()->GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + AddWeaponAttachment(BODY_ATTACHMENT_ITEM, MODEL_GOLDAMON, + TEXTURE_GOLDAMON, TEX_REFL_GOLD01, TEX_SPEC_MEDIUM, 0); + if (pmo!=NULL) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + CAttachmentModelObject *pamo = pl.GetModelObject()->GetAttachmentModelList(PLAYER_ATTACHMENT_TORSO, BODY_ATTACHMENT_ITEM, -1); + pmoModel = &(pamo->amo_moModelObject); + pmoModel->Copy(*pmo); + pmoModel->StretchModel(FLOAT3D(1,1,1)); + pamo->amo_plRelative = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0)); + } + // sync apperances + SyncWeapon(); + } + + // set player body animation + void SetBodyAnimation(INDEX iAnimation, ULONG ulFlags) { + // on weapon change skip anim + if (m_bChangeWeapon) { return; } + // on firing skip anim + if (m_bAttacking) { return; } + // play body anim + CPlayer &pl = (CPlayer&)*m_penPlayer; + CModelObject &moBody = pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject; + moBody.PlayAnim(iAnimation, ulFlags); + m_fBodyAnimTime = moBody.GetAnimLength(iAnimation); // anim length + }; + + +/************************************************************ + * INITIALIZE * + ************************************************************/ + void Initialize(void) { + // set internal properties + m_bReference = TRUE; + m_bWaitJumpAnim = FALSE; + m_bCrouch = FALSE; + m_iCrouchDownWait = 0; + m_iRiseUpWait = 0; + m_bChangeWeapon = FALSE; + m_bSwim = FALSE; + m_bAttacking = FALSE; + + // clear eyes offsets + m_fEyesYLastOffset = 0.0f; + m_fEyesYOffset = 0.0f; + m_fEyesYSpeed = 0.0f; + m_fWeaponYLastOffset = 0.0f; + m_fWeaponYOffset = 0.0f; + m_fWeaponYSpeed = 0.0f; +// m_fRecoilLastOffset = 0.0f; +// m_fRecoilOffset = 0.0f; +// m_fRecoilSpeed = 0.0f; + + // clear moving banking + m_bMoving = FALSE; + m_fMoveLastBanking = 0.0f; + m_fMoveBanking = 0.0f; + m_iMovingSide = 0; + m_bSidestepBankingLeft = FALSE; + m_bSidestepBankingRight = FALSE; + m_fSidestepLastBanking = 0.0f; + m_fSidestepBanking = 0.0f; + + // weapon + SetWeapon(); + SetBodyAnimation(BODY_ANIM_COLT_STAND, AOF_LOOPING|AOF_NORESTART); + }; + + +/************************************************************ + * ANIMATE BANKING AND SOFT EYES * + ************************************************************/ + // store for lerping + void StoreLast(void) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + m_vLastPlayerPosition = pl.GetPlacement().pl_PositionVector; // store last player position + m_fEyesYLastOffset = m_fEyesYOffset; // store last eyes offset + m_fWeaponYLastOffset = m_fWeaponYOffset; +// m_fRecoilLastOffset = m_fRecoilOffset; + m_fMoveLastBanking = m_fMoveBanking; // store last banking for lerping + m_fSidestepLastBanking = m_fSidestepBanking; + }; + + // animate banking + void AnimateBanking(void) { + // moving -> change banking + if (m_bMoving) { + // move banking left + if (m_iMovingSide == 0) { + m_fMoveBanking += 0.35f; + if (m_fMoveBanking > 1.0f) { + m_fMoveBanking = 1.0f; + m_iMovingSide = 1; + } + // move banking right + } else { + m_fMoveBanking -= 0.35f; + if (m_fMoveBanking < -1.0f) { + m_fMoveBanking = -1.0f; + m_iMovingSide = 0; + } + } + const FLOAT fBankingSpeed = 0.4f; + + // sidestep banking left + if (m_bSidestepBankingLeft) { + m_fSidestepBanking += fBankingSpeed; + if (m_fSidestepBanking > 1.0f) { m_fSidestepBanking = 1.0f; } + } + // sidestep banking right + if (m_bSidestepBankingRight) { + m_fSidestepBanking -= fBankingSpeed; + if (m_fSidestepBanking < -1.0f) { m_fSidestepBanking = -1.0f; } + } + + // restore banking + } else { + // move banking + if (m_fMoveBanking > 0.0f) { + m_fMoveBanking -= 0.1f; + if (m_fMoveBanking < 0.0f) { m_fMoveBanking = 0.0f; } + } else if (m_fMoveBanking < 0.0f) { + m_fMoveBanking += 0.1f; + if (m_fMoveBanking > 0.0f) { m_fMoveBanking = 0.0f; } + } + // sidestep banking + if (m_fSidestepBanking > 0.0f) { + m_fSidestepBanking -= 0.4f; + if (m_fSidestepBanking < 0.0f) { m_fSidestepBanking = 0.0f; } + } else if (m_fSidestepBanking < 0.0f) { + m_fSidestepBanking += 0.4f; + if (m_fSidestepBanking > 0.0f) { m_fSidestepBanking = 0.0f; } + } + } + + if (GetPlayer()->GetSettings()->ps_ulFlags&PSF_NOBOBBING) { + m_fSidestepBanking = m_fMoveBanking = 0.0f; + } + }; + + // animate soft eyes + void AnimateSoftEyes(void) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + // find eyes offset and speed (differential formula realized in numerical mathematics) + FLOAT fRelY = (pl.GetPlacement().pl_PositionVector-m_vLastPlayerPosition) % + FLOAT3D(pl.en_mRotation(1, 2), pl.en_mRotation(2, 2), pl.en_mRotation(3, 2)); + + // if just jumped + if (pl.en_tmJumped>_pTimer->CurrentTick()-0.5f) { + fRelY = ClampUp(fRelY, 0.0f); + } + m_fEyesYOffset -= fRelY; + m_fWeaponYOffset -= ClampUp(fRelY, 0.0f); + + plr_fViewDampFactor = Clamp(plr_fViewDampFactor ,0.0f,1.0f); + plr_fViewDampLimitGroundUp = Clamp(plr_fViewDampLimitGroundUp ,0.0f,2.0f); + plr_fViewDampLimitGroundDn = Clamp(plr_fViewDampLimitGroundDn ,0.0f,2.0f); + plr_fViewDampLimitWater = Clamp(plr_fViewDampLimitWater ,0.0f,2.0f); + + m_fEyesYSpeed = (m_fEyesYSpeed - m_fEyesYOffset*plr_fViewDampFactor) * (1.0f-plr_fViewDampFactor); + m_fEyesYOffset += m_fEyesYSpeed; + + m_fWeaponYSpeed = (m_fWeaponYSpeed - m_fWeaponYOffset*plr_fViewDampFactor) * (1.0f-plr_fViewDampFactor); + m_fWeaponYOffset += m_fWeaponYSpeed; + + if (m_bSwim) { + m_fEyesYOffset = Clamp(m_fEyesYOffset, -plr_fViewDampLimitWater, +plr_fViewDampLimitWater); + m_fWeaponYOffset = Clamp(m_fWeaponYOffset, -plr_fViewDampLimitWater, +plr_fViewDampLimitWater); + } else { + m_fEyesYOffset = Clamp(m_fEyesYOffset, -plr_fViewDampLimitGroundDn, +plr_fViewDampLimitGroundUp); + m_fWeaponYOffset = Clamp(m_fWeaponYOffset, -plr_fViewDampLimitGroundDn, +plr_fViewDampLimitGroundUp); + } + }; + + /* + // animate view pitch (for recoil) + void AnimateRecoilPitch(void) + { + CPlayer &pl = (CPlayer&)*m_penPlayer; + INDEX iWeapon = ((CPlayerWeapons&)*pl.m_penWeapons).m_iCurrentWeapon; + + wpn_fRecoilDampUp[iWeapon] = Clamp(wpn_fRecoilDampUp[iWeapon],0.0f,1.0f); + wpn_fRecoilDampDn[iWeapon] = Clamp(wpn_fRecoilDampDn[iWeapon],0.0f,1.0f); + + FLOAT fDamp; + if (m_fRecoilSpeed>0) { + fDamp = wpn_fRecoilDampUp[iWeapon]; + } else { + fDamp = wpn_fRecoilDampDn[iWeapon]; + } + m_fRecoilSpeed = (m_fRecoilSpeed - m_fRecoilOffset*fDamp)* (1.0f-fDamp); + + m_fRecoilOffset += m_fRecoilSpeed; + + if (m_fRecoilOffset<0.0f) { + m_fRecoilOffset = 0.0f; + } + if (m_fRecoilOffset>wpn_fRecoilLimit[iWeapon]) { + m_fRecoilOffset = wpn_fRecoilLimit[iWeapon]; + m_fRecoilSpeed = 0.0f; + } + }; + */ + // change view + void ChangeView(CPlacement3D &pl) { + TIME tmNow = _pTimer->GetLerpedCurrentTick(); + + if (!(GetPlayer()->GetSettings()->ps_ulFlags&PSF_NOBOBBING)) { + // banking + FLOAT fBanking = Lerp(m_fMoveLastBanking, m_fMoveBanking, _pTimer->GetLerpFactor()); + fBanking = fBanking * fBanking * Sgn(fBanking) * 0.25f; + fBanking += Lerp(m_fSidestepLastBanking, m_fSidestepBanking, _pTimer->GetLerpFactor()); + fBanking = Clamp(fBanking, -5.0f, 5.0f); + pl.pl_OrientationAngle(3) += fBanking; + } + +/* + // recoil pitch + INDEX iWeapon = ((CPlayerWeapons&)*((CPlayer&)*m_penPlayer).m_penWeapons).m_iCurrentWeapon; + FLOAT fRecoil = Lerp(m_fRecoilLastOffset, m_fRecoilOffset, _pTimer->GetLerpFactor()); + FLOAT fRecoilP = wpn_fRecoilFactorP[iWeapon]*fRecoil; + pl.pl_OrientationAngle(2) += fRecoilP; + // adjust recoil pitch handle + FLOAT fRecoilH = wpn_fRecoilOffset[iWeapon]; + FLOAT fDY = fRecoilH*(1.0f-Cos(fRecoilP)); + FLOAT fDZ = fRecoilH*Sin(fRecoilP); + pl.pl_PositionVector(2)-=fDY; + pl.pl_PositionVector(3)+=fDZ+wpn_fRecoilFactorZ[iWeapon]*fRecoil; + */ + + // swimming + if (m_bSwim) { + pl.pl_OrientationAngle(1) += sin(tmNow*0.9)*2.0f; + pl.pl_OrientationAngle(2) += sin(tmNow*1.7)*2.0f; + pl.pl_OrientationAngle(3) += sin(tmNow*2.5)*2.0f; + } + // eyes up/down for jumping and breathing + FLOAT fEyesOffsetY = Lerp(m_fEyesYLastOffset, m_fEyesYOffset, _pTimer->GetLerpFactor()); + fEyesOffsetY+= sin(tmNow*1.5)*0.05f * plr_fBreathingStrength; + fEyesOffsetY = Clamp(fEyesOffsetY, -1.0f, 1.0f); + pl.pl_PositionVector(2) += fEyesOffsetY; + } + + + +/************************************************************ + * ANIMATE PLAYER * + ************************************************************/ + // body and head animation + void BodyAndHeadOrientation(CPlacement3D &plView) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + CAttachmentModelObject *pamoBody = pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO); + ANGLE3D a = plView.pl_OrientationAngle; + if (!(pl.GetFlags()&ENF_ALIVE)) { + a = ANGLE3D(0,0,0); + } + pamoBody->amo_plRelative.pl_OrientationAngle = a; + pamoBody->amo_plRelative.pl_OrientationAngle(3) *= 4.0f; + + CAttachmentModelObject *pamoHead = (pamoBody->amo_moModelObject).GetAttachmentModel(BODY_ATTACHMENT_HEAD); + pamoHead->amo_plRelative.pl_OrientationAngle = a; + pamoHead->amo_plRelative.pl_OrientationAngle(1) = 0.0f; + pamoHead->amo_plRelative.pl_OrientationAngle(2) = 0.0f; + pamoHead->amo_plRelative.pl_OrientationAngle(3) *= 4.0f; + + // forbid players from cheating by kissing their @$$ + const FLOAT fMaxBanking = 5.0f; + pamoBody->amo_plRelative.pl_OrientationAngle(3) = Clamp(pamoBody->amo_plRelative.pl_OrientationAngle(3), -fMaxBanking, fMaxBanking); + pamoHead->amo_plRelative.pl_OrientationAngle(3) = Clamp(pamoHead->amo_plRelative.pl_OrientationAngle(3), -fMaxBanking, fMaxBanking); + }; + + // animate player + void AnimatePlayer(void) { + if (m_bDisableAnimating) { + return; + } + CPlayer &pl = (CPlayer&)*m_penPlayer; + + FLOAT3D vDesiredTranslation = pl.en_vDesiredTranslationRelative; + FLOAT3D vCurrentTranslation = pl.en_vCurrentTranslationAbsolute * !pl.en_mRotation; + ANGLE3D aDesiredRotation = pl.en_aDesiredRotationRelative; + ANGLE3D aCurrentRotation = pl.en_aCurrentRotationAbsolute; + + // if player is moving + if (vDesiredTranslation.ManhattanNorm()>0.01f + ||aDesiredRotation.ManhattanNorm()>0.01f) { + // prevent idle weapon animations + m_fLastActionTime = _pTimer->CurrentTick(); + } + + // swimming + if (m_bSwim) { + if (vDesiredTranslation.Length()>1.0f && vCurrentTranslation.Length()>1.0f) { + pl.StartModelAnim(PLAYER_ANIM_SWIM, AOF_LOOPING|AOF_NORESTART); + } else { + pl.StartModelAnim(PLAYER_ANIM_SWIMIDLE, AOF_LOOPING|AOF_NORESTART); + } + BodyStillAnimation(); + + // stand + } else { + // has reference (floor) + if (m_bReference) { + // jump + if (pl.en_tmJumped+_pTimer->TickQuantum>=_pTimer->CurrentTick() && + pl.en_tmJumped<=_pTimer->CurrentTick()) { + m_bReference = FALSE; + pl.StartModelAnim(PLAYER_ANIM_JUMPSTART, AOF_NORESTART); + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + + // not in jump anim and in stand mode change + } else if (!m_bWaitJumpAnim && m_iCrouchDownWait==0 && m_iRiseUpWait==0) { + // standing + if (!m_bCrouch) { + // running anim + if (vDesiredTranslation.Length()>5.0f && vCurrentTranslation.Length()>5.0f) { + if (vCurrentTranslation(3)<0) { + pl.StartModelAnim(PLAYER_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + } else { + pl.StartModelAnim(PLAYER_ANIM_BACKPEDALRUN, AOF_LOOPING|AOF_NORESTART); + } + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // walking anim + } else if (vDesiredTranslation.Length()>2.0f && vCurrentTranslation.Length()>2.0f) { + if (vCurrentTranslation(3)<0) { + pl.StartModelAnim(PLAYER_ANIM_NORMALWALK, AOF_LOOPING|AOF_NORESTART); + } else { + pl.StartModelAnim(PLAYER_ANIM_BACKPEDAL, AOF_LOOPING|AOF_NORESTART); + } + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // left rotation anim + } else if (aDesiredRotation(1)>0.5f) { + pl.StartModelAnim(PLAYER_ANIM_TURNLEFT, AOF_LOOPING|AOF_NORESTART); + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // right rotation anim + } else if (aDesiredRotation(1)<-0.5f) { + pl.StartModelAnim(PLAYER_ANIM_TURNRIGHT, AOF_LOOPING|AOF_NORESTART); + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // standing anim + } else { + pl.StartModelAnim(PLAYER_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + BodyStillAnimation(); + } + // crouch + } else { + // walking anim + if (vDesiredTranslation.Length()>2.0f && vCurrentTranslation.Length()>2.0f) { + if (vCurrentTranslation(3)<0) { + pl.StartModelAnim(PLAYER_ANIM_CROUCH_WALK, AOF_LOOPING|AOF_NORESTART); + } else { + pl.StartModelAnim(PLAYER_ANIM_CROUCH_WALKBACK, AOF_LOOPING|AOF_NORESTART); + } + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // left rotation anim + } else if (aDesiredRotation(1)>0.5f) { + pl.StartModelAnim(PLAYER_ANIM_CROUCH_TURNLEFT, AOF_LOOPING|AOF_NORESTART); + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // right rotation anim + } else if (aDesiredRotation(1)<-0.5f) { + pl.StartModelAnim(PLAYER_ANIM_CROUCH_TURNRIGHT, AOF_LOOPING|AOF_NORESTART); + BodyStillAnimation(); + m_fLastActionTime = _pTimer->CurrentTick(); + // standing anim + } else { + pl.StartModelAnim(PLAYER_ANIM_CROUCH_IDLE, AOF_LOOPING|AOF_NORESTART); + BodyStillAnimation(); + } + } + + } + + // no reference (in air) + } else { + // touched reference + if (pl.en_penReference!=NULL) { + m_bReference = TRUE; + pl.StartModelAnim(PLAYER_ANIM_JUMPEND, AOF_NORESTART); + BodyStillAnimation(); + SpawnReminder(this, pl.GetModelObject()->GetAnimLength(PLAYER_ANIM_JUMPEND), (INDEX) AA_JUMPDOWN); + m_bWaitJumpAnim = TRUE; + } + } + } + + // boring weapon animation + if (_pTimer->CurrentTick()-m_fLastActionTime > 10.0f) { + m_fLastActionTime = _pTimer->CurrentTick(); + ((CPlayerWeapons&)*pl.m_penWeapons).SendEvent(EBoringWeapon()); + } + + // moving view change + // translating -> change banking + if (m_bReference != 0 && vDesiredTranslation.Length()>1.0f && vCurrentTranslation.Length()>1.0f) { + m_bMoving = TRUE; + // sidestep banking + FLOAT vSidestepSpeedDesired = vDesiredTranslation(1); + FLOAT vSidestepSpeedCurrent = vCurrentTranslation(1); + // right + if (vSidestepSpeedDesired>1.0f && vSidestepSpeedCurrent>1.0f) { + m_bSidestepBankingRight = TRUE; + m_bSidestepBankingLeft = FALSE; + // left + } else if (vSidestepSpeedDesired<-1.0f && vSidestepSpeedCurrent<-1.0f) { + m_bSidestepBankingLeft = TRUE; + m_bSidestepBankingRight = FALSE; + // none + } else { + m_bSidestepBankingLeft = FALSE; + m_bSidestepBankingRight = FALSE; + } + // in air (space) or not moving + } else { + m_bMoving = FALSE; + m_bSidestepBankingLeft = FALSE; + m_bSidestepBankingRight = FALSE; + } + }; + + // crouch + void Crouch(void) { + if (m_bDisableAnimating) { + return; + } + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.StartModelAnim(PLAYER_ANIM_CROUCH, AOF_NORESTART); + SpawnReminder(this, pl.GetModelObject()->GetAnimLength(PLAYER_ANIM_CROUCH), (INDEX) AA_CROUCH); + m_iCrouchDownWait++; + m_bCrouch = TRUE; + }; + + // rise + void Rise(void) { + if (m_bDisableAnimating) { + return; + } + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.StartModelAnim(PLAYER_ANIM_RISE, AOF_NORESTART); + SpawnReminder(this, pl.GetModelObject()->GetAnimLength(PLAYER_ANIM_RISE), (INDEX) AA_RISE); + m_iRiseUpWait++; + m_bCrouch = FALSE; + }; + + // fall + void Fall(void) { + if (m_bDisableAnimating) { + return; + } + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.StartModelAnim(PLAYER_ANIM_JUMPSTART, AOF_NORESTART); + if (_pNetwork->ga_ulDemoMinorVersion>2) { m_bCrouch = FALSE; } + m_bReference = FALSE; + }; + + // swim + void Swim(void) { + if (m_bDisableAnimating) { + return; + } + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.StartModelAnim(PLAYER_ANIM_SWIM, AOF_LOOPING|AOF_NORESTART); + if (_pNetwork->ga_ulDemoMinorVersion>2) { m_bCrouch = FALSE; } + m_bSwim = TRUE; + }; + + // stand + void Stand(void) { + if (m_bDisableAnimating) { + return; + } + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.StartModelAnim(PLAYER_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); + if (_pNetwork->ga_ulDemoMinorVersion>2) { m_bCrouch = FALSE; } + m_bSwim = FALSE; + }; + + // fire/attack + void FireAnimation(INDEX iAnim, ULONG ulFlags) { + if (m_bSwim) { + INDEX iWeapon = ((CPlayerWeapons&)*(((CPlayer&)*m_penPlayer).m_penWeapons)).m_iCurrentWeapon; + switch (iWeapon) { + case WEAPON_NONE: + break; + case WEAPON_KNIFE: case WEAPON_COLT: case WEAPON_DOUBLECOLT: //case WEAPON_PIPEBOMB: + iAnim += BODY_ANIM_COLT_SWIM_STAND-BODY_ANIM_COLT_STAND; + break; + case WEAPON_SINGLESHOTGUN: case WEAPON_DOUBLESHOTGUN: case WEAPON_TOMMYGUN: + case WEAPON_LASER: // case WEAPON_FLAMER: case WEAPON_GHOSTBUSTER: + iAnim += BODY_ANIM_SHOTGUN_SWIM_STAND-BODY_ANIM_SHOTGUN_STAND; + break; + case WEAPON_MINIGUN: case WEAPON_ROCKETLAUNCHER: case WEAPON_GRENADELAUNCHER: + case WEAPON_IRONCANNON: // case WEAPON_NUKECANNON: + iAnim += BODY_ANIM_MINIGUN_SWIM_STAND-BODY_ANIM_MINIGUN_STAND; + break; + } + } + m_bAttacking = FALSE; + m_bChangeWeapon = FALSE; + SetBodyAnimation(iAnim, ulFlags); + if (!(ulFlags&AOF_LOOPING)) { + SpawnReminder(this, m_fBodyAnimTime, (INDEX) AA_ATTACK); + m_tmAttackingDue = _pTimer->CurrentTick()+m_fBodyAnimTime; + } + m_bAttacking = TRUE; + }; + void FireAnimationOff(void) { + m_bAttacking = FALSE; + }; + + + +/************************************************************ + * CHANGE BODY ANIMATION * + ************************************************************/ + // body animation template + void BodyAnimationTemplate(INDEX iNone, INDEX iColt, INDEX iShotgun, INDEX iMinigun, ULONG ulFlags) { + INDEX iWeapon = ((CPlayerWeapons&)*(((CPlayer&)*m_penPlayer).m_penWeapons)).m_iCurrentWeapon; + switch (iWeapon) { + case WEAPON_NONE: + SetBodyAnimation(iNone, ulFlags); + break; + case WEAPON_KNIFE: case WEAPON_COLT: case WEAPON_DOUBLECOLT: // case WEAPON_PIPEBOMB: + if (m_bSwim) { iColt += BODY_ANIM_COLT_SWIM_STAND-BODY_ANIM_COLT_STAND; } + SetBodyAnimation(iColt, ulFlags); + break; + case WEAPON_SINGLESHOTGUN: case WEAPON_DOUBLESHOTGUN: case WEAPON_TOMMYGUN: + case WEAPON_LASER: // case WEAPON_FLAMER: case WEAPON_GHOSTBUSTER: + if (m_bSwim) { iShotgun += BODY_ANIM_SHOTGUN_SWIM_STAND-BODY_ANIM_SHOTGUN_STAND; } + SetBodyAnimation(iShotgun, ulFlags); + break; + case WEAPON_MINIGUN: case WEAPON_ROCKETLAUNCHER: case WEAPON_GRENADELAUNCHER: + case WEAPON_IRONCANNON: // case WEAPON_NUKECANNON: + if (m_bSwim) { iMinigun+=BODY_ANIM_MINIGUN_SWIM_STAND-BODY_ANIM_MINIGUN_STAND; } + SetBodyAnimation(iMinigun, ulFlags); + break; + default: ASSERTALWAYS("Player Animator - Unknown weapon"); + } + }; + + // walk + void BodyWalkAnimation() { + BodyAnimationTemplate(BODY_ANIM_NORMALWALK, + BODY_ANIM_COLT_STAND, BODY_ANIM_SHOTGUN_STAND, BODY_ANIM_MINIGUN_STAND, + AOF_LOOPING|AOF_NORESTART); + }; + + // stand + void BodyStillAnimation() { + BodyAnimationTemplate(BODY_ANIM_WAIT, + BODY_ANIM_COLT_STAND, BODY_ANIM_SHOTGUN_STAND, BODY_ANIM_MINIGUN_STAND, + AOF_LOOPING|AOF_NORESTART); + }; + + // push weapon + void BodyPushAnimation() { + m_bAttacking = FALSE; + m_bChangeWeapon = FALSE; + BodyAnimationTemplate(BODY_ANIM_WAIT, + BODY_ANIM_COLT_REDRAW, BODY_ANIM_SHOTGUN_REDRAW, BODY_ANIM_MINIGUN_REDRAW, 0); + m_bChangeWeapon = TRUE; + }; + + // remove weapon attachment + void RemoveWeapon(void) + { + CPlayer &pl = (CPlayer&)*m_penPlayer; + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + switch (m_iWeaponLast) { + case WEAPON_NONE: + case WEAPON_KNIFE: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_KNIFE); + break; + case WEAPON_DOUBLECOLT: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_COLT_LEFT); + // reset to player body + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + case WEAPON_COLT: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_COLT_RIGHT); + break; + case WEAPON_SINGLESHOTGUN: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_SINGLE_SHOTGUN); + break; + case WEAPON_DOUBLESHOTGUN: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_DOUBLE_SHOTGUN); + break; + case WEAPON_TOMMYGUN: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_TOMMYGUN); + break; + case WEAPON_MINIGUN: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_MINIGUN); + break; + case WEAPON_ROCKETLAUNCHER: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_ROCKET_LAUNCHER); + break; + case WEAPON_GRENADELAUNCHER: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_GRENADE_LAUNCHER); + break; +/* + case WEAPON_PIPEBOMB: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_COLT_RIGHT); + // reset to player body + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_COLT_LEFT); + break; + case WEAPON_FLAMER: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_FLAMER); + break; + */ + case WEAPON_LASER: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_LASER); + break; +/* + case WEAPON_GHOSTBUSTER: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_LASER); + break; + */ + case WEAPON_IRONCANNON: +// case WEAPON_NUKECANNON: + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_CANNON); + break; + default: + ASSERT(FALSE); + } + // sync apperances + SyncWeapon(); + } + + // pull weapon + void BodyPullAnimation() { + // remove old weapon + RemoveWeapon(); + + // set new weapon + SetWeapon(); + + // pull weapon + m_bChangeWeapon = FALSE; + BodyAnimationTemplate(BODY_ANIM_WAIT, + BODY_ANIM_COLT_DRAW, BODY_ANIM_SHOTGUN_DRAW, BODY_ANIM_MINIGUN_DRAW, 0); + INDEX iWeapon = ((CPlayerWeapons&)*(((CPlayer&)*m_penPlayer).m_penWeapons)).m_iCurrentWeapon; + if (iWeapon!=WEAPON_NONE) { + m_bChangeWeapon = TRUE; + SpawnReminder(this, m_fBodyAnimTime, (INDEX) AA_PULLWEAPON); + } + // sync apperances + SyncWeapon(); + }; + + // pull item + void BodyPullItemAnimation() { + // remove old weapon + RemoveWeapon(); + + // pull item + m_bChangeWeapon = FALSE; + SetBodyAnimation(BODY_ANIM_STATUE_PULL, 0); + m_bChangeWeapon = TRUE; + SpawnReminder(this, m_fBodyAnimTime, (INDEX) AA_PULLWEAPON); + // sync apperances + SyncWeapon(); + }; + + // pick item + void BodyPickItemAnimation() { + // remove old weapon + RemoveWeapon(); + + // pick item + m_bChangeWeapon = FALSE; + SetBodyAnimation(BODY_ANIM_KEYLIFT, 0); + m_bChangeWeapon = TRUE; + SpawnReminder(this, m_fBodyAnimTime, (INDEX) AA_PULLWEAPON); + // sync apperances + SyncWeapon(); + }; + + // remove item + void BodyRemoveItem() { + CPlayer &pl = (CPlayer&)*m_penPlayer; + pmoModel = &(pl.GetModelObject()->GetAttachmentModel(PLAYER_ATTACHMENT_TORSO)->amo_moModelObject); + pmoModel->RemoveAttachmentModel(BODY_ATTACHMENT_ITEM); + // sync apperances + SyncWeapon(); + }; + + +/************************************************************ + * FIRE FLARE * + ************************************************************/ + void OnPreRender(void) { + ControlFlareAttachment(); + + // Minigun Specific + CPlayerWeapons &plw = (CPlayerWeapons&)*(((CPlayer&)*m_penPlayer).m_penWeapons); + if (plw.m_iCurrentWeapon==WEAPON_MINIGUN) { + ANGLE aAngle = Lerp(plw.m_aMiniGunLast, plw.m_aMiniGun, _pTimer->GetLerpFactor()); + // rotate minigun barrels + CPlayer &pl = (CPlayer&)*m_penPlayer; + CAttachmentModelObject *pamo = pl.GetModelObject()->GetAttachmentModelList( + PLAYER_ATTACHMENT_TORSO, BODY_ATTACHMENT_MINIGUN, MINIGUNITEM_ATTACHMENT_BARRELS, -1); + if (pamo!=NULL) { + pamo->amo_plRelative.pl_OrientationAngle(3) = aAngle; + } + } + }; + + // show flare + void ShowFlare(INDEX iAttachWeapon, INDEX iAttachObject, INDEX iAttachFlare) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + CAttachmentModelObject *pamo = pl.GetModelObject()->GetAttachmentModelList( + PLAYER_ATTACHMENT_TORSO, iAttachWeapon, iAttachObject, iAttachFlare, -1); + if (pamo!=NULL) { + pamo->amo_plRelative.pl_OrientationAngle(3) = (rand()*360.0f)/RAND_MAX; + CModelObject &mo = pamo->amo_moModelObject; + mo.StretchModel(FLOAT3D(1, 1, 1)); + } + }; + + // hide flare + void HideFlare(INDEX iAttachWeapon, INDEX iAttachObject, INDEX iAttachFlare) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + CAttachmentModelObject *pamo = pl.GetModelObject()->GetAttachmentModelList( + PLAYER_ATTACHMENT_TORSO, iAttachWeapon, iAttachObject, iAttachFlare, -1); + if (pamo!=NULL) { + CModelObject &mo = pamo->amo_moModelObject; + mo.StretchModel(FLOAT3D(0, 0, 0)); + } + }; + + // flare attachment + void ControlFlareAttachment(void) + { +/* if(!IsPredictionHead()) { + return; + } + */ + + // get your prediction tail + CPlayerAnimator *pen = (CPlayerAnimator *)GetPredictionTail(); + + INDEX iWeapon = ((CPlayerWeapons&)*(((CPlayer&)*pen->m_penPlayer).m_penWeapons)).m_iCurrentWeapon; + // second colt only + if (iWeapon==WEAPON_DOUBLECOLT) { + // add flare + if (pen->m_iSecondFlare==FLARE_ADD) { + pen->m_iSecondFlare = FLARE_REMOVE; + ShowFlare(BODY_ATTACHMENT_COLT_LEFT, COLTITEM_ATTACHMENT_BODY, COLTMAIN_ATTACHMENT_FLARE); + // remove flare + } else if (m_iSecondFlare==FLARE_REMOVE) { + HideFlare(BODY_ATTACHMENT_COLT_LEFT, COLTITEM_ATTACHMENT_BODY, COLTMAIN_ATTACHMENT_FLARE); + } + } + + // add flare + if (pen->m_iFlare==FLARE_ADD) { + pen->m_iFlare = FLARE_REMOVE; + pen->m_tmFlareAdded = _pTimer->CurrentTick(); + switch(iWeapon) { + case WEAPON_DOUBLECOLT: case WEAPON_COLT: + ShowFlare(BODY_ATTACHMENT_COLT_RIGHT, COLTITEM_ATTACHMENT_BODY, COLTMAIN_ATTACHMENT_FLARE); + break; + case WEAPON_SINGLESHOTGUN: + ShowFlare(BODY_ATTACHMENT_SINGLE_SHOTGUN, SINGLESHOTGUNITEM_ATTACHMENT_BARRELS, BARRELS_ATTACHMENT_FLARE); + break; + case WEAPON_DOUBLESHOTGUN: + ShowFlare(BODY_ATTACHMENT_DOUBLE_SHOTGUN, DOUBLESHOTGUNITEM_ATTACHMENT_BARRELS, DSHOTGUNBARRELS_ATTACHMENT_FLARE); + break; + case WEAPON_TOMMYGUN: + ShowFlare(BODY_ATTACHMENT_TOMMYGUN, TOMMYGUNITEM_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE); + break; + case WEAPON_MINIGUN: + ShowFlare(BODY_ATTACHMENT_MINIGUN, MINIGUNITEM_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE); + break; + } + // remove + } else if (m_iFlare==FLARE_REMOVE && + _pTimer->CurrentTick()>pen->m_tmFlareAdded+_pTimer->TickQuantum) { + switch(iWeapon) { + case WEAPON_DOUBLECOLT: case WEAPON_COLT: + HideFlare(BODY_ATTACHMENT_COLT_RIGHT, COLTITEM_ATTACHMENT_BODY, COLTMAIN_ATTACHMENT_FLARE); + break; + case WEAPON_SINGLESHOTGUN: + HideFlare(BODY_ATTACHMENT_SINGLE_SHOTGUN, SINGLESHOTGUNITEM_ATTACHMENT_BARRELS, BARRELS_ATTACHMENT_FLARE); + break; + case WEAPON_DOUBLESHOTGUN: + HideFlare(BODY_ATTACHMENT_DOUBLE_SHOTGUN, DOUBLESHOTGUNITEM_ATTACHMENT_BARRELS, DSHOTGUNBARRELS_ATTACHMENT_FLARE); + break; + case WEAPON_TOMMYGUN: + HideFlare(BODY_ATTACHMENT_TOMMYGUN, TOMMYGUNITEM_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE); + break; + case WEAPON_MINIGUN: + HideFlare(BODY_ATTACHMENT_MINIGUN, MINIGUNITEM_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE); + break; + } + } + }; + + + +/************************************************************ + * PROCEDURES * + ************************************************************/ +procedures: + ReminderAction(EReminder er) { + switch (er.iValue) { + case AA_JUMPDOWN: m_bWaitJumpAnim = FALSE; break; + case AA_CROUCH: m_iCrouchDownWait--; ASSERT(m_iCrouchDownWait>=0); break; + case AA_RISE: m_iRiseUpWait--; ASSERT(m_iRiseUpWait>=0); break; + case AA_PULLWEAPON: m_bChangeWeapon = FALSE; break; + case AA_ATTACK: if(m_tmAttackingDue<=_pTimer->CurrentTick()) { m_bAttacking = FALSE; } break; + default: ASSERTALWAYS("Animator - unknown reminder action."); + } + return EBegin(); + }; + + Main(EAnimatorInit eInit) { + // remember the initial parameters + ASSERT(eInit.penPlayer!=NULL); + m_penPlayer = eInit.penPlayer; + + // declare yourself as a void + InitAsVoid(); + SetFlags(GetFlags()|ENF_CROSSESLEVELS); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // last action time for boring weapon animation + m_fLastActionTime = _pTimer->CurrentTick(); + + wait() { + on (EBegin) : { resume; } + on (EReminder er) : { call ReminderAction(er); } + on (EEnd) : { stop; } + } + + // cease to exist + Destroy(); + + return; + }; +}; + diff --git a/Sources/Entities/PlayerMarker.es b/Sources/Entities/PlayerMarker.es new file mode 100644 index 0000000..e6f314e --- /dev/null +++ b/Sources/Entities/PlayerMarker.es @@ -0,0 +1,90 @@ +404 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/MusicHolder.h" +%} + +uses "Entities/Marker"; + +%{ + extern void CPlayerWeapons_Precache(ULONG ulAvailable); +%} + +class CPlayerMarker: CMarker { +name "Player Marker"; +thumbnail "Thumbnails\\PlayerMarker.tbn"; +features "IsImportant"; + +properties: + 1 FLOAT m_fHealth "Health" 'H' = 100.0f, + 2 FLOAT m_fShield "Shield" 'S' = 0.0f, + 3 INDEX m_iGiveWeapons "Give Weapons" 'W' = 0x1, + 4 INDEX m_iTakeWeapons "Take Weapons" = 0x0, + 5 CTString m_strGroup "Group" 'G' = "", + 6 BOOL m_bQuickStart "Quick start" 'Q' = FALSE, + 7 BOOL m_bStartInComputer "Start in computer" 'C' = FALSE, + 8 CEntityPointer m_penMessage "Message" 'M', + 9 FLOAT m_fMaxAmmoRatio "Max ammo ratio" 'A' = 0.0f, + 10 FLOAT m_tmLastSpawned = -1000.0f, // to avoid telefragging in deathmatch + 11 INDEX m_iTakeAmmo "Take Ammo" = 0x0, + +components: + 1 model MODEL_MARKER "Models\\Editor\\PlayerStart.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\PlayerStart.tex", + +functions: + void Precache(void) { + if (m_iGiveWeapons>1) { + CPlayerWeapons_Precache(m_iGiveWeapons); + } + } + BOOL HandleEvent(const CEntityEvent &ee) { + if (ee.ee_slEvent == EVENTCODE_ETrigger) { + CEntity *penMainMusicHolder = _pNetwork->GetEntityWithName("MusicHolder", 0); + if (penMainMusicHolder==NULL || !IsOfClass(penMainMusicHolder, "MusicHolder")) { + return TRUE; + } + CMusicHolder *pmh = (CMusicHolder *)penMainMusicHolder; + BOOL bNew = (pmh->m_penRespawnMarker!=this); + pmh->m_penRespawnMarker = this; + + // if this is a new marker and we are in single player and the trigger originator is valid + CEntity *penCaused = ((ETrigger&)ee).penCaused; + if (bNew && + (GetSP()->sp_bSinglePlayer && GetSP()->sp_gmGameMode!=CSessionProperties::GM_FLYOVER) + && IsOfClass(penCaused, "Player")) { + // if the player wants auto-save + CPlayerSettings *pps = (CPlayerSettings *) (((CPlayerEntity*)penCaused)->en_pcCharacter.pc_aubAppearance); + if (pps->ps_ulFlags&PSF_AUTOSAVE) { + // save now + _pShell->Execute("gam_bQuickSave=1;"); + } + } + return TRUE; + } + + return FALSE; + }; + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // set name + if (m_bQuickStart) { + m_strName.PrintF("Player Quick Start"); + } else { + m_strName.PrintF("Player Start - %s", (const char*)m_strGroup); + } + + return; + } +}; + diff --git a/Sources/Entities/PlayerView.es b/Sources/Entities/PlayerView.es new file mode 100644 index 0000000..289327f --- /dev/null +++ b/Sources/Entities/PlayerView.es @@ -0,0 +1,241 @@ +403 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/Player.h" +#include "Entities/PlayerWeapons.h" +%} + + +enum ViewType { + 0 VT_PLAYERDEATH "", // player death + 1 VT_PLAYERREBIRTH "", // player rebirth (player is spawned) + 2 VT_CAMERA "", // camera view + 3 VT_3RDPERSONVIEW "", // 3rd person view +}; + +// input parameter for viewer +event EViewInit { + CEntityPointer penOwner, // who owns it + CEntityPointer penCamera, // first camera for camera view + enum ViewType vtView, // view type + BOOL bDeathFixed, +}; + +%{ + +void CPlayerView_Precache(void) +{ + CDLLEntityClass *pdec = &CPlayerView_DLLClass; + pdec->PrecacheModel(MODEL_MARKER); + pdec->PrecacheTexture(TEXTURE_MARKER); +} + +%} + +class export CPlayerView : CMovableEntity { +name "Player View"; +thumbnail ""; +features "CanBePredictable"; + +properties: + 1 CEntityPointer m_penOwner, // class which owns it + 2 INDEX m_iViewType=0, // view type + 3 FLOAT m_fDistance = 1.0f, // current distance + 4 FLOAT3D m_vZLast = FLOAT3D(0,0,0), + 5 FLOAT3D m_vTargetLast = FLOAT3D(0,0,0), + 6 BOOL m_bFixed = FALSE, // fixed view (player falling in abyss) + +components: + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + +functions: + // add to prediction any entities that this entity depends on + void AddDependentsToPrediction(void) + { + m_penOwner->AddToPrediction(); + } + void PreMoving() {}; + void DoMoving() { + en_plLastPlacement = GetPlacement(); // remember old placement for lerping + }; + void PostMoving() + { + SetCameraPosition(); + } + CPlacement3D GetLerpedPlacement(void) const + { + FLOAT fLerpFactor; + if (IsPredictor()) { + fLerpFactor = _pTimer->GetLerpFactor(); + } else { + fLerpFactor = _pTimer->GetLerpFactor2(); + } + return LerpPlacementsPrecise(en_plLastPlacement, en_plPlacement, fLerpFactor); + //return CMovableEntity::GetLerpedPlacement(); + } + + // render particles + void RenderParticles(void) + { + if (Particle_GetViewer()==this) { + Particles_ViewerLocal(this); + } + } + + void SetCameraPosition() + { + // 3rd person view + FLOAT fDistance = 1.0f; + CPlacement3D pl = ((CPlayerEntity&) *m_penOwner).en_plViewpoint; + BOOL bFollowCrossHair; + + if (m_iViewType == VT_3RDPERSONVIEW) { + // little above player eyes so it can be seen where he is fireing + pl.pl_OrientationAngle(2) -= 10.0f; + pl.pl_PositionVector(2) += 1.0f; + fDistance = 5.75f; + bFollowCrossHair = TRUE; + // death + } else if (m_iViewType == VT_PLAYERDEATH) { + fDistance = 3.5f; + bFollowCrossHair = FALSE; + } + + pl.pl_OrientationAngle(3) = 0.0f; + + // transform rotation angle + pl.RelativeToAbsolute(m_penOwner->GetPlacement()); + // make base placement to back out from + FLOAT3D vBase; + EntityInfo *pei= (EntityInfo*) (m_penOwner->GetEntityInfo()); + GetEntityInfoPosition(m_penOwner, pei->vSourceCenter, vBase); + + // create a set of rays to test + FLOATmatrix3D m; + MakeRotationMatrixFast(m, pl.pl_OrientationAngle); + FLOAT3D vRight = m.GetColumn(1); + FLOAT3D vUp = m.GetColumn(2); + FLOAT3D vFront = m.GetColumn(3); + + FLOAT3D vDest[5]; + vDest[0] = vBase+vFront*fDistance+vUp*1.0f; + vDest[1] = vBase+vFront*fDistance-vUp*1.0f; + vDest[2] = vBase+vFront*fDistance+vRight*1.0f; + vDest[3] = vBase+vFront*fDistance-vRight*1.0f; + vDest[4] = vBase+vFront*fDistance; + + FLOAT fBack = 0; + // for each ray + for (INDEX i=0; i<5; i++) { + // cast a ray to find if any brush is hit + CCastRay crRay( m_penOwner, vBase, vDest[i]); + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + GetWorld()->CastRay(crRay); + + // if hit something + if (crRay.cr_penHit!=NULL) { + // clamp distance + fDistance = Min(fDistance, crRay.cr_fHitDistance-0.5f); + // if hit polygon + if (crRay.cr_pbpoBrushPolygon!=NULL) { + // back off + FLOAT3D vDir = (vDest[i]-vBase).Normalize(); + FLOAT fD = Abs(FLOAT3D(crRay.cr_pbpoBrushPolygon->bpo_pbplPlane->bpl_plAbsolute)%vDir)*0.25f; + fBack = Max(fBack, fD); + } + } + + } + fDistance = ClampDn(fDistance-fBack, 0.0f); + m_fDistance = fDistance; + vBase += vFront*fDistance; + + CPlayerWeapons *ppw = ((CPlayer&) *m_penOwner).GetPlayerWeapons(); + if (bFollowCrossHair) { + FLOAT3D vTarget = vBase-ppw->m_vRayHit; + FLOAT fLen = vTarget.Length(); + if (fLen>0.01) { + vTarget/=fLen; + } else { + vTarget = FLOAT3D(0,1,0); + } + + FLOAT3D vX; + FLOAT3D vY = m.GetColumn(2); + FLOAT3D vZ = vTarget; + vZ.Normalize(); + + if (Abs(vY%vZ)>0.9f) { + vY = -m.GetColumn(3); + } + + vX = vY*vZ; + vX.Normalize(); + vY = vZ*vX; + vY.Normalize(); + m_vZLast = vZ; + + m(1,1) = vX(1); m(1,2) = vY(1); m(1,3) = vZ(1); + m(2,1) = vX(2); m(2,2) = vY(2); m(2,3) = vZ(2); + m(3,1) = vX(3); m(3,2) = vY(3); m(3,3) = vZ(3); + DecomposeRotationMatrixNoSnap(pl.pl_OrientationAngle, m); + } + + if (m_bFixed) { + pl.pl_PositionVector = GetPlacement().pl_PositionVector; + pl.pl_OrientationAngle = ANGLE3D(0,-90, 0); + m_fDistance = (pl.pl_PositionVector-m_penOwner->GetPlacement().pl_PositionVector).Length(); + MakeRotationMatrixFast(m, pl.pl_OrientationAngle); + } else { + pl.pl_PositionVector = vBase; + } + + // set camera placement + SetPlacement_internal(pl, m, TRUE /* try to optimize for small movements */); + }; + +procedures: + + Main(EViewInit eInit) { + // remember the initial parameters + ASSERT(eInit.penOwner!=NULL); + m_penOwner = eInit.penOwner; + m_iViewType = eInit.vtView; + m_bFixed = eInit.bDeathFixed; + ASSERT(IsOfClass(m_penOwner, "Player")); + + // init as model + InitAsEditorModel(); + SetFlags(GetFlags()|ENF_CROSSESLEVELS); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); + SetCollisionFlags(ECF_IMMATERIAL); + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + // add to movers list if needed + if (m_iViewType == VT_PLAYERDEATH) { + AddToMovers(); + } + + SendEvent(EStart()); + wait() { + on (EBegin) : { resume; } + on (EStart) : { + SetCameraPosition(); + en_plLastPlacement = GetPlacement(); // remember old placement for lerping + m_vTargetLast = ((CPlayer&) *m_penOwner).GetPlayerWeapons()->m_vRayHit; + resume; + }; + on (EEnd) : { stop; } + otherwise() : { resume; } + } + // cease to exist + Destroy(); + + return; + }; +}; + diff --git a/Sources/Entities/PlayerWeapons.es b/Sources/Entities/PlayerWeapons.es new file mode 100644 index 0000000..debfb7f --- /dev/null +++ b/Sources/Entities/PlayerWeapons.es @@ -0,0 +1,4838 @@ +402 +%{ +#include "Entities/StdH/StdH.h" + +#include + +#include "Models/Weapons/Knife/Knife.h" +#include "Models/Weapons/Knife/KnifeItem.h" +#include "Models/Weapons/Colt/colt.h" +#include "Models/Weapons/Colt/ColtMain.h" +#include "Models/Weapons/SingleShotgun/SingleShotGun.h" +#include "Models/Weapons/SingleShotgun/Barrels.h" +#include "Models/Weapons/DoubleShotgun/DoubleShotgun.h" +#include "Models/Weapons/DoubleShotgun/Dshotgunbarrels.h" +#include "Models/Weapons/DoubleShotgun/HandWithAmmo.h" +#include "Models/Weapons/TommyGun/TommyGun.h" +#include "Models/Weapons/TommyGun/Body.h" +#include "Models/Weapons/MiniGun/minigun.h" +#include "Models/Weapons/MiniGun/Body.h" +#include "Models/Weapons/GrenadeLauncher/GrenadeLauncher.h" +#include "Models/Weapons/RocketLauncher/RocketLauncher.h" +//#include "Models/Weapons/PipeBomb/HandWithStick.h" +//#include "Models/Weapons/PipeBomb/HandWithBomb.h" +//#include "Models/Weapons/Flamer/Flamer.h" +#include "Models/Weapons/Laser/Laser.h" +#include "Models/Weapons/Laser/Barrel.h" +//#include "Models/Weapons/GhostBuster/GhostBuster.h" +//#include "Models/Weapons/GhostBuster/Effect01.h" +#include "Models/Weapons/Cannon/Cannon.h" +#include "Models/Weapons/Cannon/Body.h" +//#include "Models/Weapons/Cannon/NukeBox.h" +//#include "Models/Weapons/Cannon/Light.h" +#include "Models/Player/SeriousSam/Body.h" + +#include "Entities/Switch.h" +#include "Entities/PlayerAnimator.h" +#include "Entities/MovingBrush.h" +#include "Entities/MessageHolder.h" +#include "Entities/EnemyBase.h" +extern INDEX hud_bShowWeapon; +%} + +uses "Entities/Player"; +uses "Entities/PlayerWeaponsEffects"; +uses "Entities/Projectile"; +uses "Entities/Bullet"; +uses "Entities/BasicEffects"; +uses "Entities/WeaponItem"; +uses "Entities/AmmoItem"; +uses "Entities/AmmoPack"; +//uses "Entities/Pipebomb"; +//uses "Entities/GhostBusterRay"; +uses "Entities/CannonBall"; + + +// input parameter for weapons +event EWeaponsInit { + CEntityPointer penOwner, // who owns it +}; + +// select weapon +event ESelectWeapon { + INDEX iWeapon, // weapon to select +}; + +// boring weapon animations +event EBoringWeapon {}; + +// fire weapon +event EFireWeapon {}; +// release weapon +event EReleaseWeapon {}; +// reload weapon +event EReloadWeapon {}; + + +// weapons (do not change order! - needed by HUD.cpp) +enum WeaponType { + 0 WEAPON_NONE "", + 1 WEAPON_KNIFE "", + 2 WEAPON_COLT "", + 3 WEAPON_DOUBLECOLT "", + 4 WEAPON_SINGLESHOTGUN "", + 5 WEAPON_DOUBLESHOTGUN "", + 6 WEAPON_TOMMYGUN "", + 7 WEAPON_MINIGUN "", + 8 WEAPON_ROCKETLAUNCHER "", + 9 WEAPON_GRENADELAUNCHER "", +// 10 WEAPON_PIPEBOMB "", +// 12 WEAPON_FLAMER "", + 14 WEAPON_LASER "", +// 15 WEAPON_GHOSTBUSTER "", + 16 WEAPON_IRONCANNON "", +// 17 WEAPON_NUKECANNON "", + 17 WEAPON_LAST "", +}; + +%{ + +/* +#if BUILD_TEST + #define WEAPONS_DISABLEDMASK (\ + (1<<(WEAPON_TOMMYGUN -1))|\ + (1<<(WEAPON_GRENADELAUNCHER-1))|\ + (1<<(WEAPON_PIPEBOMB -1))|\ + (1<<(WEAPON_FLAMER -1))|\ + (1<<(WEAPON_LASER -1))|\ + (1<<(WEAPON_GHOSTBUSTER -1))|\ + (1<<(WEAPON_IRONCANNON -1))|\ + (1<<(WEAPON_NUKECANNON -1))) +#else + #define WEAPONS_DISABLEDMASK (0) +#endif + */ + +#define MAX_WEAPONS 30 + + +// MiniGun specific +#define MINIGUN_STATIC 0 +#define MINIGUN_FIRE 1 +#define MINIGUN_SPINUP 2 +#define MINIGUN_SPINDOWN 3 + +#define MINIGUN_SPINUPTIME 0.5f +#define MINIGUN_SPINDNTIME 3.0f +#define MINIGUN_SPINUPSOUND 0.5f +#define MINIGUN_SPINDNSOUND 1.5f +#define MINIGUN_FULLSPEED 500.0f +#define MINIGUN_SPINUPACC (MINIGUN_FULLSPEED/MINIGUN_SPINUPTIME) +#define MINIGUN_SPINDNACC (MINIGUN_FULLSPEED/MINIGUN_SPINDNTIME) +#define MINIGUN_TICKTIME (_pTimer->TickQuantum) + +// fire flare specific +#define FLARE_REMOVE 1 +#define FLARE_ADD 2 + +// animation light specific +#define LIGHT_ANIM_MINIGUN 2 +#define LIGHT_ANIM_TOMMYGUN 3 +#define LIGHT_ANIM_COLT_SHOTGUN 4 +#define LIGHT_ANIM_NONE 5 + + +// mana for ammo adjustment (multiplier) +#define MANA_AMMO (0.1f) + +// position of weapon model -- weapon 0 is never used +static FLOAT wpn_fH[MAX_WEAPONS+1]; +static FLOAT wpn_fP[MAX_WEAPONS+1]; +static FLOAT wpn_fB[MAX_WEAPONS+1]; +static FLOAT wpn_fX[MAX_WEAPONS+1]; +static FLOAT wpn_fY[MAX_WEAPONS+1]; +static FLOAT wpn_fZ[MAX_WEAPONS+1]; +static FLOAT wpn_fFOV[MAX_WEAPONS+1]; +static FLOAT wpn_fClip[MAX_WEAPONS+1]; +static FLOAT wpn_fFX[MAX_WEAPONS+1]; // firing source +static FLOAT wpn_fFY[MAX_WEAPONS+1]; +//static FLOAT wpn_fFZ[MAX_WEAPONS+1]; +static INDEX wpn_iCurrent; +extern FLOAT hud_tmWeaponsOnScreen; +extern FLOAT wpn_fRecoilSpeed[17]; +extern FLOAT wpn_fRecoilLimit[17]; +extern FLOAT wpn_fRecoilDampUp[17]; +extern FLOAT wpn_fRecoilDampDn[17]; +extern FLOAT wpn_fRecoilOffset[17]; +extern FLOAT wpn_fRecoilFactorP[17]; +extern FLOAT wpn_fRecoilFactorZ[17]; + +// bullet positions +static FLOAT afSingleShotgunPellets[] = +{ -0.3f,+0.1f, +0.0f,+0.1f, +0.3f,+0.1f, + -0.4f,-0.1f, -0.1f,-0.1f, +0.1f,-0.1f, +0.4f,-0.1f +}; +static FLOAT afDoubleShotgunPellets[] = +{ + -0.3f,+0.15f, +0.0f,+0.15f, +0.3f,+0.15f, + -0.4f,+0.05f, -0.1f,+0.05f, +0.1f,+0.05f, +0.4f,+0.05f, + -0.3f,-0.05f, +0.0f,-0.05f, +0.3f,-0.05f, + -0.4f,-0.15f, -0.1f,-0.15f, +0.1f,-0.15f, +0.4f,-0.15f +}; + + +// crosshair console variables +static INDEX hud_bCrosshairFixed = FALSE; +static INDEX hud_bCrosshairColoring = TRUE; +static FLOAT hud_fCrosshairScale = 1.0f; +static FLOAT hud_fCrosshairOpacity = 1.0f; +static FLOAT hud_fCrosshairRatio = 0.5f; // max distance size ratio +// misc HUD vars +static INDEX hud_bShowPlayerName = TRUE; +static INDEX hud_bShowCoords = FALSE; +static FLOAT plr_tmSnoopingDelay = 1.0f; // seconds +FLOAT plr_tmSnoopingTime = 1.0f; // seconds + +// some static vars +static INDEX _iLastCrosshairType=-1; +static CTextureObject _toCrosshair; + +// must do this to keep dependency catcher happy +CTFileName fn1 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair1.tex"); +CTFileName fn2 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair2.tex"); +CTFileName fn3 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair3.tex"); +CTFileName fn4 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair4.tex"); +CTFileName fn5 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair5.tex"); +CTFileName fn6 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair6.tex"); +CTFileName fn7 = CTFILENAME("Textures\\Interface\\Crosshairs\\Crosshair7.tex"); + + +void CPlayerWeapons_Precache(ULONG ulAvailable) +{ + CDLLEntityClass *pdec = &CPlayerWeapons_DLLClass; + + // precache general stuff always + pdec->PrecacheTexture(TEX_REFL_BWRIPLES01 ); + pdec->PrecacheTexture(TEX_REFL_BWRIPLES02 ); + pdec->PrecacheTexture(TEX_REFL_LIGHTMETAL01 ); + pdec->PrecacheTexture(TEX_REFL_LIGHTBLUEMETAL01); + pdec->PrecacheTexture(TEX_REFL_DARKMETAL ); + pdec->PrecacheTexture(TEX_REFL_PURPLE01 ); + pdec->PrecacheTexture(TEX_SPEC_WEAK ); + pdec->PrecacheTexture(TEX_SPEC_MEDIUM ); + pdec->PrecacheTexture(TEX_SPEC_STRONG ); + pdec->PrecacheTexture(TEXTURE_HAND ); + pdec->PrecacheTexture(TEXTURE_FLARE01 ); + pdec->PrecacheModel(MODEL_FLARE01); + pdec->PrecacheClass(CLASS_BULLET); + pdec->PrecacheSound(SOUND_SILENCE); + + // precache other weapons if available + if ( ulAvailable&(1<<(WEAPON_KNIFE-1)) ) { + pdec->PrecacheModel(MODEL_KNIFE ); + pdec->PrecacheModel(MODEL_KNIFEITEM ); + pdec->PrecacheTexture(TEXTURE_KNIFEITEM ); + pdec->PrecacheSound(SOUND_KNIFE_BACK ); + pdec->PrecacheSound(SOUND_KNIFE_HIGH ); + pdec->PrecacheSound(SOUND_KNIFE_LONG ); + pdec->PrecacheSound(SOUND_KNIFE_LOW ); + } + + if ( ulAvailable&(1<<(WEAPON_COLT-1)) ) { + pdec->PrecacheModel(MODEL_COLT ); + pdec->PrecacheModel(MODEL_COLTCOCK ); + pdec->PrecacheModel(MODEL_COLTMAIN ); + pdec->PrecacheModel(MODEL_COLTBULLETS ); + pdec->PrecacheTexture(TEXTURE_COLTMAIN ); + pdec->PrecacheTexture(TEXTURE_COLTCOCK ); + pdec->PrecacheTexture(TEXTURE_COLTBULLETS ); + pdec->PrecacheSound(SOUND_COLT_FIRE ); + pdec->PrecacheSound(SOUND_COLT_RELOAD ); + } + + if ( ulAvailable&(1<<(WEAPON_SINGLESHOTGUN-1)) ) { + pdec->PrecacheModel(MODEL_SINGLESHOTGUN ); + pdec->PrecacheModel(MODEL_SS_SLIDER ); + pdec->PrecacheModel(MODEL_SS_HANDLE ); + pdec->PrecacheModel(MODEL_SS_BARRELS ); + pdec->PrecacheTexture(TEXTURE_SS_HANDLE ); + pdec->PrecacheTexture(TEXTURE_SS_BARRELS ); + pdec->PrecacheSound(SOUND_SINGLESHOTGUN_FIRE); + } + + if ( ulAvailable&(1<<(WEAPON_DOUBLESHOTGUN-1)) ) { + pdec->PrecacheModel(MODEL_DOUBLESHOTGUN ); + pdec->PrecacheModel(MODEL_DS_HANDLE ); + pdec->PrecacheModel(MODEL_DS_BARRELS ); + pdec->PrecacheModel(MODEL_DS_AMMO ); + pdec->PrecacheModel(MODEL_DS_SWITCH ); + pdec->PrecacheModel(MODEL_DS_HANDWITHAMMO ); + pdec->PrecacheTexture(TEXTURE_DS_HANDLE ); + pdec->PrecacheTexture(TEXTURE_DS_BARRELS ); + pdec->PrecacheTexture(TEXTURE_DS_AMMO ); + pdec->PrecacheTexture(TEXTURE_DS_SWITCH ); + pdec->PrecacheSound(SOUND_DOUBLESHOTGUN_FIRE ); + pdec->PrecacheSound(SOUND_DOUBLESHOTGUN_RELOAD ); + } + + if ( ulAvailable&(1<<(WEAPON_TOMMYGUN-1)) ) { + pdec->PrecacheModel(MODEL_TOMMYGUN ); + pdec->PrecacheModel(MODEL_TG_BODY ); + pdec->PrecacheModel(MODEL_TG_SLIDER ); + pdec->PrecacheTexture(TEXTURE_TG_BODY ); + pdec->PrecacheSound(SOUND_TOMMYGUN_FIRE ); + } + + if ( ulAvailable&(1<<(WEAPON_MINIGUN-1)) ) { + pdec->PrecacheModel(MODEL_MINIGUN ); + pdec->PrecacheModel(MODEL_MG_BARRELS ); + pdec->PrecacheModel(MODEL_MG_BODY ); + pdec->PrecacheModel(MODEL_MG_ENGINE ); + pdec->PrecacheTexture(TEXTURE_MG_BODY ); + pdec->PrecacheTexture(TEXTURE_MG_BARRELS ); + pdec->PrecacheSound(SOUND_MINIGUN_FIRE ); + pdec->PrecacheSound(SOUND_MINIGUN_ROTATE ); + pdec->PrecacheSound(SOUND_MINIGUN_SPINUP ); + pdec->PrecacheSound(SOUND_MINIGUN_SPINDOWN ); + pdec->PrecacheSound(SOUND_MINIGUN_CLICK ); + } + + if ( ulAvailable&(1<<(WEAPON_ROCKETLAUNCHER-1)) ) { + pdec->PrecacheModel(MODEL_ROCKETLAUNCHER ); + pdec->PrecacheModel(MODEL_RL_BODY ); + pdec->PrecacheModel(MODEL_RL_ROTATINGPART ); + pdec->PrecacheModel(MODEL_RL_ROCKET ); + pdec->PrecacheTexture(TEXTURE_RL_BODY ); + pdec->PrecacheTexture(TEXTURE_RL_ROCKET ); + pdec->PrecacheSound(SOUND_ROCKETLAUNCHER_FIRE); + pdec->PrecacheClass(CLASS_PROJECTILE, PRT_ROCKET); + } + + if ( ulAvailable&(1<<(WEAPON_GRENADELAUNCHER-1)) ) { + pdec->PrecacheModel(MODEL_GRENADELAUNCHER ); + pdec->PrecacheModel(MODEL_GL_BODY ); + pdec->PrecacheModel(MODEL_GL_MOVINGPART ); + pdec->PrecacheModel(MODEL_GL_GRENADE ); + pdec->PrecacheTexture(TEXTURE_GL_BODY ); + pdec->PrecacheTexture(TEXTURE_GL_MOVINGPART ); + pdec->PrecacheSound(SOUND_GRENADELAUNCHER_FIRE ); + pdec->PrecacheClass(CLASS_PROJECTILE, PRT_GRENADE); + } + +/* + if ( ulAvailable&(1<<(WEAPON_PIPEBOMB-1)) ) { + pdec->PrecacheModel(MODEL_PIPEBOMB_STICK ); + pdec->PrecacheModel(MODEL_PIPEBOMB_HAND ); + pdec->PrecacheModel(MODEL_PB_BUTTON ); + pdec->PrecacheModel(MODEL_PB_SHIELD ); + pdec->PrecacheModel(MODEL_PB_STICK ); + pdec->PrecacheModel(MODEL_PB_BOMB ); + pdec->PrecacheTexture(TEXTURE_PB_STICK ); + pdec->PrecacheTexture(TEXTURE_PB_BOMB ); + pdec->PrecacheSound(SOUND_PIPEBOMB_FIRE ); + pdec->PrecacheSound(SOUND_PIPEBOMB_OPEN ); + pdec->PrecacheSound(SOUND_PIPEBOMB_THROW ); + pdec->PrecacheClass(CLASS_PIPEBOMB); + } + + if ( ulAvailable&(1<<(WEAPON_FLAMER-1)) ) { + pdec->PrecacheModel(MODEL_FLAMER ); + pdec->PrecacheModel(MODEL_FL_BODY ); + pdec->PrecacheModel(MODEL_FL_RESERVOIR); + pdec->PrecacheModel(MODEL_FL_FLAME ); + pdec->PrecacheTexture(TEXTURE_FL_BODY ); + pdec->PrecacheTexture(TEXTURE_FL_FLAME); + pdec->PrecacheTexture(TEXTURE_FL_FUELRESERVOIR); + pdec->PrecacheSound(SOUND_FL_FIRE ); + pdec->PrecacheSound(SOUND_FL_START ); + pdec->PrecacheSound(SOUND_FL_STOP ); + pdec->PrecacheClass(CLASS_PROJECTILE, PRT_FLAME); + } +*/ + + if ( ulAvailable&(1<<(WEAPON_LASER-1)) ) { + pdec->PrecacheModel(MODEL_LASER ); + pdec->PrecacheModel(MODEL_LS_BODY ); + pdec->PrecacheModel(MODEL_LS_BARREL ); + pdec->PrecacheTexture(TEXTURE_LS_BODY ); + pdec->PrecacheTexture(TEXTURE_LS_BARREL); + pdec->PrecacheSound(SOUND_LASER_FIRE); + pdec->PrecacheClass(CLASS_PROJECTILE, PRT_LASER_RAY); + } +/* + if ( ulAvailable&(1<<(WEAPON_GHOSTBUSTER-1)) ) { + pdec->PrecacheModel(MODEL_GHOSTBUSTER ); + pdec->PrecacheModel(MODEL_GB_BODY ); + pdec->PrecacheModel(MODEL_GB_ROTATOR ); + pdec->PrecacheModel(MODEL_GB_EFFECT1 ); + pdec->PrecacheModel(MODEL_GB_EFFECT1FLARE ); + pdec->PrecacheTexture(TEXTURE_GB_ROTATOR ); + pdec->PrecacheTexture(TEXTURE_GB_BODY ); + pdec->PrecacheTexture(TEXTURE_GB_LIGHTNING); + pdec->PrecacheTexture(TEXTURE_GB_FLARE ); + pdec->PrecacheSound(SOUND_GB_FIRE ); + pdec->PrecacheClass(CLASS_GHOSTBUSTERRAY); + } + */ + if ( ulAvailable&(1<<(WEAPON_IRONCANNON-1)) /*|| + ulAvailable&(1<<(WEAPON_NUKECANNON-1))*/ ) { + pdec->PrecacheModel(MODEL_CANNON ); + pdec->PrecacheModel(MODEL_CN_BODY ); +// pdec->PrecacheModel(MODEL_CN_NUKEBOX); + pdec->PrecacheTexture(TEXTURE_CANNON); + pdec->PrecacheSound(SOUND_CANNON ); + pdec->PrecacheSound(SOUND_CANNON_PREPARE); + pdec->PrecacheClass(CLASS_CANNONBALL); + } + + // precache animator too + extern void CPlayerAnimator_Precache(ULONG ulAvailable); + CPlayerAnimator_Precache(ulAvailable); +} + +void CPlayerWeapons_Init(void) { + // declare weapon position controls + _pShell->DeclareSymbol("user INDEX wpn_iCurrent;", &wpn_iCurrent); + + #include "Common/WeaponPositions.h" + + // declare crosshair and its coordinates + _pShell->DeclareSymbol("persistent user INDEX hud_bCrosshairFixed;", &hud_bCrosshairFixed); + _pShell->DeclareSymbol("persistent user INDEX hud_bCrosshairColoring;", &hud_bCrosshairColoring); + _pShell->DeclareSymbol("persistent user FLOAT hud_fCrosshairScale;", &hud_fCrosshairScale); + _pShell->DeclareSymbol("persistent user FLOAT hud_fCrosshairRatio;", &hud_fCrosshairRatio); + _pShell->DeclareSymbol("persistent user FLOAT hud_fCrosshairOpacity;", &hud_fCrosshairOpacity); + + _pShell->DeclareSymbol("persistent user INDEX hud_bShowPlayerName;", &hud_bShowPlayerName); + _pShell->DeclareSymbol("persistent user INDEX hud_bShowCoords;", &hud_bShowCoords); + + _pShell->DeclareSymbol("persistent user FLOAT plr_tmSnoopingTime;", &plr_tmSnoopingTime); + _pShell->DeclareSymbol("persistent user FLOAT plr_tmSnoopingDelay;", &plr_tmSnoopingDelay); + + // precache base weapons + CPlayerWeapons_Precache(0x03); +} + +// weapons positions for raycasting and firing +/* +static FLOAT afKnifePos[4] = { -0.01f, 0.25f, 0.0f}; +static FLOAT afColtPos[4] = { -0.01f, 0.1f, 0.0f}; +static FLOAT afDoubleColtPos[4] = { -0.01f, 0.1f, 0.0f}; +static FLOAT afSingleShotgunPos[4] = { 0.0f, 0.1f, 0.0f}; +static FLOAT afDoubleShotgunPos[4] = { 0.0f, 0.1f, 0.0f}; +static FLOAT afTommygunPos[4] = { 0.0f, 0.1f, 0.0f}; +static FLOAT afMinigunPos[4] = { 0.0f, -0.075f, 0.0f}; +static FLOAT afRocketLauncherPos[4] = { -0.175f, 0.19f, -0.23f}; +static FLOAT afGrenadeLauncherPos[4] = { 0.0f, 0.16f, -1.42f}; +static FLOAT afPipebombPos[4] = { 0.01f, 0.04f, -0.44f}; +static FLOAT afFlamerPos[4] = { 0.0f, 0.18f, -0.62f}; +static FLOAT afLaserPos[4] = { 0.0f, -0.095f, -0.65f}; +static FLOAT afGhostBusterPos[4] = { 0.0f, 0.0f, -0.74f}; +static FLOAT afCannonPos[4] = { 0.0f, 0.0f, -0.74f}; +*/ + +// extra weapon positions for shells dropout +static FLOAT afSingleShotgunShellPos[3] = { 0.2f, 0.0f, -0.31f}; +static FLOAT afDoubleShotgunShellPos[3] = { 0.0f, 0.0f, -0.5f}; +static FLOAT afTommygunShellPos[3] = { 0.2f, 0.0f, -0.31f}; +static FLOAT afMinigunShellPos[3] = { 0.2f, 0.0f, -0.31f}; +static FLOAT afMinigunShellPos3rdView[3] = { 0.2f, 0.2f, -0.31f}; + +static FLOAT afRightColtPipe[3] = { 0.07f, -0.05f, -0.26f}; +static FLOAT afSingleShotgunPipe[3] = { 0.2f, 0.0f, -1.25f}; +static FLOAT afDoubleShotgunPipe[3] = { 0.2f, 0.0f, -1.25f}; +static FLOAT afTommygunPipe[3] = { -0.06f, 0.1f, -0.6f}; +static FLOAT afMinigunPipe[3] = { -0.06f, 0.0f, -0.6f}; +static FLOAT afMinigunPipe3rdView[3] = { 0.25f, 0.3f, -2.5f}; + +//static FLOAT afLaserPos[4] = { 0.0f, -0.095f, -0.65f}; +//static FLOAT afLaser1Pos[4] = { -0.115f, -0.05f, -0.65f}; +//static FLOAT afLaser2Pos[4] = { 0.115f, -0.05f, -0.65f}; +//static FLOAT afLaser3Pos[4] = { -0.145f, -0.14f, -0.8f}; +//static FLOAT afLaser4Pos[4] = { 0.145f, -0.14f, -0.8f}; + +#define TM_START m_aMiniGun +#define F_OFFSET_CHG m_aMiniGunLast +#define F_TEMP m_aMiniGunSpeed + +// decrement ammo taking infinite ammo options in account +void DecAmmo(INDEX &ctAmmo, INDEX iDec = 1) +{ + if (!GetSP()->sp_bInfiniteAmmo) { + ctAmmo-=iDec; + } +} +%} + +class export CPlayerWeapons : CRationalEntity { +name "Player Weapons"; +thumbnail ""; +features "CanBePredictable"; + +properties: + 1 CEntityPointer m_penPlayer, // player which owns it + 2 BOOL m_bFireWeapon = FALSE, // weapon is fireing + 3 BOOL m_bHasAmmo = FALSE, // weapon has ammo + 4 enum WeaponType m_iCurrentWeapon = WEAPON_KNIFE, // currently active weapon (internal) + 5 enum WeaponType m_iWantedWeapon = WEAPON_KNIFE, // wanted weapon (internal) + 6 enum WeaponType m_iPreviousWeapon = WEAPON_KNIFE, // previous active weapon (internal) + 11 INDEX m_iAvailableWeapons = 0x01, // avaible weapons + 12 BOOL m_bChangeWeapon = FALSE, // change current weapon + 13 BOOL m_bReloadWeapon = FALSE, // reload weapon + 14 BOOL m_bMirrorFire = FALSE, // fire with mirror model + 15 INDEX m_iAnim = 0, // temporary anim variable + 16 FLOAT m_fAnimWaitTime = 0.0f, // animation wait time + 17 FLOAT m_tmRangeSoundSpawned = 0.0f, // for not spawning range sounds too often + + 18 CTString m_strLastTarget = "", // string for last target + 19 FLOAT m_tmTargetingStarted = -99.0f, // when targeting started + 20 FLOAT m_tmLastTarget = -99.0f, // when last target was seen + 21 FLOAT m_tmSnoopingStarted = -99.0f, // is player spying another player + 22 CEntityPointer m_penTargeting, // who is the target + + 25 CModelObject m_moWeapon, // current weapon model + 26 CModelObject m_moWeaponSecond, // current weapon second (additional) model + 27 FLOAT m_tmWeaponChangeRequired = 0.0f, // time when weapon change was required + + 30 CEntityPointer m_penRayHit, // entity hit by ray + 31 FLOAT m_fRayHitDistance = 100.0f, // distance from hit point + 32 FLOAT m_fEnemyHealth = 0.0f, // normalized health of enemy in target (for coloring of crosshair) + 33 FLOAT3D m_vRayHit = FLOAT3D(0,0,0), // coordinates where ray hit + 34 FLOAT3D m_vRayHitLast = FLOAT3D(0,0,0), // for lerping + + // ammo for all weapons + 40 INDEX m_iBullets = 0, + 41 INDEX m_iMaxBullets = MAX_BULLETS, + 42 INDEX m_iShells = 0, + 43 INDEX m_iMaxShells = MAX_SHELLS, + 44 INDEX m_iRockets = 0, + 45 INDEX m_iMaxRockets = MAX_ROCKETS, + 46 INDEX m_iGrenades = 0, + 47 INDEX m_iMaxGrenades = MAX_GRENADES, +// 48 INDEX m_iNapalm = 0, +// 49 INDEX m_iMaxNapalm = MAX_NAPALM, + 50 INDEX m_iElectricity = 0, + 51 INDEX m_iMaxElectricity = MAX_ELECTRICITY, + 52 INDEX m_iIronBalls = 0, + 53 INDEX m_iMaxIronBalls = MAX_IRONBALLS, +// 54 INDEX m_iNukeBalls = 0, +// 55 INDEX m_iMaxNukeBalls = MAX_NUKEBALLS, + +// weapons specific +// knife +210 INDEX m_iKnifeStand = 1, +// colt +215 INDEX m_iColtBullets = 6, +// minigun +220 FLOAT m_aMiniGun = 0.0f, +221 FLOAT m_aMiniGunLast = 0.0f, +222 FLOAT m_aMiniGunSpeed = 0.0f, + +// lerped bullets fire +230 FLOAT3D m_iLastBulletPosition = FLOAT3D(32000.0f, 32000.0f, 32000.0f), +231 INDEX m_iBulletsOnFireStart = 0, +// pipebomb +//235 CEntityPointer m_penPipebomb, +//236 INDEX m_bPipeBombDropped = FALSE, +// flamer +//240 CEntityPointer m_penFlame, +// laser +245 INDEX m_iLaserBarrel = 0, +// ghostbuster +//250 CEntityPointer m_penGhostBusterRay, +// fire flare +251 INDEX m_iFlare = FLARE_REMOVE, // 0-none, 1-remove, 2-add +252 INDEX m_iSecondFlare = FLARE_REMOVE, // 0-none, 1-remove, 2-add +// cannon +260 FLOAT m_fWeaponDrawPowerOld = 0, +261 FLOAT m_fWeaponDrawPower = 0, +262 FLOAT m_tmDrawStartTime = 0.0f, + +{ + CEntity *penBullet; + CPlacement3D plBullet; + FLOAT3D vBulletDestination; +} + +components: + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + 2 class CLASS_BULLET "Classes\\Bullet.ecl", + 3 class CLASS_WEAPONEFFECT "Classes\\PlayerWeaponsEffects.ecl", + 4 class CLASS_PIPEBOMB "Classes\\Pipebomb.ecl", + 5 class CLASS_GHOSTBUSTERRAY "Classes\\GhostBusterRay.ecl", + 6 class CLASS_CANNONBALL "Classes\\CannonBall.ecl", + 7 class CLASS_WEAPONITEM "Classes\\WeaponItem.ecl", + +// ************** HAND ************** + 10 texture TEXTURE_HAND "Models\\Weapons\\Hand.tex", + +// ************** KNIFE ************** + 20 model MODEL_KNIFEITEM "Models\\Weapons\\Knife\\KnifeItem.mdl", + 21 texture TEXTURE_KNIFEITEM "Models\\Weapons\\Knife\\KnifeItem.tex", + 22 model MODEL_KNIFE "Models\\Weapons\\Knife\\Knife.mdl", + 23 sound SOUND_KNIFE_BACK "Models\\Weapons\\Knife\\Sounds\\Back.wav", + 24 sound SOUND_KNIFE_HIGH "Models\\Weapons\\Knife\\Sounds\\High.wav", + 25 sound SOUND_KNIFE_LONG "Models\\Weapons\\Knife\\Sounds\\Long.wav", + 26 sound SOUND_KNIFE_LOW "Models\\Weapons\\Knife\\Sounds\\Low.wav", + +// ************** COLT ************** + 30 model MODEL_COLT "Models\\Weapons\\Colt\\Colt.mdl", + 31 model MODEL_COLTCOCK "Models\\Weapons\\Colt\\ColtCock.mdl", + 32 model MODEL_COLTMAIN "Models\\Weapons\\Colt\\ColtMain.mdl", + 33 model MODEL_COLTBULLETS "Models\\Weapons\\Colt\\ColtBullets.mdl", + 34 texture TEXTURE_COLTMAIN "Models\\Weapons\\Colt\\ColtMain.tex", + 35 texture TEXTURE_COLTCOCK "Models\\Weapons\\Colt\\ColtCock.tex", + 36 texture TEXTURE_COLTBULLETS "Models\\Weapons\\Colt\\ColtBullets.tex", + 37 sound SOUND_COLT_FIRE "Models\\Weapons\\Colt\\Sounds\\Fire.wav", + 38 sound SOUND_COLT_RELOAD "Models\\Weapons\\Colt\\Sounds\\Reload.wav", + +// ************** SINGLE SHOTGUN ************ + 40 model MODEL_SINGLESHOTGUN "Models\\Weapons\\SingleShotgun\\SingleShotgun.mdl", + 41 model MODEL_SS_SLIDER "Models\\Weapons\\SingleShotgun\\Slider.mdl", + 42 model MODEL_SS_HANDLE "Models\\Weapons\\SingleShotgun\\Handle.mdl", + 43 model MODEL_SS_BARRELS "Models\\Weapons\\SingleShotgun\\Barrels.mdl", + 44 texture TEXTURE_SS_HANDLE "Models\\Weapons\\SingleShotgun\\Handle.tex", + 45 texture TEXTURE_SS_BARRELS "Models\\Weapons\\SingleShotgun\\Barrels.tex", + 46 sound SOUND_SINGLESHOTGUN_FIRE "Models\\Weapons\\SingleShotgun\\Sounds\\_Fire.wav", + +// ************** DOUBLE SHOTGUN ************** + 50 model MODEL_DOUBLESHOTGUN "Models\\Weapons\\DoubleShotgun\\DoubleShotgun.mdl", + 51 model MODEL_DS_HANDLE "Models\\Weapons\\DoubleShotgun\\Dshotgunhandle.mdl", + 52 model MODEL_DS_BARRELS "Models\\Weapons\\DoubleShotgun\\Dshotgunbarrels.mdl", + 53 model MODEL_DS_AMMO "Models\\Weapons\\DoubleShotgun\\Ammo.mdl", + 54 model MODEL_DS_SWITCH "Models\\Weapons\\DoubleShotgun\\Switch.mdl", + 55 model MODEL_DS_HANDWITHAMMO "Models\\Weapons\\DoubleShotgun\\HandWithAmmo.mdl", + 56 texture TEXTURE_DS_HANDLE "Models\\Weapons\\DoubleShotgun\\Handle.tex", + 57 texture TEXTURE_DS_BARRELS "Models\\Weapons\\DoubleShotgun\\Barrels.tex", + 58 texture TEXTURE_DS_AMMO "Models\\Weapons\\DoubleShotgun\\Ammo.tex", + 59 texture TEXTURE_DS_SWITCH "Models\\Weapons\\DoubleShotgun\\Switch.tex", + 60 sound SOUND_DOUBLESHOTGUN_FIRE "Models\\Weapons\\DoubleShotgun\\Sounds\\Fire.wav", + 61 sound SOUND_DOUBLESHOTGUN_RELOAD "Models\\Weapons\\DoubleShotgun\\Sounds\\Reload.wav", + +// ************** TOMMYGUN ************** + 70 model MODEL_TOMMYGUN "Models\\Weapons\\TommyGun\\TommyGun.mdl", + 71 model MODEL_TG_BODY "Models\\Weapons\\TommyGun\\Body.mdl", + 72 model MODEL_TG_SLIDER "Models\\Weapons\\TommyGun\\Slider.mdl", + 73 texture TEXTURE_TG_BODY "Models\\Weapons\\TommyGun\\Body.tex", + 74 sound SOUND_TOMMYGUN_FIRE "Models\\Weapons\\TommyGun\\Sounds\\_Fire.wav", + +// ************** MINIGUN ************** + 80 model MODEL_MINIGUN "Models\\Weapons\\MiniGun\\MiniGun.mdl", + 81 model MODEL_MG_BARRELS "Models\\Weapons\\MiniGun\\Barrels.mdl", + 82 model MODEL_MG_BODY "Models\\Weapons\\MiniGun\\Body.mdl", + 83 model MODEL_MG_ENGINE "Models\\Weapons\\MiniGun\\Engine.mdl", + 84 texture TEXTURE_MG_BODY "Models\\Weapons\\MiniGun\\Body.tex", + 99 texture TEXTURE_MG_BARRELS "Models\\Weapons\\MiniGun\\Barrels.tex", + 85 sound SOUND_MINIGUN_FIRE "Models\\Weapons\\MiniGun\\Sounds\\Fire.wav", + 86 sound SOUND_MINIGUN_ROTATE "Models\\Weapons\\MiniGun\\Sounds\\Rotate.wav", + 87 sound SOUND_MINIGUN_SPINUP "Models\\Weapons\\MiniGun\\Sounds\\RotateUp.wav", + 88 sound SOUND_MINIGUN_SPINDOWN "Models\\Weapons\\MiniGun\\Sounds\\RotateDown.wav", + 89 sound SOUND_MINIGUN_CLICK "Models\\Weapons\\MiniGun\\Sounds\\Click.wav", + +// ************** ROCKET LAUNCHER ************** + 90 model MODEL_ROCKETLAUNCHER "Models\\Weapons\\RocketLauncher\\RocketLauncher.mdl", + 91 model MODEL_RL_BODY "Models\\Weapons\\RocketLauncher\\Body.mdl", + 92 texture TEXTURE_RL_BODY "Models\\Weapons\\RocketLauncher\\Body.tex", + 93 model MODEL_RL_ROTATINGPART "Models\\Weapons\\RocketLauncher\\RotatingPart.mdl", + 94 texture TEXTURE_RL_ROTATINGPART "Models\\Weapons\\RocketLauncher\\RotatingPart.tex", + 95 model MODEL_RL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.mdl", + 96 texture TEXTURE_RL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.tex", + 97 sound SOUND_ROCKETLAUNCHER_FIRE "Models\\Weapons\\RocketLauncher\\Sounds\\_Fire.wav", + +// ************** GRENADE LAUNCHER ************** +100 model MODEL_GRENADELAUNCHER "Models\\Weapons\\GrenadeLauncher\\GrenadeLauncher.mdl", +101 model MODEL_GL_BODY "Models\\Weapons\\GrenadeLauncher\\Body.mdl", +102 model MODEL_GL_MOVINGPART "Models\\Weapons\\GrenadeLauncher\\MovingPipe.mdl", +103 model MODEL_GL_GRENADE "Models\\Weapons\\GrenadeLauncher\\GrenadeBack.mdl", +104 texture TEXTURE_GL_BODY "Models\\Weapons\\GrenadeLauncher\\Body.tex", +105 texture TEXTURE_GL_MOVINGPART "Models\\Weapons\\GrenadeLauncher\\MovingPipe.tex", +106 sound SOUND_GRENADELAUNCHER_FIRE "Models\\Weapons\\GrenadeLauncher\\Sounds\\_Fire.wav", + +/* +// ************** PIPEBOMB ************** +110 model MODEL_PIPEBOMB_STICK "Models\\Weapons\\Pipebomb\\HandWithStick.mdl", +111 model MODEL_PIPEBOMB_HAND "Models\\Weapons\\Pipebomb\\HandWithBomb.mdl", +112 model MODEL_PB_BUTTON "Models\\Weapons\\Pipebomb\\Button.mdl", +113 model MODEL_PB_SHIELD "Models\\Weapons\\Pipebomb\\Shield.mdl", +114 model MODEL_PB_STICK "Models\\Weapons\\Pipebomb\\Stick.mdl", +115 model MODEL_PB_BOMB "Models\\Weapons\\Pipebomb\\Bomb.mdl", +116 texture TEXTURE_PB_STICK "Models\\Weapons\\Pipebomb\\Stick.tex", +117 texture TEXTURE_PB_BOMB "Models\\Weapons\\Pipebomb\\Bomb.tex", +118 sound SOUND_PIPEBOMB_FIRE "Models\\Weapons\\Pipebomb\\Sounds\\Fire.wav", +119 sound SOUND_PIPEBOMB_OPEN "Models\\Weapons\\Pipebomb\\Sounds\\Open.wav", +120 sound SOUND_PIPEBOMB_THROW "Models\\Weapons\\Pipebomb\\Sounds\\Throw.wav", + +// ************** FLAMER ************** +130 model MODEL_FLAMER "Models\\Weapons\\Flamer\\Flamer.mdl", +131 model MODEL_FL_BODY "Models\\Weapons\\Flamer\\Body.mdl", +132 model MODEL_FL_RESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.mdl", +133 model MODEL_FL_FLAME "Models\\Weapons\\Flamer\\Flame.mdl", +134 texture TEXTURE_FL_BODY "Models\\Weapons\\Flamer\\Body.tex", +135 texture TEXTURE_FL_FLAME "Models\\Weapons\\Flamer\\Flame.tex", +136 sound SOUND_FL_FIRE "Models\\Weapons\\Flamer\\Sounds\\_Fire.wav", +137 sound SOUND_FL_START "Models\\Weapons\\Flamer\\Sounds\\Start.wav", +138 sound SOUND_FL_STOP "Models\\Weapons\\Flamer\\Sounds\\Stop.wav", +139 texture TEXTURE_FL_FUELRESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.tex", +*/ + +// ************** LASER ************** +140 model MODEL_LASER "Models\\Weapons\\Laser\\Laser.mdl", +141 model MODEL_LS_BODY "Models\\Weapons\\Laser\\Body.mdl", +142 model MODEL_LS_BARREL "Models\\Weapons\\Laser\\Barrel.mdl", +144 texture TEXTURE_LS_BODY "Models\\Weapons\\Laser\\Body.tex", +145 texture TEXTURE_LS_BARREL "Models\\Weapons\\Laser\\Barrel.tex", +146 sound SOUND_LASER_FIRE "Models\\Weapons\\Laser\\Sounds\\_Fire.wav", +/* +// ************** GHOSTBUSTER ************** +150 model MODEL_GHOSTBUSTER "Models\\Weapons\\GhostBuster\\GhostBuster.mdl", +151 model MODEL_GB_BODY "Models\\Weapons\\GhostBuster\\Body.mdl", +152 model MODEL_GB_ROTATOR "Models\\Weapons\\GhostBuster\\Rotator.mdl", +153 model MODEL_GB_EFFECT1 "Models\\Weapons\\GhostBuster\\Effect01.mdl", +154 model MODEL_GB_EFFECT1FLARE "Models\\Weapons\\GhostBuster\\EffectFlare01.mdl", +155 texture TEXTURE_GB_ROTATOR "Models\\Weapons\\GhostBuster\\Rotator.tex", +156 texture TEXTURE_GB_BODY "Models\\Weapons\\GhostBuster\\Body.tex", +157 texture TEXTURE_GB_LIGHTNING "Models\\Weapons\\GhostBuster\\Lightning.tex", +158 texture TEXTURE_GB_FLARE "Models\\Weapons\\GhostBuster\\EffectFlare.tex", +159 sound SOUND_GB_FIRE "Models\\Weapons\\GhostBuster\\Sounds\\_Fire.wav", +*/ +// ************** CANNON ************** +170 model MODEL_CANNON "Models\\Weapons\\Cannon\\Cannon.mdl", +171 model MODEL_CN_BODY "Models\\Weapons\\Cannon\\Body.mdl", +//172 model MODEL_CN_NUKEBOX "Models\\Weapons\\Cannon\\NukeBox.mdl", +173 texture TEXTURE_CANNON "Models\\Weapons\\Cannon\\Body.tex", +174 sound SOUND_CANNON "Models\\Weapons\\Cannon\\Sounds\\Fire.wav", +175 sound SOUND_CANNON_PREPARE "Models\\Weapons\\Cannon\\Sounds\\Prepare.wav", +//175 model MODEL_CN_LIGHT "Models\\Weapons\\Cannon\\Light.mdl", + +// ************** REFLECTIONS ************** +200 texture TEX_REFL_BWRIPLES01 "Models\\ReflectionTextures\\BWRiples01.tex", +201 texture TEX_REFL_BWRIPLES02 "Models\\ReflectionTextures\\BWRiples02.tex", +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", +203 texture TEX_REFL_LIGHTBLUEMETAL01 "Models\\ReflectionTextures\\LightBlueMetal01.tex", +204 texture TEX_REFL_DARKMETAL "Models\\ReflectionTextures\\DarkMetal.tex", +205 texture TEX_REFL_PURPLE01 "Models\\ReflectionTextures\\Purple01.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + +// ************** FLARES ************** +250 model MODEL_FLARE01 "Models\\Effects\\Weapons\\Flare01\\Flare.mdl", +251 texture TEXTURE_FLARE01 "Models\\Effects\\Weapons\\Flare01\\Flare.tex", + +280 sound SOUND_SILENCE "Sounds\\Misc\\Silence.wav", + + +functions: + // add to prediction any entities that this entity depends on + void AddDependentsToPrediction(void) + { + m_penPlayer->AddToPrediction(); +// m_penPipebomb->AddToPrediction(); +// m_penGhostBusterRay->AddToPrediction(); +// m_penFlame->AddToPrediction(); + } + void Precache(void) + { + CPlayerWeapons_Precache(m_iAvailableWeapons); + } + CPlayer *GetPlayer(void) + { + ASSERT(m_penPlayer!=NULL); + return (CPlayer *)&*m_penPlayer; + } + CPlayerAnimator *GetAnimator(void) + { + ASSERT(m_penPlayer!=NULL); + return ((CPlayerAnimator*)&*((CPlayer&)*m_penPlayer).m_penAnimator); + } + + // recoil + void DoRecoil(void) + { +// CPlayerAnimator &plan = (CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator; +// plan.m_fRecoilSpeed += wpn_fRecoilSpeed[m_iCurrentWeapon]; + } + + // + BOOL HoldingFire(void) + { + return m_bFireWeapon && !m_bChangeWeapon; + } + + + // render weapon model(s) + void RenderWeaponModel( CPerspectiveProjection3D &prProjection, CDrawPort *pdp, + FLOAT3D vViewerLightDirection, COLOR colViewerLight, COLOR colViewerAmbient, + BOOL bRender) + { + _mrpModelRenderPrefs.SetRenderType( RT_TEXTURE|RT_SHADING_PHONG); + + // flare attachment + ControlFlareAttachment(); + + if( !bRender || m_iCurrentWeapon==WEAPON_NONE + || GetPlayer()->GetSettings()->ps_ulFlags&PSF_HIDEWEAPON) { return; } + + // nuke and iron cannons have the same view settings + INDEX iWeaponData = m_iCurrentWeapon; +// if( iWeaponData==WEAPON_NUKECANNON) { iWeaponData = WEAPON_IRONCANNON; } + + // store FOV for Crosshair + const FLOAT fFOV = ((CPerspectiveProjection3D &)prProjection).FOVL(); + CPlacement3D plView; + plView = ((CPlayer&)*m_penPlayer).en_plViewpoint; + plView.RelativeToAbsolute(m_penPlayer->GetPlacement()); + + CPlacement3D plWeapon( FLOAT3D(wpn_fX[iWeaponData], wpn_fY[iWeaponData], wpn_fZ[iWeaponData]), + ANGLE3D(AngleDeg(wpn_fH[iWeaponData]), AngleDeg(wpn_fP[iWeaponData]), + AngleDeg(wpn_fB[iWeaponData]))); + + // make sure that weapon will be bright enough + UBYTE ubLR,ubLG,ubLB, ubAR,ubAG,ubAB; + ColorToRGB( colViewerLight, ubLR,ubLG,ubLB); + ColorToRGB( colViewerAmbient, ubAR,ubAG,ubAB); + INDEX iMinDL = Min( Min(ubLR,ubLG),ubLB) -32; + INDEX iMinDA = Min( Min(ubAR,ubAG),ubAB) -32; + if( iMinDL<0) { + ubLR = ClampUp( ubLR-iMinDL, (INDEX)255); + ubLG = ClampUp( ubLG-iMinDL, (INDEX)255); + ubLB = ClampUp( ubLB-iMinDL, (INDEX)255); + } + if( iMinDA<0) { + ubAR = ClampUp( ubAR-iMinDA, (INDEX)255); + ubAG = ClampUp( ubAG-iMinDA, (INDEX)255); + ubAB = ClampUp( ubAB-iMinDA, (INDEX)255); + } + const COLOR colLight = RGBToColor( ubLR,ubLG,ubLB); + const COLOR colAmbient = RGBToColor( ubAR,ubAG,ubAB); + + // DRAW WEAPON MODEL + // Double colt - second colt in mirror + // Double shotgun - hand with ammo + // Pipebomb - left hand (mirror) with stick + if( iWeaponData==WEAPON_DOUBLECOLT || iWeaponData==WEAPON_DOUBLESHOTGUN /*|| iWeaponData==WEAPON_PIPEBOMB*/) + { + // prepare render model structure and projection + CRenderModel rmMain; + CPerspectiveProjection3D prMirror = prProjection; + prMirror.ViewerPlacementL() = plView; + prMirror.FrontClipDistanceL() = wpn_fClip[iWeaponData]; + prMirror.DepthBufferNearL() = 0.0f; + prMirror.DepthBufferFarL() = 0.1f; + CPlacement3D plWeaponMirror( FLOAT3D(wpn_fX[iWeaponData], wpn_fY[iWeaponData], wpn_fZ[iWeaponData]), + ANGLE3D(AngleDeg(wpn_fH[iWeaponData]), AngleDeg(wpn_fP[iWeaponData]), + AngleDeg(wpn_fB[iWeaponData]))); + if( iWeaponData==WEAPON_DOUBLECOLT /*|| iWeaponData==WEAPON_PIPEBOMB*/) { + FLOATmatrix3D mRotation; + MakeRotationMatrixFast(mRotation, plView.pl_OrientationAngle); + plWeaponMirror.pl_PositionVector(1) = -plWeaponMirror.pl_PositionVector(1); + plWeaponMirror.pl_OrientationAngle(1) = -plWeaponMirror.pl_OrientationAngle(1); + plWeaponMirror.pl_OrientationAngle(3) = -plWeaponMirror.pl_OrientationAngle(3); + } + ((CPerspectiveProjection3D &)prMirror).FOVL() = AngleDeg(wpn_fFOV[iWeaponData]); + CAnyProjection3D apr; + apr = prMirror; + BeginModelRenderingView(apr, pdp); + + WeaponMovingOffset(plWeaponMirror.pl_PositionVector); + plWeaponMirror.RelativeToAbsoluteSmooth(plView); + rmMain.SetObjectPlacement(plWeaponMirror); + + rmMain.rm_colLight = colLight; + rmMain.rm_colAmbient = colAmbient; + rmMain.rm_vLightDirection = vViewerLightDirection; + rmMain.rm_ulFlags |= RMF_WEAPON; // TEMP: for Truform + + m_moWeaponSecond.SetupModelRendering(rmMain); + m_moWeaponSecond.RenderModel(rmMain); + EndModelRenderingView(); + } + + // minigun specific (update rotation) + if( iWeaponData==WEAPON_MINIGUN) { RotateMinigun(); } + + // prepare render model structure + CRenderModel rmMain; + prProjection.ViewerPlacementL() = plView; + prProjection.FrontClipDistanceL() = wpn_fClip[iWeaponData]; + prProjection.DepthBufferNearL() = 0.0f; + prProjection.DepthBufferFarL() = 0.1f; + ((CPerspectiveProjection3D &)prProjection).FOVL() = AngleDeg(wpn_fFOV[iWeaponData]); + + CAnyProjection3D apr; + apr = prProjection; + BeginModelRenderingView(apr, pdp); + + WeaponMovingOffset(plWeapon.pl_PositionVector); + plWeapon.RelativeToAbsoluteSmooth(plView); + rmMain.SetObjectPlacement(plWeapon); + + rmMain.rm_colLight = colLight; + rmMain.rm_colAmbient = colAmbient; + rmMain.rm_vLightDirection = vViewerLightDirection; + rmMain.rm_ulFlags |= RMF_WEAPON; // TEMP: for Truform + + m_moWeapon.SetupModelRendering(rmMain); + m_moWeapon.RenderModel(rmMain); + EndModelRenderingView(); + + // restore FOV for Crosshair + ((CPerspectiveProjection3D &)prProjection).FOVL() = fFOV; + }; + + + // Weapon moving offset + void WeaponMovingOffset(FLOAT3D &plPos) + { + CPlayerAnimator &plan = (CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator; + FLOAT fXOffset = Lerp(plan.m_fMoveLastBanking, plan.m_fMoveBanking, _pTimer->GetLerpFactor()) * -0.02f; + FLOAT fYOffset = Lerp(plan.m_fWeaponYLastOffset, plan.m_fWeaponYOffset, _pTimer->GetLerpFactor()) * 0.15f; + fYOffset += (fXOffset * fXOffset) * 30.0f; + plPos(1) += fXOffset; + plPos(2) += fYOffset; + // apply grenade launcher pumping + if( m_iCurrentWeapon == WEAPON_GRENADELAUNCHER) + { + // obtain moving part attachment + CAttachmentModelObject *amo = m_moWeapon.GetAttachmentModel(GRENADELAUNCHER_ATTACHMENT_MOVING_PART); + FLOAT fLerpedMovement = Lerp(m_fWeaponDrawPowerOld, m_fWeaponDrawPower, _pTimer->GetLerpFactor()); + amo->amo_plRelative.pl_PositionVector(3) = fLerpedMovement; + plPos(3) += fLerpedMovement/2.0f; + if( m_tmDrawStartTime != 0.0f) + { + FLOAT tmPassed = _pTimer->GetLerpedCurrentTick()-m_tmDrawStartTime; + plPos(1) += Sin(tmPassed*360.0f*10)*0.0125f*tmPassed/6.0f; + plPos(2) += Sin(tmPassed*270.0f*8)*0.01f*tmPassed/6.0f; + } + } + // apply cannon draw + else if( (m_iCurrentWeapon == WEAPON_IRONCANNON) /*|| + (m_iCurrentWeapon == WEAPON_NUKECANNON) */) + { + FLOAT fLerpedMovement = Lerp(m_fWeaponDrawPowerOld, m_fWeaponDrawPower, _pTimer->GetLerpFactor()); + plPos(3) += fLerpedMovement; + if( m_tmDrawStartTime != 0.0f) + { + FLOAT tmPassed = _pTimer->GetLerpedCurrentTick()-m_tmDrawStartTime; + plPos(1) += Sin(tmPassed*360.0f*10)*0.0125f*tmPassed/2.0f; + plPos(2) += Sin(tmPassed*270.0f*8)*0.01f*tmPassed/2.0f; + } + } + }; + + // check target for time prediction updating + void CheckTargetPrediction(CEntity *penTarget) + { + // if target is not predictable + if (!penTarget->IsPredictable()) { + // do nothing + return; + } + + extern FLOAT cli_tmPredictFoe; + extern FLOAT cli_tmPredictAlly; + extern FLOAT cli_tmPredictEnemy; + + // get your and target's bases for prediction + CEntity *penMe = GetPlayer(); + if (IsPredictor()) { + penMe = penMe->GetPredicted(); + } + CEntity *penYou = penTarget; + if (penYou->IsPredictor()) { + penYou = penYou->GetPredicted(); + } + + // if player + if (IsOfClass(penYou, "Player")) { + // if ally player + if (GetSP()->sp_bCooperative) { + // if ally prediction is on and this player is local + if (cli_tmPredictAlly>0 && _pNetwork->IsPlayerLocal(penMe)) { + // predict the ally + penYou->SetPredictionTime(cli_tmPredictAlly); + } + // if foe player + } else { + // if foe prediction is on + if (cli_tmPredictFoe>0) { + // if this player is local + if (_pNetwork->IsPlayerLocal(penMe)) { + // predict the foe + penYou->SetPredictionTime(cli_tmPredictFoe); + } + // if the target is local + if (_pNetwork->IsPlayerLocal(penYou)) { + // predict self + penMe->SetPredictionTime(cli_tmPredictFoe); + } + } + } + } else { + // if enemy prediction is on an it is an enemy + if( cli_tmPredictEnemy>0 && IsDerivedFromClass( penYou, "Enemy Base")) { + // if this player is local + if (_pNetwork->IsPlayerLocal(penMe)) { + // set enemy prediction time + penYou->SetPredictionTime(cli_tmPredictEnemy); + } + } + } + } + + // cast a ray from weapon + void UpdateTargetingInfo(void) + { + // crosshair start position from weapon + CPlacement3D plCrosshair; + FLOAT fFX = wpn_fFX[m_iCurrentWeapon]; // get weapon firing position + FLOAT fFY = wpn_fFY[m_iCurrentWeapon]; + if (GetPlayer()->m_iViewState == PVT_3RDPERSONVIEW) { + fFX = fFY = 0; + } + CalcWeaponPosition(FLOAT3D(fFX, fFY, 0), plCrosshair, FALSE); + // cast ray + CCastRay crRay( m_penPlayer, plCrosshair); + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_bPhysical = FALSE; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + GetWorld()->CastRay(crRay); + // store required cast ray results + m_vRayHitLast = m_vRayHit; // for lerping purposes + m_vRayHit = crRay.cr_vHit; + m_penRayHit = crRay.cr_penHit; + m_fRayHitDistance = crRay.cr_fHitDistance; + m_fEnemyHealth = 0.0f; + + // set some targeting properties (snooping and such...) + TIME tmNow = _pTimer->CurrentTick(); + if( m_penRayHit!=NULL) + { + CEntity *pen = m_penRayHit; + // if alive + if( pen->GetFlags()&ENF_ALIVE) + { + // check the target for time prediction updating + CheckTargetPrediction(pen); + + // if player + if( IsOfClass( pen, "Player")) { + // rememer when targeting begun + if( m_tmTargetingStarted==0) { + m_penTargeting = pen; + m_tmTargetingStarted = tmNow; + } + // keep player name, mana and health for eventual printout or coloring + m_fEnemyHealth = ((CPlayer*)pen)->GetHealth() / ((CPlayer*)pen)->m_fMaxHealth; + m_strLastTarget.PrintF( "%s", (const char*)((CPlayer*)pen)->GetPlayerName()); + if( GetSP()->sp_gmGameMode==CSessionProperties::GM_SCOREMATCH) { + // add mana to player name + CTString strMana=""; + strMana.PrintF( " (%d)", ((CPlayer*)pen)->m_iMana); + m_strLastTarget += strMana; + } + if( hud_bShowPlayerName) { m_tmLastTarget = tmNow+1.5f; } + } + // not targeting player + else { + // reset targeting + m_tmTargetingStarted = 0; + } + // keep enemy health for eventual crosshair coloring + if( IsDerivedFromClass( pen, "Enemy Base")) { + m_fEnemyHealth = ((CEnemyBase*)pen)->GetHealth() / ((CEnemyBase*)pen)->m_fMaxHealth; + } + // cannot snoop while firing + if( m_bFireWeapon) { m_tmTargetingStarted = 0; } + } + // if not alive + else + { + // not targeting player + m_tmTargetingStarted = 0; + + // check switch relaying by moving brush + if( IsOfClass( pen, "Moving Brush") && ((CMovingBrush&)*pen).m_penSwitch!=NULL) { + pen = ((CMovingBrush&)*pen).m_penSwitch; + } + // if switch and near enough + if( IsOfClass( pen, "Switch") && m_fRayHitDistance<2.0f) { + CSwitch &enSwitch = (CSwitch&)*pen; + // if switch is useable + if( enSwitch.m_bUseable) { + // show switch message + if( enSwitch.m_strMessage!="") { m_strLastTarget = enSwitch.m_strMessage; } + else { m_strLastTarget = TRANS("Use"); } + m_tmLastTarget = tmNow+0.5f; + } + } + // if analyzable + if( IsOfClass( pen, "MessageHolder") + && m_fRayHitDistance < ((CMessageHolder*)&*pen)->m_fDistance + && ((CMessageHolder*)&*pen)->m_bActive) { + const CTFileName &fnmMessage = ((CMessageHolder*)&*pen)->m_fnmMessage; + // if player doesn't have that message it database + CPlayer &pl = (CPlayer&)*m_penPlayer; + if( !pl.HasMessage(fnmMessage)) { + // show analyse message + m_strLastTarget = TRANS("Analyze"); + m_tmLastTarget = tmNow+0.5f; + } + } + } + } + // if didn't hit anything + else { + // not targeting player + m_tmTargetingStarted = 0; + // remember position ahead + FLOAT3D vDir = crRay.cr_vTarget-crRay.cr_vOrigin; + vDir.Normalize(); + m_vRayHit = crRay.cr_vOrigin+vDir*50.0f; + } + + // determine snooping time + TIME tmDelta = tmNow - m_tmTargetingStarted; + if( m_tmTargetingStarted>0 && plr_tmSnoopingDelay>0 && tmDelta>plr_tmSnoopingDelay) { + m_tmSnoopingStarted = tmNow; + } + } + + + + // Render Crosshair + void RenderCrosshair( CProjection3D &prProjection, CDrawPort *pdp, CPlacement3D &plViewSource) + { + INDEX iCrossHair = GetPlayer()->GetSettings()->ps_iCrossHairType+1; + + // adjust crosshair type + if( iCrossHair<=0) { + iCrossHair = 0; + _iLastCrosshairType = 0; + } + + // create new crosshair texture (if needed) + if( _iLastCrosshairType != iCrossHair) { + _iLastCrosshairType = iCrossHair; + CTString fnCrosshair; + fnCrosshair.PrintF( "Textures\\Interface\\Crosshairs\\Crosshair%d.tex", iCrossHair); + try { + // load new crosshair texture + _toCrosshair.SetData_t( fnCrosshair); + } catch( char *strError) { + // didn't make it! - reset crosshair + CPrintF( strError); + iCrossHair = 0; + return; + } + } + COLOR colCrosshair = C_WHITE; + TIME tmNow = _pTimer->CurrentTick(); + + // if hit anything + FLOAT3D vOnScreen; + FLOAT fDistance = m_fRayHitDistance; + //const FLOAT3D vRayHit = Lerp( m_vRayHitLast, m_vRayHit, _pTimer->GetLerpFactor()); + const FLOAT3D vRayHit = m_vRayHit; // lerping doesn't seem to work ??? + // if hit anything + if( m_penRayHit!=NULL) { + + CEntity *pen = m_penRayHit; + // do screen projection + prProjection.ViewerPlacementL() = plViewSource; + prProjection.ObjectPlacementL() = CPlacement3D( FLOAT3D(0.0f, 0.0f, 0.0f), ANGLE3D( 0, 0, 0)); + prProjection.Prepare(); + prProjection.ProjectCoordinate( vRayHit, vOnScreen); + // if required, show enemy health thru crosshair color + if( hud_bCrosshairColoring && m_fEnemyHealth>0) { + if( m_fEnemyHealth<0.25f) { colCrosshair = C_RED; } + else if( m_fEnemyHealth<0.60f) { colCrosshair = C_YELLOW; } + else { colCrosshair = C_GREEN; } + } + } + // if didn't hit anything + else + { + // far away in screen center + vOnScreen(1) = (FLOAT)pdp->GetWidth() *0.5f; + vOnScreen(2) = (FLOAT)pdp->GetHeight() *0.5f; + fDistance = 100.0f; + } + + // if croshair should be of fixed position + if( hud_bCrosshairFixed || GetPlayer()->m_iViewState == PVT_3RDPERSONVIEW) { + // reset it to screen center + vOnScreen(1) = (FLOAT)pdp->GetWidth() *0.5f; + vOnScreen(2) = (FLOAT)pdp->GetHeight() *0.5f; + //fDistance = 100.0f; + } + + // clamp console variables + hud_fCrosshairScale = Clamp( hud_fCrosshairScale, 0.1f, 2.0f); + hud_fCrosshairRatio = Clamp( hud_fCrosshairRatio, 0.1f, 1.0f); + hud_fCrosshairOpacity = Clamp( hud_fCrosshairOpacity, 0.1f, 1.0f); + const ULONG ulAlpha = NormFloatToByte( hud_fCrosshairOpacity); + // draw crosshair if needed + if( iCrossHair>0) { + // determine crosshair size + const FLOAT fMinD = 1.0f; + const FLOAT fMaxD = 100.0f; + fDistance = Clamp( fDistance, fMinD, fMaxD); + const FLOAT fRatio = (fDistance-fMinD) / (fMaxD-fMinD); + const FLOAT fMaxSize = (FLOAT)pdp->GetWidth() / 640.0f; + const FLOAT fMinSize = fMaxSize * hud_fCrosshairRatio; + const FLOAT fSize = 16 * Lerp( fMaxSize, fMinSize, fRatio) * hud_fCrosshairScale; + // draw crosshair + const FLOAT fI0 = + (PIX)vOnScreen(1) - fSize; + const FLOAT fI1 = + (PIX)vOnScreen(1) + fSize; + const FLOAT fJ0 = - (PIX)vOnScreen(2) - fSize +pdp->GetHeight(); + const FLOAT fJ1 = - (PIX)vOnScreen(2) + fSize +pdp->GetHeight(); + pdp->InitTexture( &_toCrosshair); + pdp->AddTexture( fI0, fJ0, fI1, fJ1, colCrosshair|ulAlpha); + pdp->FlushRenderingQueue(); + } + + // if there is still time + TIME tmDelta = m_tmLastTarget - tmNow; + if( tmDelta>0) { + // printout current target info + SLONG slDPWidth = pdp->GetWidth(); + SLONG slDPHeight = pdp->GetHeight(); + FLOAT fScaling = (FLOAT)slDPWidth/640.0f; + // set font and scale + pdp->SetFont( _pfdDisplayFont); + pdp->SetTextScaling( fScaling); + pdp->SetTextAspect( 1.0f); + // do faded printout + ULONG ulA = (FLOAT)ulAlpha * Clamp( 2*tmDelta, 0.0f, 1.0f); + pdp->PutTextC( m_strLastTarget, slDPWidth*0.5f, slDPHeight*0.75f, C_lGREEN|ulA); + } + + // printout crosshair world coordinates if needed + if( hud_bShowCoords) { + CTString strCoords; + SLONG slDPWidth = pdp->GetWidth(); + SLONG slDPHeight = pdp->GetHeight(); + // set font and scale + pdp->SetFont( _pfdDisplayFont); + pdp->SetTextAspect( 1.0f); + pdp->SetTextScaling( (FLOAT)slDPWidth/640.0f); + // do printout only if coordinates are valid + const FLOAT fMax = Max( Max( vRayHit(1), vRayHit(2)), vRayHit(3)); + const FLOAT fMin = Min( Min( vRayHit(1), vRayHit(2)), vRayHit(3)); + if( fMax<+100000 && fMin>-100000) { + strCoords.PrintF( "%.0f,%.0f,%.0f", vRayHit(1), vRayHit(2), vRayHit(3)); + pdp->PutTextC( strCoords, slDPWidth*0.5f, slDPHeight*0.10f, C_WHITE|CT_OPAQUE); + } + } + }; + + + +/************************************************************ + * FIRE FLARE * + ************************************************************/ + // show flare + void ShowFlare(CModelObject &moWeapon, INDEX iAttachObject, INDEX iAttachFlare, FLOAT fSize) { + CModelObject *pmo = &(moWeapon.GetAttachmentModel(iAttachObject)->amo_moModelObject); + CAttachmentModelObject *pamo = pmo->GetAttachmentModel(iAttachFlare); + pamo->amo_plRelative.pl_OrientationAngle(3) = (rand()*360.0f)/RAND_MAX; + pmo = &(pamo->amo_moModelObject); + pmo->StretchModel(FLOAT3D(fSize, fSize, fSize)); + }; + + + // hide flare + void HideFlare(CModelObject &moWeapon, INDEX iAttachObject, INDEX iAttachFlare) { + CModelObject *pmo = &(moWeapon.GetAttachmentModel(iAttachObject)->amo_moModelObject); + pmo = &(pmo->GetAttachmentModel(iAttachFlare)->amo_moModelObject); + pmo->StretchModel(FLOAT3D(0, 0, 0)); + }; + + void SetFlare(INDEX iFlare, INDEX iAction) + { + // if not a prediction head + if (!IsPredictionHead()) { + // do nothing + return; + } + + // get your prediction tail + CPlayerWeapons *pen = (CPlayerWeapons*)GetPredictionTail(); + if (iFlare==0) { + pen->m_iFlare = iAction; + pen->GetPlayer()->GetPlayerAnimator()->m_iFlare = iAction; + } else { + pen->m_iSecondFlare = iAction; + pen->GetPlayer()->GetPlayerAnimator()->m_iSecondFlare = iAction; + } + } + + // flare attachment + void ControlFlareAttachment(void) { + // if not a prediction head +/* if (!IsPredictionHead()) { + // do nothing + return; + } + */ + + // get your prediction tail + CPlayerWeapons *pen = (CPlayerWeapons *)GetPredictionTail(); + // second colt only + if (m_iCurrentWeapon==WEAPON_DOUBLECOLT) { + // add flare + if (pen->m_iSecondFlare==FLARE_ADD) { + pen->m_iSecondFlare = FLARE_REMOVE; + ShowFlare(m_moWeaponSecond, COLT_ATTACHMENT_COLT, COLTMAIN_ATTACHMENT_FLARE, 1.0f); + // remove flare + } else if (pen->m_iSecondFlare==FLARE_REMOVE) { + HideFlare(m_moWeaponSecond, COLT_ATTACHMENT_COLT, COLTMAIN_ATTACHMENT_FLARE); + } + } + + // add flare + if (pen->m_iFlare==FLARE_ADD) { + pen->m_iFlare = FLARE_REMOVE; + switch(m_iCurrentWeapon) { + case WEAPON_DOUBLECOLT: case WEAPON_COLT: + ShowFlare(m_moWeapon, COLT_ATTACHMENT_COLT, COLTMAIN_ATTACHMENT_FLARE, 0.75f); + break; + case WEAPON_SINGLESHOTGUN: + ShowFlare(m_moWeapon, SINGLESHOTGUN_ATTACHMENT_BARRELS, BARRELS_ATTACHMENT_FLARE, 1.0f); + break; + case WEAPON_DOUBLESHOTGUN: + ShowFlare(m_moWeapon, DOUBLESHOTGUN_ATTACHMENT_BARRELS, DSHOTGUNBARRELS_ATTACHMENT_FLARE, 1.75f); + break; + case WEAPON_TOMMYGUN: + ShowFlare(m_moWeapon, TOMMYGUN_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE, 0.5f); + break; + case WEAPON_MINIGUN: + ShowFlare(m_moWeapon, MINIGUN_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE, 1.25f); + break; + } + // remove + } else if (pen->m_iFlare==FLARE_REMOVE) { + switch(m_iCurrentWeapon) { + case WEAPON_DOUBLECOLT: case WEAPON_COLT: + HideFlare(m_moWeapon, COLT_ATTACHMENT_COLT, COLTMAIN_ATTACHMENT_FLARE); + break; + case WEAPON_SINGLESHOTGUN: + HideFlare(m_moWeapon, SINGLESHOTGUN_ATTACHMENT_BARRELS, BARRELS_ATTACHMENT_FLARE); + break; + case WEAPON_DOUBLESHOTGUN: + HideFlare(m_moWeapon, DOUBLESHOTGUN_ATTACHMENT_BARRELS, DSHOTGUNBARRELS_ATTACHMENT_FLARE); + break; + case WEAPON_TOMMYGUN: + HideFlare(m_moWeapon, TOMMYGUN_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE); + break; + case WEAPON_MINIGUN: + HideFlare(m_moWeapon, MINIGUN_ATTACHMENT_BODY, BODY_ATTACHMENT_FLARE); + break; + } + } else { + ASSERT(FALSE); + } + }; + + + // play light animation + void PlayLightAnim(INDEX iAnim, ULONG ulFlags) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + if (pl.m_aoLightAnimation.GetData()!=NULL) { + pl.m_aoLightAnimation.PlayAnim(iAnim, ulFlags); + } + }; + + + // Set weapon model for current weapon. + void SetCurrentWeaponModel(void) { + // WARNING !!! ---> Order of attachment must be the same with order in RenderWeaponModel() + switch (m_iCurrentWeapon) { + case WEAPON_NONE: + break; + // knife + case WEAPON_KNIFE: + SetComponents(this, m_moWeapon, MODEL_KNIFE, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, KNIFE_ATTACHMENT_KNIFEITEM, MODEL_KNIFEITEM, + TEXTURE_KNIFEITEM, TEX_REFL_BWRIPLES02, TEX_SPEC_WEAK, 0); + m_moWeapon.PlayAnim(KNIFE_ANIM_WAIT1, 0); + break; + // colt + case WEAPON_DOUBLECOLT: { + SetComponents(this, m_moWeaponSecond, MODEL_COLT, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeaponSecond, COLT_ATTACHMENT_BULLETS, MODEL_COLTBULLETS, TEXTURE_COLTBULLETS, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeaponSecond, COLT_ATTACHMENT_COCK, MODEL_COLTCOCK, TEXTURE_COLTCOCK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeaponSecond, COLT_ATTACHMENT_COLT, MODEL_COLTMAIN, TEXTURE_COLTMAIN, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + CModelObject &mo = m_moWeaponSecond.GetAttachmentModel(COLT_ATTACHMENT_COLT)->amo_moModelObject; + AddAttachmentToModel(this, mo, COLTMAIN_ATTACHMENT_FLARE, MODEL_FLARE01, TEXTURE_FLARE01, 0, 0, 0); } + m_moWeaponSecond.StretchModel(FLOAT3D(-1,1,1)); + m_moWeaponSecond.PlayAnim(COLT_ANIM_WAIT1, 0); + case WEAPON_COLT: { + SetComponents(this, m_moWeapon, MODEL_COLT, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, COLT_ATTACHMENT_BULLETS, MODEL_COLTBULLETS, TEXTURE_COLTBULLETS, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, COLT_ATTACHMENT_COCK, MODEL_COLTCOCK, TEXTURE_COLTCOCK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, COLT_ATTACHMENT_COLT, MODEL_COLTMAIN, TEXTURE_COLTMAIN, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + CModelObject &mo = m_moWeapon.GetAttachmentModel(COLT_ATTACHMENT_COLT)->amo_moModelObject; + AddAttachmentToModel(this, mo, COLTMAIN_ATTACHMENT_FLARE, MODEL_FLARE01, TEXTURE_FLARE01, 0, 0, 0); + m_moWeapon.PlayAnim(COLT_ANIM_WAIT1, 0); + break; } + case WEAPON_SINGLESHOTGUN: { + SetComponents(this, m_moWeapon, MODEL_SINGLESHOTGUN, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, SINGLESHOTGUN_ATTACHMENT_BARRELS, MODEL_SS_BARRELS, TEXTURE_SS_BARRELS, TEX_REFL_DARKMETAL, TEX_SPEC_WEAK, 0); + AddAttachmentToModel(this, m_moWeapon, SINGLESHOTGUN_ATTACHMENT_HANDLE, MODEL_SS_HANDLE, TEXTURE_SS_HANDLE, TEX_REFL_DARKMETAL, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, SINGLESHOTGUN_ATTACHMENT_SLIDER, MODEL_SS_SLIDER, TEXTURE_SS_BARRELS, TEX_REFL_DARKMETAL, TEX_SPEC_MEDIUM, 0); + CModelObject &mo = m_moWeapon.GetAttachmentModel(SINGLESHOTGUN_ATTACHMENT_BARRELS)->amo_moModelObject; + AddAttachmentToModel(this, mo, BARRELS_ATTACHMENT_FLARE, MODEL_FLARE01, TEXTURE_FLARE01, 0, 0, 0); + m_moWeapon.PlayAnim(SINGLESHOTGUN_ANIM_WAIT1, 0); + break; } + case WEAPON_DOUBLESHOTGUN: { + SetComponents(this, m_moWeapon, MODEL_DOUBLESHOTGUN, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, DOUBLESHOTGUN_ATTACHMENT_BARRELS, MODEL_DS_BARRELS, TEXTURE_DS_BARRELS, TEX_REFL_BWRIPLES01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, DOUBLESHOTGUN_ATTACHMENT_HANDLE, MODEL_DS_HANDLE, TEXTURE_DS_HANDLE, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, DOUBLESHOTGUN_ATTACHMENT_SWITCH, MODEL_DS_SWITCH, TEXTURE_DS_SWITCH, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, DOUBLESHOTGUN_ATTACHMENT_AMMO, MODEL_DS_AMMO, TEXTURE_DS_AMMO, 0 ,0, 0); + SetComponents(this, m_moWeaponSecond, MODEL_DS_HANDWITHAMMO, TEXTURE_HAND, 0, 0, 0); + CModelObject &mo = m_moWeapon.GetAttachmentModel(DOUBLESHOTGUN_ATTACHMENT_BARRELS)->amo_moModelObject; + AddAttachmentToModel(this, mo, DSHOTGUNBARRELS_ATTACHMENT_FLARE, MODEL_FLARE01, TEXTURE_FLARE01, 0, 0, 0); + m_moWeaponSecond.StretchModel(FLOAT3D(1,1,1)); + m_moWeapon.PlayAnim(DOUBLESHOTGUN_ANIM_WAIT1, 0); + break; } + case WEAPON_TOMMYGUN: { + SetComponents(this, m_moWeapon, MODEL_TOMMYGUN, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, TOMMYGUN_ATTACHMENT_BODY, MODEL_TG_BODY, TEXTURE_TG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, TOMMYGUN_ATTACHMENT_SLIDER, MODEL_TG_SLIDER, TEXTURE_TG_BODY, 0, TEX_SPEC_MEDIUM, 0); + CModelObject &mo = m_moWeapon.GetAttachmentModel(TOMMYGUN_ATTACHMENT_BODY)->amo_moModelObject; + AddAttachmentToModel(this, mo, BODY_ATTACHMENT_FLARE, MODEL_FLARE01, TEXTURE_FLARE01, 0, 0, 0); + break; } + case WEAPON_MINIGUN: { + SetComponents(this, m_moWeapon, MODEL_MINIGUN, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, MINIGUN_ATTACHMENT_BARRELS, MODEL_MG_BARRELS, TEXTURE_MG_BARRELS, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, MINIGUN_ATTACHMENT_BODY, MODEL_MG_BODY, TEXTURE_MG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, MINIGUN_ATTACHMENT_ENGINE, MODEL_MG_ENGINE, TEXTURE_MG_BARRELS, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + CModelObject &mo = m_moWeapon.GetAttachmentModel(MINIGUN_ATTACHMENT_BODY)->amo_moModelObject; + AddAttachmentToModel(this, mo, BODY_ATTACHMENT_FLARE, MODEL_FLARE01, TEXTURE_FLARE01, 0, 0, 0); + break; } + case WEAPON_ROCKETLAUNCHER: + SetComponents(this, m_moWeapon, MODEL_ROCKETLAUNCHER, TEXTURE_RL_BODY, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, ROCKETLAUNCHER_ATTACHMENT_BODY, MODEL_RL_BODY, TEXTURE_RL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, ROCKETLAUNCHER_ATTACHMENT_ROTATINGPART, MODEL_RL_ROTATINGPART, TEXTURE_RL_ROTATINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, ROCKETLAUNCHER_ATTACHMENT_ROCKET1, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, ROCKETLAUNCHER_ATTACHMENT_ROCKET2, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, ROCKETLAUNCHER_ATTACHMENT_ROCKET3, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; + case WEAPON_GRENADELAUNCHER: + SetComponents(this, m_moWeapon, MODEL_GRENADELAUNCHER, TEXTURE_GL_BODY, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, GRENADELAUNCHER_ATTACHMENT_BODY, MODEL_GL_BODY, TEXTURE_GL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, GRENADELAUNCHER_ATTACHMENT_MOVING_PART, MODEL_GL_MOVINGPART, TEXTURE_GL_MOVINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, GRENADELAUNCHER_ATTACHMENT_GRENADE, MODEL_GL_GRENADE, TEXTURE_GL_MOVINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; +/* + case WEAPON_PIPEBOMB: + SetComponents(this, m_moWeapon, MODEL_PIPEBOMB_HAND, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, HANDWITHBOMB_ATTACHMENT_BOMB, MODEL_PB_BOMB, TEXTURE_PB_BOMB, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + SetComponents(this, m_moWeaponSecond, MODEL_PIPEBOMB_STICK, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeaponSecond, HANDWITHSTICK_ATTACHMENT_STICK, MODEL_PB_STICK, TEXTURE_PB_STICK, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeaponSecond, HANDWITHSTICK_ATTACHMENT_SHIELD, MODEL_PB_SHIELD, TEXTURE_PB_STICK, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeaponSecond, HANDWITHSTICK_ATTACHMENT_BUTTON, MODEL_PB_BUTTON, TEXTURE_PB_STICK, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + m_moWeaponSecond.StretchModel(FLOAT3D(1,1,1)); + break; + case WEAPON_FLAMER: + SetComponents(this, m_moWeapon, MODEL_FLAMER, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, FLAMER_ATTACHMENT_BODY, MODEL_FL_BODY, TEXTURE_FL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, FLAMER_ATTACHMENT_FUEL, MODEL_FL_RESERVOIR, TEXTURE_FL_FUELRESERVOIR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, FLAMER_ATTACHMENT_FLAME, MODEL_FL_FLAME, TEXTURE_FL_FLAME, 0, 0, 0); + break; + */ + case WEAPON_LASER: + SetComponents(this, m_moWeapon, MODEL_LASER, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, LASER_ATTACHMENT_BODY, MODEL_LS_BODY, TEXTURE_LS_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, LASER_ATTACHMENT_LEFTUP, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, LASER_ATTACHMENT_LEFTDOWN, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, LASER_ATTACHMENT_RIGHTUP, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, LASER_ATTACHMENT_RIGHTDOWN, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; +/* + case WEAPON_GHOSTBUSTER: + SetComponents(this, m_moWeapon, MODEL_GHOSTBUSTER, TEXTURE_HAND, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, GHOSTBUSTER_ATTACHMENT_BODY, MODEL_GB_BODY, TEXTURE_GB_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, GHOSTBUSTER_ATTACHMENT_ROTATOR, MODEL_GB_ROTATOR, TEXTURE_GB_ROTATOR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, m_moWeapon, GHOSTBUSTER_ATTACHMENT_EFFECT01, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, GHOSTBUSTER_ATTACHMENT_EFFECT02, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, GHOSTBUSTER_ATTACHMENT_EFFECT03, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, GHOSTBUSTER_ATTACHMENT_EFFECT04, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + CModelObject *pmo; + pmo = &(m_moWeapon.GetAttachmentModel(GHOSTBUSTER_ATTACHMENT_EFFECT01)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmo = &(m_moWeapon.GetAttachmentModel(GHOSTBUSTER_ATTACHMENT_EFFECT02)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmo = &(m_moWeapon.GetAttachmentModel(GHOSTBUSTER_ATTACHMENT_EFFECT03)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmo = &(m_moWeapon.GetAttachmentModel(GHOSTBUSTER_ATTACHMENT_EFFECT04)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + break; + */ + case WEAPON_IRONCANNON: +// case WEAPON_NUKECANNON: + SetComponents(this, m_moWeapon, MODEL_CANNON, TEXTURE_CANNON, 0, 0, 0); + AddAttachmentToModel(this, m_moWeapon, CANNON_ATTACHMENT_BODY, MODEL_CN_BODY, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); +// AddAttachmentToModel(this, m_moWeapon, CANNON_ATTACHMENT_NUKEBOX, MODEL_CN_NUKEBOX, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); +// AddAttachmentToModel(this, m_moWeapon, CANNON_ATTACHMENT_LIGHT, MODEL_CN_LIGHT, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + break; + } + }; + + + + /* + * >>>--- ROTATE MINIGUN ---<<< + */ + void RotateMinigun(void) { + ANGLE aAngle = Lerp(m_aMiniGunLast, m_aMiniGun, _pTimer->GetLerpFactor()); + // rotate minigun barrels + CAttachmentModelObject *amo = m_moWeapon.GetAttachmentModel(MINIGUN_ATTACHMENT_BARRELS); + amo->amo_plRelative.pl_OrientationAngle(3) = aAngle; + }; + + + + /* + * >>>--- SUPPORT (COMMON) FUNCTIONS ---<<< + */ + + // calc weapon position for 3rd person view + void CalcWeaponPosition3rdPersonView(FLOAT3D vPos, CPlacement3D &plPos, BOOL bResetZ) { + plPos.pl_OrientationAngle = ANGLE3D(0, 0, 0); + // weapon handle + if (!m_bMirrorFire) { + plPos.pl_PositionVector = FLOAT3D( wpn_fX[m_iCurrentWeapon], wpn_fY[m_iCurrentWeapon], + wpn_fZ[m_iCurrentWeapon]); + } else { + plPos.pl_PositionVector = FLOAT3D( -wpn_fX[m_iCurrentWeapon], wpn_fY[m_iCurrentWeapon], + wpn_fZ[m_iCurrentWeapon]); + } + // weapon offset + if (!m_bMirrorFire) { + plPos.RelativeToAbsolute(CPlacement3D(vPos, ANGLE3D(0, 0, 0))); + } else { + plPos.RelativeToAbsolute(CPlacement3D(vPos, ANGLE3D(0, 0, 0))); + } + plPos.pl_PositionVector(1) *= SinFast(wpn_fFOV[m_iCurrentWeapon]/2) / SinFast(90.0f/2); + plPos.pl_PositionVector(2) *= SinFast(wpn_fFOV[m_iCurrentWeapon]/2) / SinFast(90.0f/2); + plPos.pl_PositionVector(3) *= SinFast(wpn_fFOV[m_iCurrentWeapon]/2) / SinFast(90.0f/2); + + if (bResetZ) { + plPos.pl_PositionVector(3) = 0.0f; + } + + // player view and absolute position + CPlacement3D plView = ((CPlayer &)*m_penPlayer).en_plViewpoint; + plView.pl_PositionVector(2)= 1.25118f; + plPos.RelativeToAbsolute(plView); + plPos.RelativeToAbsolute(m_penPlayer->GetPlacement()); + }; + + // calc weapon position + void CalcWeaponPosition(FLOAT3D vPos, CPlacement3D &plPos, BOOL bResetZ) { + plPos.pl_OrientationAngle = ANGLE3D(0, 0, 0); + // weapon handle + if (!m_bMirrorFire) { + plPos.pl_PositionVector = FLOAT3D( wpn_fX[m_iCurrentWeapon], wpn_fY[m_iCurrentWeapon], + wpn_fZ[m_iCurrentWeapon]); + } else { + plPos.pl_PositionVector = FLOAT3D( -wpn_fX[m_iCurrentWeapon], wpn_fY[m_iCurrentWeapon], + wpn_fZ[m_iCurrentWeapon]); + } + // weapon offset + if (!m_bMirrorFire) { + plPos.RelativeToAbsolute(CPlacement3D(vPos, ANGLE3D(0, 0, 0))); + } else { + plPos.RelativeToAbsolute(CPlacement3D(vPos, ANGLE3D(0, 0, 0))); + } + plPos.pl_PositionVector(1) *= SinFast(wpn_fFOV[m_iCurrentWeapon]/2) / SinFast(90.0f/2); + plPos.pl_PositionVector(2) *= SinFast(wpn_fFOV[m_iCurrentWeapon]/2) / SinFast(90.0f/2); + plPos.pl_PositionVector(3) *= SinFast(wpn_fFOV[m_iCurrentWeapon]/2) / SinFast(90.0f/2); + + if (bResetZ) { + plPos.pl_PositionVector(3) = 0.0f; + } + + // player view and absolute position + CPlacement3D plView = ((CPlayer &)*m_penPlayer).en_plViewpoint; + plView.pl_PositionVector(2)+= ((CPlayerAnimator&)*((CPlayer &)*m_penPlayer).m_penAnimator). + m_fEyesYOffset; + plPos.RelativeToAbsolute(plView); + plPos.RelativeToAbsolute(m_penPlayer->GetPlacement()); + }; + + // setup 3D sound parameters + void Setup3DSoundParameters(void) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + + // initialize sound 3D parameters + pl.m_soWeapon0.Set3DParameters(25.0f, 2.0f, 1.0f, 1.0f); + pl.m_soWeapon1.Set3DParameters(25.0f, 2.0f, 1.0f, 1.0f); + pl.m_soWeapon2.Set3DParameters(25.0f, 2.0f, 1.0f, 1.0f); + pl.m_soWeapon3.Set3DParameters(25.0f, 2.0f, 1.0f, 1.0f); + }; + + + /* + * >>>--- FIRE FUNCTIONS ---<<< + */ + + // cut in front of you with knife + BOOL CutWithKnife(FLOAT fX, FLOAT fY, FLOAT fRange, FLOAT fWide, FLOAT fThickness, FLOAT fDamage) + { + // knife start position + CPlacement3D plKnife; + CalcWeaponPosition(FLOAT3D(fX, fY, 0), plKnife, TRUE); + + // create a set of rays to test + const FLOAT3D &vBase = plKnife.pl_PositionVector; + FLOATmatrix3D m; + MakeRotationMatrixFast(m, plKnife.pl_OrientationAngle); + FLOAT3D vRight = m.GetColumn(1)*fWide; + FLOAT3D vUp = m.GetColumn(2)*fWide; + FLOAT3D vFront = -m.GetColumn(3)*fRange; + + FLOAT3D vDest[5]; + vDest[0] = vBase+vFront; + vDest[1] = vBase+vFront+vUp; + vDest[2] = vBase+vFront-vUp; + vDest[3] = vBase+vFront+vRight; + vDest[4] = vBase+vFront-vRight; + + CEntity *penClosest = NULL; + FLOAT fDistance = UpperLimit(0.0f); + FLOAT3D vHit; + FLOAT3D vDir; + // for each ray + for (INDEX i=0; i<5; i++) { + // cast a ray to find if any model + CCastRay crRay( m_penPlayer, vBase, vDest[i]); + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_fTestR = fThickness; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + GetWorld()->CastRay(crRay); + + // if hit something + if (crRay.cr_penHit!=NULL && crRay.cr_penHit->GetRenderType()==RT_MODEL && crRay.cr_fHitDistanceInitialize(eInit); + }; + + // fire one bullet + void FireOneBullet(FLOAT fX, FLOAT fY, FLOAT fRange, FLOAT fDamage) { + PrepareBullet(fX, fY, fDamage); + ((CBullet&)*penBullet).CalcTarget(fRange); + ((CBullet&)*penBullet).m_fBulletSize = 0.1f; + // launch bullet + ((CBullet&)*penBullet).LaunchBullet(TRUE, FALSE, TRUE); + ((CBullet&)*penBullet).DestroyBullet(); + }; + + // fire bullets (x offset is used for double shotgun) + void FireBullets(FLOAT fX, FLOAT fY, FLOAT fRange, FLOAT fDamage, INDEX iBullets, + FLOAT *afPositions, FLOAT fStretch, FLOAT fJitter) { + PrepareBullet(fX, fY, fDamage); + ((CBullet&)*penBullet).CalcTarget(fRange); + ((CBullet&)*penBullet).m_fBulletSize = GetSP()->sp_bCooperative ? 0.1f : 0.3f; + // launch slugs + INDEX iSlug; + for (iSlug=0; iSlugInitialize(eLaunch); + }; + + // fire rocket + void FireRocket(void) { + // rocket start position + CPlacement3D plRocket; + CalcWeaponPosition( + FLOAT3D(wpn_fFX[WEAPON_ROCKETLAUNCHER],wpn_fFY[WEAPON_ROCKETLAUNCHER], 0), + plRocket, TRUE); + // create rocket + CEntityPointer penRocket= CreateEntity(plRocket, CLASS_PROJECTILE); + // init and launch rocket + ELaunchProjectile eLaunch; + eLaunch.penLauncher = m_penPlayer; + eLaunch.prtType = PRT_ROCKET; + penRocket->Initialize(eLaunch); + }; + + /* + // drop pipebomb + void DropPipebomb(void) { + // pipebomb start position + CPlacement3D plPipebomb; + CalcWeaponPosition( + FLOAT3D(wpn_fFX[WEAPON_PIPEBOMB],wpn_fFY[WEAPON_PIPEBOMB], 0), + plPipebomb, TRUE); + // create pipebomb + CEntityPointer penPipebomb = CreateEntity(plPipebomb, CLASS_PIPEBOMB); + // init and drop pipebomb + EDropPipebomb eDrop; + eDrop.penLauncher = m_penPlayer; + if (((CPlayer&)*m_penPlayer).en_plViewpoint.pl_OrientationAngle(2) > 10.0f) { + eDrop.fSpeed = 30.0f; + } else if (((CPlayer&)*m_penPlayer).en_plViewpoint.pl_OrientationAngle(2) > -20.0f) { + eDrop.fSpeed = 20.0f; + } else { + eDrop.fSpeed = 5.0f; + } + penPipebomb->Initialize(eDrop); + m_penPipebomb = penPipebomb; + }; + + // flamer source + void GetFlamerSourcePlacement(CPlacement3D &plSource) { + CalcWeaponPosition( + FLOAT3D(wpn_fFX[WEAPON_FLAMER],wpn_fFY[WEAPON_FLAMER], 0), + plSource, TRUE); + }; + + // fire flame + void FireFlame(void) { + // flame start position + CPlacement3D plFlame; + GetFlamerSourcePlacement(plFlame); + + // create flame + CEntityPointer penFlame = CreateEntity(plFlame, CLASS_PROJECTILE); + // init and launch flame + ELaunchProjectile eLaunch; + eLaunch.penLauncher = m_penPlayer; + eLaunch.prtType = PRT_FLAME; + penFlame->Initialize(eLaunch); + // link last flame with this one (if not NULL or deleted) + if (m_penFlame!=NULL && !(m_penFlame->GetFlags()&ENF_DELETED)) { + ((CProjectile&)*m_penFlame).m_penParticles = penFlame; + } + // link to player weapons + ((CProjectile&)*penFlame).m_penParticles = this; + // store last flame + m_penFlame = penFlame; + }; + */ + + // fire laser ray + void FireLaserRay(void) { + // laser start position + CPlacement3D plLaserRay; + FLOAT fFX = wpn_fFX[WEAPON_LASER]; // get laser center position + FLOAT fFY = wpn_fFY[WEAPON_LASER]; + FLOAT fLUX = 0.0f; + FLOAT fLUY = 0.0f; + FLOAT fRUX = 0.8f; + FLOAT fRUY = 0.0f; + FLOAT fLDX = -0.1f; + FLOAT fLDY = -0.3f; + FLOAT fRDX = 0.9f; + FLOAT fRDY = -0.3f; + switch(m_iLaserBarrel) { + case 0: // barrel lu (*o-oo) + CalcWeaponPosition(FLOAT3D(fFX+fLUX, fFY+fLUY, 0), plLaserRay, TRUE); + break; + case 1: // barrel ld (oo-*o) + CalcWeaponPosition(FLOAT3D(fFX+fLDX, fFY+fLDY, 0), plLaserRay, TRUE); + break; + case 2: // barrel ru (o*-oo) + CalcWeaponPosition(FLOAT3D(fFX+fRUX, fFY+fRUY, 0), plLaserRay, TRUE); + break; + case 3: // barrel rd (oo-o*) + CalcWeaponPosition(FLOAT3D(fFX+fRDX, fFY+fRDY, 0), plLaserRay, TRUE); + break; + } + // create laser projectile + CEntityPointer penLaser = CreateEntity(plLaserRay, CLASS_PROJECTILE); + // init and launch laser projectile + ELaunchProjectile eLaunch; + eLaunch.penLauncher = m_penPlayer; + eLaunch.prtType = PRT_LASER_RAY; + penLaser->Initialize(eLaunch); + }; + + /* + // ghostbuster source + void GetGhostBusterSourcePlacement(CPlacement3D &plSource) { + CalcWeaponPosition( + FLOAT3D(wpn_fFX[WEAPON_GHOSTBUSTER],wpn_fFY[WEAPON_GHOSTBUSTER], 0), + plSource, TRUE); + }; + + // fire ghost buster ray + void FireGhostBusterRay(void) { + // ray start position + CPlacement3D plRay; + GetGhostBusterSourcePlacement(plRay); + // fire ray + ((CGhostBusterRay&)*m_penGhostBusterRay).Fire(plRay); + }; + */ + + // fire cannon ball + void FireCannonBall(INDEX iPower) + { + // cannon ball start position + CPlacement3D plBall; + CalcWeaponPosition( + FLOAT3D(wpn_fFX[WEAPON_IRONCANNON],wpn_fFY[WEAPON_IRONCANNON], 0), + plBall, TRUE); + // create cannon ball + CEntityPointer penBall = CreateEntity(plBall, CLASS_CANNONBALL); + // init and launch cannon ball + ELaunchCannonBall eLaunch; + eLaunch.penLauncher = m_penPlayer; + eLaunch.fLaunchPower = 60.0f+iPower*4.0f; // ranges from 60-140 (since iPower can be max 20) +/* if( m_iCurrentWeapon == WEAPON_NUKECANNON) + { + eLaunch.cbtType = CBT_NUKE; + } + else + { + */ + eLaunch.cbtType = CBT_IRON; +// } + penBall->Initialize(eLaunch); + }; + + // weapon sound when fireing + void SpawnRangeSound( FLOAT fRange) + { + if( _pTimer->CurrentTick()>m_tmRangeSoundSpawned+0.5f) { + m_tmRangeSoundSpawned = _pTimer->CurrentTick(); + ::SpawnRangeSound( m_penPlayer, m_penPlayer, SNDT_PLAYER, fRange); + } + }; + + + /* + * >>>--- WEAPON INTERFACE FUNCTIONS ---<<< + */ + // clear weapons + void ClearWeapons(void) { + // give/take weapons + m_iAvailableWeapons = 0x03; + m_iColtBullets = 6; + m_iBullets = 0; + m_iShells = 0; + m_iRockets = 0; + m_iGrenades = 0; +// m_iNapalm = 0; + m_iElectricity = 0; + m_iIronBalls = 0; +// m_iNukeBalls = 0; + }; + + void ResetWeaponMovingOffset(void) + { + // reset weapon draw offset + m_fWeaponDrawPowerOld = m_fWeaponDrawPower = m_tmDrawStartTime = 0; + } + + // initialize weapons + void InitializeWeapons(INDEX iGiveWeapons, INDEX iTakeWeapons, INDEX iTakeAmmo, FLOAT fMaxAmmoRatio) + { + ResetWeaponMovingOffset(); + // remember old weapons + ULONG ulOldWeapons = m_iAvailableWeapons; + // give/take weapons + m_iAvailableWeapons &= ~iTakeWeapons; + m_iAvailableWeapons |= 0x03|iGiveWeapons; +// m_iAvailableWeapons &= ~WEAPONS_DISABLEDMASK; + // find which weapons are new + ULONG ulNewWeapons = m_iAvailableWeapons&~ulOldWeapons; + // for each new weapon + for(INDEX iWeapon=WEAPON_KNIFE; iWeaponsp_fAmmoQuantity, 1.0f); + m_iMaxBullets = ClampUp((INDEX) ceil(MAX_BULLETS*fModifier), INDEX(999)); + m_iMaxShells = ClampUp((INDEX) ceil(MAX_SHELLS*fModifier), INDEX(999)); + m_iMaxRockets = ClampUp((INDEX) ceil(MAX_ROCKETS*fModifier), INDEX(999)); + m_iMaxGrenades = ClampUp((INDEX) ceil(MAX_GRENADES*fModifier), INDEX(999)); +// m_iMaxNapalm = ClampUp((INDEX) ceil(MAX_NAPALM*fModifier), INDEX(999)); + m_iMaxElectricity = ClampUp((INDEX) ceil(MAX_ELECTRICITY*fModifier), INDEX(999)); +// m_iMaxNukeBalls = ClampUp((INDEX) ceil(MAX_NUKEBALLS*fModifier), INDEX(999)); + m_iMaxIronBalls = ClampUp((INDEX) ceil(MAX_IRONBALLS*fModifier), INDEX(999)); + + // take away ammo + if( iTakeAmmo & (1<SendEvent(ETrigger()); + } + } + + // cheat give all + void CheatGiveAll(void) { + // all weapons + m_iAvailableWeapons = 0x1EBFF; +// m_iAvailableWeapons &= ~WEAPONS_DISABLEDMASK; + // ammo for all weapons + m_iBullets = m_iMaxBullets; + m_iShells = m_iMaxShells; + m_iRockets = m_iMaxRockets; + m_iGrenades = m_iMaxGrenades; +// m_iNapalm = m_iMaxNapalm; + m_iElectricity = m_iMaxElectricity; + m_iIronBalls = m_iMaxIronBalls; +// m_iNukeBalls = m_iMaxNukeBalls; + // precache eventual new weapons + Precache(); + }; + + // add a given amount of mana to the player + void AddManaToPlayer(INDEX iMana) + { + ((CPlayer&)*m_penPlayer).m_iMana += iMana; + ((CPlayer&)*m_penPlayer).m_fPickedMana += iMana; + } + + + /* + * >>>--- RECEIVE FUNCTIONS ---<<< + */ + + // clamp ammounts of all ammunition to maximum values + void ClampAllAmmo(void) + { + m_iBullets = ClampUp(m_iBullets, m_iMaxBullets); + m_iShells = ClampUp(m_iShells, m_iMaxShells); + m_iRockets = ClampUp(m_iRockets, m_iMaxRockets); + m_iGrenades = ClampUp(m_iGrenades, m_iMaxGrenades); +// m_iNapalm = ClampUp(m_iNapalm, m_iMaxNapalm); + m_iElectricity = ClampUp(m_iElectricity, m_iMaxElectricity); + m_iIronBalls = ClampUp(m_iIronBalls, m_iMaxIronBalls); +// m_iNukeBalls = ClampUp(m_iNukeBalls, m_iMaxNukeBalls); + } + + // add default ammount of ammunition when receiving a weapon + void AddDefaultAmmoForWeapon(INDEX iWeapon, FLOAT fMaxAmmoRatio) + { + INDEX iAmmoPicked; + // add ammo + switch (iWeapon) { + // unlimited ammo + case WEAPON_KNIFE: + case WEAPON_COLT: + case WEAPON_DOUBLECOLT: + break; + // shells + case WEAPON_SINGLESHOTGUN: + iAmmoPicked = Max(10.0f, m_iMaxShells*fMaxAmmoRatio); + m_iShells += iAmmoPicked; + AddManaToPlayer(iAmmoPicked*70.0f*MANA_AMMO); + break; + case WEAPON_DOUBLESHOTGUN: + iAmmoPicked = Max(20.0f, m_iMaxShells*fMaxAmmoRatio); + m_iShells += iAmmoPicked; + AddManaToPlayer(iAmmoPicked*70.0f*MANA_AMMO); + break; + // bullets + case WEAPON_TOMMYGUN: + iAmmoPicked = Max(50.0f, m_iMaxBullets*fMaxAmmoRatio); + m_iBullets += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*10.0f*MANA_AMMO); + break; + case WEAPON_MINIGUN: + iAmmoPicked = Max(100.0f, m_iMaxBullets*fMaxAmmoRatio); + m_iBullets += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*10.0f*MANA_AMMO); + break; + // rockets + case WEAPON_ROCKETLAUNCHER: + iAmmoPicked = Max(5.0f, m_iMaxRockets*fMaxAmmoRatio); + m_iRockets += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*150.0f*MANA_AMMO); + break; + // grenades + case WEAPON_GRENADELAUNCHER: + iAmmoPicked = Max(5.0f, m_iMaxGrenades*fMaxAmmoRatio); + m_iGrenades += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*100.0f*MANA_AMMO); + break; +/* + case WEAPON_PIPEBOMB: + iAmmoPicked = Max(5.0f, m_iMaxGrenades*fMaxAmmoRatio); + m_iGrenades += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*100.0f*MANA_AMMO); + break; + case WEAPON_GHOSTBUSTER: + iAmmoPicked = Max(100.0f, m_iMaxElectricity*fMaxAmmoRatio); + m_iElectricity += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*15.0f*MANA_AMMO); + break; + */ + // electricity + case WEAPON_LASER: + iAmmoPicked = Max(50.0f, m_iMaxElectricity*fMaxAmmoRatio); + m_iElectricity += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*15.0f*MANA_AMMO); + break; + // cannon balls + case WEAPON_IRONCANNON: + // for iron ball + iAmmoPicked = Max(1.0f, m_iMaxIronBalls*fMaxAmmoRatio); + m_iIronBalls += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*700.0f*MANA_AMMO); + break; +/* // for nuke ball + case WEAPON_NUKECANNON: + iAmmoPicked = Max(1.0f, m_iMaxNukeBalls*fMaxAmmoRatio); + m_iNukeBalls += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*1000.0f*MANA_AMMO); + break; + // flamer // !!!! how much mana exactly? + case WEAPON_FLAMER: + iAmmoPicked = Max(50.0f, m_iMaxNapalm*fMaxAmmoRatio); + m_iNapalm += iAmmoPicked; + AddManaToPlayer( iAmmoPicked*15.0f*MANA_AMMO); + break; + */ + // error + default: + ASSERTALWAYS("Uknown weapon type"); + } + + // make sure we don't have more ammo than maximum + ClampAllAmmo(); + } + + // drop current weapon (in deathmatch) + void DropWeapon(void) + { + CEntityPointer penWeapon = CreateEntity(GetPlayer()->GetPlacement(), CLASS_WEAPONITEM); + CWeaponItem *pwi = (CWeaponItem*)&*penWeapon; + + WeaponItemType wit = WIT_COLT; + switch (m_iCurrentWeapon) { + default: + ASSERT(FALSE); + case WEAPON_KNIFE: + case WEAPON_COLT: + case WEAPON_DOUBLECOLT: + NOTHING; break; + case WEAPON_SINGLESHOTGUN: wit = WIT_SINGLESHOTGUN; break; + case WEAPON_DOUBLESHOTGUN: wit = WIT_DOUBLESHOTGUN; break; + case WEAPON_TOMMYGUN: wit = WIT_TOMMYGUN; break; + case WEAPON_MINIGUN: wit = WIT_MINIGUN; break; + case WEAPON_ROCKETLAUNCHER: wit = WIT_ROCKETLAUNCHER; break; + case WEAPON_GRENADELAUNCHER: wit = WIT_GRENADELAUNCHER; break; +// case WEAPON_PIPEBOMB: wit = WIT_PIPEBOMB; break; +// case WEAPON_FLAMER: wit = WIT_FLAMER; break; + case WEAPON_LASER : wit = WIT_LASER; break; +// case WEAPON_GHOSTBUSTER : wit = WIT_GHOSTBUSTER; break; + case WEAPON_IRONCANNON : wit = WIT_CANNON; break; + } + + pwi->m_EwitType = wit; + pwi->m_bDropped = TRUE; + pwi->CEntity::Initialize(); + + const FLOATmatrix3D &m = GetPlayer()->GetRotationMatrix(); + FLOAT3D vSpeed = FLOAT3D( 5.0f, 10.0f, -7.5f); + pwi->GiveImpulseTranslationAbsolute(vSpeed*m); + } + + // receive weapon + BOOL ReceiveWeapon(const CEntityEvent &ee) { + ASSERT(ee.ee_slEvent == EVENTCODE_EWeaponItem); + + EWeaponItem &Ewi = (EWeaponItem&)ee; + INDEX wit = Ewi.iWeapon; + switch (Ewi.iWeapon) { + case WIT_COLT: Ewi.iWeapon = WEAPON_COLT; break; + case WIT_SINGLESHOTGUN: Ewi.iWeapon = WEAPON_SINGLESHOTGUN; break; + case WIT_DOUBLESHOTGUN: Ewi.iWeapon = WEAPON_DOUBLESHOTGUN; break; + case WIT_TOMMYGUN: Ewi.iWeapon = WEAPON_TOMMYGUN; break; + case WIT_MINIGUN: Ewi.iWeapon = WEAPON_MINIGUN; break; + case WIT_ROCKETLAUNCHER: Ewi.iWeapon = WEAPON_ROCKETLAUNCHER; break; + case WIT_GRENADELAUNCHER: Ewi.iWeapon = WEAPON_GRENADELAUNCHER; break; +// case WIT_PIPEBOMB: Ewi.iWeapon = WEAPON_PIPEBOMB; break; +// case WIT_FLAMER: Ewi.iWeapon = WEAPON_FLAMER; break; + case WIT_LASER: Ewi.iWeapon = WEAPON_LASER; break; +// case WIT_GHOSTBUSTER: Ewi.iWeapon = WEAPON_GHOSTBUSTER; break; + case WIT_CANNON: Ewi.iWeapon = WEAPON_IRONCANNON; break; + default: + ASSERTALWAYS("Uknown weapon type"); + } + + // add weapon + if (Ewi.iWeapon==WEAPON_COLT && (m_iAvailableWeapons&(1<<(WEAPON_COLT-1)))) { + Ewi.iWeapon = WEAPON_DOUBLECOLT; + } + + ULONG ulOldWeapons = m_iAvailableWeapons; + m_iAvailableWeapons |= 1<<(Ewi.iWeapon-1); +// m_iAvailableWeapons &= ~WEAPONS_DISABLEDMASK; + +/* + if( Ewi.iWeapon == WEAPON_IRONCANNON) + { + m_iAvailableWeapons |= 1<<(WEAPON_NUKECANNON-1); + m_iAvailableWeapons &= ~WEAPONS_DISABLEDMASK; + } + */ + + // precache eventual new weapons + Precache(); + + CTFileName fnmMsg; + switch (wit) { + case WIT_COLT: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Shofield .45 w/ TMAR"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\colt.txt"); + break; + case WIT_SINGLESHOTGUN: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("12 Gauge Pump Action Shotgun"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\singleshotgun.txt"); + break; + case WIT_DOUBLESHOTGUN: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Double Barrel Coach Gun"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\doubleshotgun.txt"); + break; + case WIT_TOMMYGUN: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("M1-A2 Tommygun"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\tommygun.txt"); + break; + case WIT_MINIGUN: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("XM214-A Minigun"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\minigun.txt"); + break; + case WIT_ROCKETLAUNCHER: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("XPML21 Rocket Launcher"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\rocketlauncher.txt"); + break; + case WIT_GRENADELAUNCHER: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("MKIII Grenade Launcher"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\grenadelauncher.txt"); + break; +// case WIT_PIPEBOMB: +// fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\pipebomb.txt"); +// break; +// case WIT_FLAMER: +// fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\flamer.txt"); +// break; + case WIT_LASER: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("XL2 Lasergun"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\laser.txt"); + break; +// case WIT_GHOSTBUSTER: +// fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\ghostbuster.txt"); +// break; + case WIT_CANNON: + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("SBC Cannon"), 0); + fnmMsg = CTFILENAME("Data\\Messages\\Weapons\\cannon.txt"); + break; + default: + ASSERTALWAYS("Uknown weapon type"); + } + // send computer message + if (GetSP()->sp_bCooperative) { + EComputerMessage eMsg; + eMsg.fnmMessage = fnmMsg; + m_penPlayer->SendEvent(eMsg); + } + + // must be -1 for default (still have to implement dropping weapons in deathmatch !!!!) + ASSERT(Ewi.iAmmo==-1); + // add the ammunition + AddDefaultAmmoForWeapon(Ewi.iWeapon, 0); + + // if this weapon should be auto selected + BOOL bAutoSelect = FALSE; + INDEX iSelectionSetting = GetPlayer()->GetSettings()->ps_iWeaponAutoSelect; + if (iSelectionSetting==PS_WAS_ALL) { + bAutoSelect = TRUE; + } else if (iSelectionSetting==PS_WAS_ONLYNEW) { + if (m_iAvailableWeapons&~ulOldWeapons) { + bAutoSelect = TRUE; + } + } else if (iSelectionSetting==PS_WAS_BETTER) { + if (m_iCurrentWeapon<(WeaponType)Ewi.iWeapon) { + bAutoSelect = TRUE; + } + } + if (bAutoSelect) { + // select it + if (WeaponSelectOk((WeaponType)Ewi.iWeapon)) { + SendEvent(EBegin()); + } + } + + return TRUE; + }; + + // receive ammo + BOOL ReceiveAmmo(const CEntityEvent &ee) { + ASSERT(ee.ee_slEvent == EVENTCODE_EAmmoItem); + + // if infinite ammo is on + if (GetSP()->sp_bInfiniteAmmo) { + // pick all items anyway (items that exist in this mode are only those that + // trigger something when picked - so they must be picked) + return TRUE; + } + + + EAmmoItem &Eai = (EAmmoItem&)ee; + // add ammo + switch (Eai.EaitType) { + // shells + case AIT_SHELLS: + if (m_iShells>=m_iMaxShells) { m_iShells = m_iMaxShells; return FALSE; } + m_iShells += Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Shells"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_SHELLS*MANA_AMMO); + break; + // bullets + case AIT_BULLETS: + if (m_iBullets>=m_iMaxBullets) { m_iBullets = m_iMaxBullets; return FALSE; } + m_iBullets += Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Bullets"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_BULLETS *MANA_AMMO); + break; + // rockets + case AIT_ROCKETS: + if (m_iRockets>=m_iMaxRockets) { m_iRockets = m_iMaxRockets; return FALSE; } + m_iRockets += Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Rockets"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_ROCKETS *MANA_AMMO); + break; + // grenades + case AIT_GRENADES: + if (m_iGrenades>=m_iMaxGrenades) { m_iGrenades = m_iMaxGrenades; return FALSE; } + m_iGrenades += Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Grenades"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_GRENADES *MANA_AMMO); + break; + // electicity + case AIT_ELECTRICITY: + if (m_iElectricity>=m_iMaxElectricity) { m_iElectricity = m_iMaxElectricity; return FALSE; } + m_iElectricity += Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Cells"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_ELECTRICITY *MANA_AMMO); + break; +/* // cannon balls + case AIT_NUKEBALL: + if (m_iNukeBalls>=m_iMaxNukeBalls) { m_iNukeBalls = m_iMaxNukeBalls; return FALSE; } + m_iNukeBalls+= Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Nuke ball"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_NUKEBALLS *MANA_AMMO); + break;*/ + case AIT_IRONBALLS: + if (m_iIronBalls>=m_iMaxIronBalls) { m_iIronBalls = m_iMaxIronBalls; return FALSE; } + m_iIronBalls+= Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Cannonballs"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_IRONBALLS *MANA_AMMO); + break; +/* case AIT_NAPALM: + if (m_iNapalm>=m_iMaxNapalm) { m_iNapalm = m_iMaxNapalm; return FALSE; } + m_iNapalm+= Eai.iQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Napalm"), Eai.iQuantity); + AddManaToPlayer(Eai.iQuantity*AV_NAPALM*MANA_AMMO); + break;*/ + case AIT_BACKPACK: + m_iShells += 20*GetSP()->sp_fAmmoQuantity; + m_iBullets += 200*GetSP()->sp_fAmmoQuantity; + m_iRockets += 5*GetSP()->sp_fAmmoQuantity; + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("Ammo pack"), 0); + AddManaToPlayer(100000000.0f *MANA_AMMO); // adjust mana value!!!! + break; + case AIT_SERIOUSPACK: + m_iShells += MAX_SHELLS*GetSP()->sp_fAmmoQuantity; + m_iBullets += MAX_BULLETS*GetSP()->sp_fAmmoQuantity; + m_iGrenades += MAX_GRENADES*GetSP()->sp_fAmmoQuantity; + m_iRockets += MAX_ROCKETS*GetSP()->sp_fAmmoQuantity; + m_iElectricity += MAX_ELECTRICITY*GetSP()->sp_fAmmoQuantity; + m_iIronBalls += MAX_IRONBALLS*GetSP()->sp_fAmmoQuantity; +// m_iNukeBalls += MAX_NUKEBALLS*GetSP()->sp_fAmmoQuantity; + + ((CPlayer&)*m_penPlayer).ItemPicked(TRANS("All Ammo"), 0); + AddManaToPlayer(100000000.0f *MANA_AMMO); // adjust mana value!!!! + break; + // error + default: + ASSERTALWAYS("Uknown ammo type"); + } + + // make sure we don't have more ammo than maximum + ClampAllAmmo(); + return TRUE; + }; + + // receive ammo + BOOL ReceivePackAmmo(const CEntityEvent &ee) + { + // if infinite ammo is on + if (GetSP()->sp_bInfiniteAmmo) { + // pick all items anyway (items that exist in this mode are only those that + // trigger something when picked - so they must be picked) + return TRUE; + } + + ASSERT(ee.ee_slEvent == EVENTCODE_EAmmoPackItem); + EAmmoPackItem &eapi = (EAmmoPackItem &)ee; + if( (eapi.iShells>0 && m_iShells0 && m_iBullets0 && m_iRockets0 && m_iGrenades0 && m_iNapalm0 && m_iElectricity0 && m_iIronBalls0 && m_iNukeBalls0 && strMessage[iLen-1]==',') + { + strMessage.DeleteChar(iLen-1); + }; + + ((CPlayer&)*m_penPlayer).ItemPicked(strMessage, 0); + return TRUE; + } + return FALSE; + } + + /* + * >>>--- WEAPON CHANGE FUNCTIONS ---<<< + */ + // get weapon from selected number + WeaponType GetStrongerWeapon(INDEX iWeapon) { + switch(iWeapon) { + case 1: return WEAPON_KNIFE; + case 2: return WEAPON_DOUBLECOLT; + case 3: return WEAPON_DOUBLESHOTGUN; + case 4: return WEAPON_MINIGUN; + case 5: return WEAPON_ROCKETLAUNCHER; + case 6: return WEAPON_GRENADELAUNCHER; +// case 7: return WEAPON_FLAMER; +// case 8: return WEAPON_GHOSTBUSTER; + case 8: return WEAPON_LASER; + case 9: return WEAPON_IRONCANNON; + } + return WEAPON_NONE; + }; + + // get selected number for weapon + INDEX GetSelectedWeapon(WeaponType EwtSelectedWeapon) { + switch(EwtSelectedWeapon) { + case WEAPON_KNIFE: return 1; + case WEAPON_COLT: case WEAPON_DOUBLECOLT: return 2; + case WEAPON_SINGLESHOTGUN: case WEAPON_DOUBLESHOTGUN: return 3; + case WEAPON_TOMMYGUN: case WEAPON_MINIGUN: return 4; + case WEAPON_ROCKETLAUNCHER: return 5; + case WEAPON_GRENADELAUNCHER: return 6; +// case WEAPON_PIPEBOMB: return 6; +// case WEAPON_FLAMER: return 7; + case WEAPON_LASER: /*case WEAPON_GHOSTBUSTER: */return 8; + case WEAPON_IRONCANNON: /*case WEAPON_NUKECANNON: */return 9; + } + return 0; + }; + + // get secondary weapon from selected one + WeaponType GetAltWeapon(WeaponType EwtWeapon) { + switch (EwtWeapon) { + case WEAPON_KNIFE: return WEAPON_KNIFE; + case WEAPON_COLT: return WEAPON_DOUBLECOLT; + case WEAPON_DOUBLECOLT: return WEAPON_COLT; + case WEAPON_SINGLESHOTGUN: return WEAPON_DOUBLESHOTGUN; + case WEAPON_DOUBLESHOTGUN: return WEAPON_SINGLESHOTGUN; + case WEAPON_TOMMYGUN: return WEAPON_MINIGUN; + case WEAPON_MINIGUN: return WEAPON_TOMMYGUN; + case WEAPON_ROCKETLAUNCHER: return WEAPON_ROCKETLAUNCHER; + case WEAPON_GRENADELAUNCHER: return WEAPON_GRENADELAUNCHER; +// case WEAPON_PIPEBOMB: return WEAPON_PIPEBOMB; +// case WEAPON_FLAMER: return WEAPON_FLAMER; + case WEAPON_LASER: return WEAPON_LASER; //return WEAPON_GHOSTBUSTER; +// case WEAPON_GHOSTBUSTER: return WEAPON_LASER; + case WEAPON_IRONCANNON: return WEAPON_IRONCANNON; //return WEAPON_NUKECANNON; +// case WEAPON_NUKECANNON: return WEAPON_IRONCANNON; + } + return WEAPON_NONE; + }; + + // select new weapon if possible + BOOL WeaponSelectOk(WeaponType wtToTry) + { + // if player has weapon and has enough ammo + if (((1<<(INDEX(wtToTry)-1))&m_iAvailableWeapons) + &&HasAmmo(wtToTry)) { + // if different weapon + if (wtToTry!=m_iCurrentWeapon) { + // initiate change + //m_bHasAmmo = FALSE; + m_iWantedWeapon = wtToTry; + m_bChangeWeapon = TRUE; + } + // selection ok + return TRUE; + // if no weapon or not enough ammo + } else { + // selection not ok + return FALSE; + } + } + // select new weapon when no more ammo + void SelectNewWeapon() + { + switch (m_iCurrentWeapon) { + case WEAPON_NONE: + case WEAPON_KNIFE: case WEAPON_COLT: case WEAPON_DOUBLECOLT: + case WEAPON_SINGLESHOTGUN: case WEAPON_DOUBLESHOTGUN: + case WEAPON_TOMMYGUN: case WEAPON_MINIGUN: + WeaponSelectOk(WEAPON_MINIGUN)|| + WeaponSelectOk(WEAPON_TOMMYGUN)|| + WeaponSelectOk(WEAPON_DOUBLESHOTGUN)|| + WeaponSelectOk(WEAPON_SINGLESHOTGUN)|| + WeaponSelectOk(WEAPON_DOUBLECOLT)|| + WeaponSelectOk(WEAPON_COLT)|| + WeaponSelectOk(WEAPON_KNIFE); + break; + case WEAPON_IRONCANNON: +// WeaponSelectOk(WEAPON_NUKECANNON)|| + WeaponSelectOk(WEAPON_ROCKETLAUNCHER)|| + WeaponSelectOk(WEAPON_GRENADELAUNCHER)|| +// WeaponSelectOk(WEAPON_PIPEBOMB)|| + WeaponSelectOk(WEAPON_MINIGUN)|| + WeaponSelectOk(WEAPON_TOMMYGUN)|| + WeaponSelectOk(WEAPON_DOUBLESHOTGUN)|| + WeaponSelectOk(WEAPON_SINGLESHOTGUN)|| + WeaponSelectOk(WEAPON_DOUBLECOLT)|| + WeaponSelectOk(WEAPON_COLT)|| + WeaponSelectOk(WEAPON_KNIFE); + break; +/* + case WEAPON_NUKECANNON: + WeaponSelectOk(WEAPON_IRONCANNON)|| + WeaponSelectOk(WEAPON_ROCKETLAUNCHER)|| + WeaponSelectOk(WEAPON_GRENADELAUNCHER)|| + WeaponSelectOk(WEAPON_PIPEBOMB)|| + WeaponSelectOk(WEAPON_MINIGUN)|| + WeaponSelectOk(WEAPON_TOMMYGUN)|| + WeaponSelectOk(WEAPON_DOUBLESHOTGUN)|| + WeaponSelectOk(WEAPON_SINGLESHOTGUN)|| + WeaponSelectOk(WEAPON_DOUBLECOLT)|| + WeaponSelectOk(WEAPON_COLT)|| + WeaponSelectOk(WEAPON_KNIFE); + break; + */ + case WEAPON_ROCKETLAUNCHER: + case WEAPON_GRENADELAUNCHER: +// case WEAPON_PIPEBOMB: + WeaponSelectOk(WEAPON_ROCKETLAUNCHER)|| + WeaponSelectOk(WEAPON_GRENADELAUNCHER)|| +// WeaponSelectOk(WEAPON_PIPEBOMB)|| + WeaponSelectOk(WEAPON_MINIGUN)|| + WeaponSelectOk(WEAPON_TOMMYGUN)|| + WeaponSelectOk(WEAPON_DOUBLESHOTGUN)|| + WeaponSelectOk(WEAPON_SINGLESHOTGUN)|| + WeaponSelectOk(WEAPON_DOUBLECOLT)|| + WeaponSelectOk(WEAPON_COLT)|| + WeaponSelectOk(WEAPON_KNIFE); + break; + case WEAPON_LASER: // case WEAPON_FLAMER: case WEAPON_GHOSTBUSTER: +// WeaponSelectOk(WEAPON_GHOSTBUSTER)|| + WeaponSelectOk(WEAPON_LASER)|| +// WeaponSelectOk(WEAPON_FLAMER)|| + WeaponSelectOk(WEAPON_MINIGUN)|| + WeaponSelectOk(WEAPON_TOMMYGUN)|| + WeaponSelectOk(WEAPON_DOUBLESHOTGUN)|| + WeaponSelectOk(WEAPON_SINGLESHOTGUN)|| + WeaponSelectOk(WEAPON_DOUBLECOLT)|| + WeaponSelectOk(WEAPON_COLT)|| + WeaponSelectOk(WEAPON_KNIFE); + break; + default: + WeaponSelectOk(WEAPON_KNIFE); + ASSERT(FALSE); + } + }; + + // did weapon has ammo + BOOL HasAmmo(WeaponType EwtWeapon) { + switch (EwtWeapon) { + case WEAPON_KNIFE: case WEAPON_COLT: case WEAPON_DOUBLECOLT: return TRUE; + case WEAPON_SINGLESHOTGUN: return (m_iShells>0); + case WEAPON_DOUBLESHOTGUN: return (m_iShells>1); + case WEAPON_TOMMYGUN: return (m_iBullets>0); + case WEAPON_MINIGUN: return (m_iBullets>0); + case WEAPON_ROCKETLAUNCHER: return (m_iRockets>0); + case WEAPON_GRENADELAUNCHER: return (m_iGrenades>0); +// case WEAPON_PIPEBOMB: return (m_iGrenades>0 || m_bPipeBombDropped); +// case WEAPON_FLAMER: return (m_iNapalm>0); + case WEAPON_LASER: return (m_iElectricity>0); +// case WEAPON_GHOSTBUSTER: return (m_iElectricity>0); + case WEAPON_IRONCANNON: return (m_iIronBalls>0); +// case WEAPON_NUKECANNON: return (m_iNukeBalls>0); + } + return FALSE; + }; + + /* + * >>>--- DEFAULT ANIM ---<<< + */ + void PlayDefaultAnim(void) { + switch(m_iCurrentWeapon) { + case WEAPON_NONE: + break; + case WEAPON_KNIFE: + switch (m_iKnifeStand) { + case 1: m_moWeapon.PlayAnim(KNIFE_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case 3: m_moWeapon.PlayAnim(KNIFE_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + default: ASSERTALWAYS("Unknown knife stand."); + } + break; + case WEAPON_DOUBLECOLT: + m_moWeaponSecond.PlayAnim(COLT_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); + case WEAPON_COLT: + m_moWeapon.PlayAnim(COLT_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case WEAPON_SINGLESHOTGUN: + m_moWeapon.PlayAnim(SINGLESHOTGUN_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case WEAPON_DOUBLESHOTGUN: + m_moWeapon.PlayAnim(DOUBLESHOTGUN_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case WEAPON_TOMMYGUN: + m_moWeapon.PlayAnim(TOMMYGUN_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case WEAPON_MINIGUN: + m_moWeapon.PlayAnim(MINIGUN_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case WEAPON_ROCKETLAUNCHER: + m_moWeapon.PlayAnim(ROCKETLAUNCHER_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + case WEAPON_GRENADELAUNCHER: + m_moWeapon.PlayAnim(GRENADELAUNCHER_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; +/* + case WEAPON_PIPEBOMB: + if (m_bPipeBombDropped) { + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_STICKTHROWWAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + } else { + m_moWeapon.PlayAnim(HANDWITHBOMB_ANIM_BOMBWAIT2, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_STICKWAIT1, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + } + case WEAPON_FLAMER: + m_moWeapon.PlayAnim(FLAMER_ANIM_WAIT01, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + */ + case WEAPON_LASER: + m_moWeapon.PlayAnim(LASER_ANIM_WAIT01, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; +/* + case WEAPON_GHOSTBUSTER: + m_moWeapon.PlayAnim(GHOSTBUSTER_ANIM_WAIT03, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + */ + case WEAPON_IRONCANNON: +// case WEAPON_NUKECANNON: + m_moWeapon.PlayAnim(CANNON_ANIM_WAIT01, AOF_LOOPING|AOF_NORESTART|AOF_SMOOTHCHANGE); break; + default: + ASSERTALWAYS("Unknown weapon."); + } + }; + + /* + * >>>--- WEAPON BORING ---<<< + */ + FLOAT KnifeBoring(void) { + // play boring anim + INDEX iAnim; + switch (m_iKnifeStand) { + case 1: iAnim = KNIFE_ANIM_WAIT1; break; + case 3: iAnim = KNIFE_ANIM_WAIT1; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + FLOAT ColtBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = COLT_ANIM_WAIT3; break; + case 1: iAnim = COLT_ANIM_WAIT4; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + FLOAT DoubleColtBoring(void) { + // play boring anim for one colt + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = COLT_ANIM_WAIT3; break; + case 1: iAnim = COLT_ANIM_WAIT4; break; + } + if (IRnd()&1) { + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + } else { + m_moWeaponSecond.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeaponSecond.GetAnimLength(iAnim); + } + }; + + FLOAT SingleShotgunBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = SINGLESHOTGUN_ANIM_WAIT2; break; + case 1: iAnim = SINGLESHOTGUN_ANIM_WAIT3; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + FLOAT DoubleShotgunBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = DOUBLESHOTGUN_ANIM_WAIT2; break; + case 1: iAnim = DOUBLESHOTGUN_ANIM_WAIT3; break; + case 2: iAnim = DOUBLESHOTGUN_ANIM_WAIT4; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + FLOAT TommyGunBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%2) { + case 0: iAnim = TOMMYGUN_ANIM_WAIT2; break; + case 1: iAnim = TOMMYGUN_ANIM_WAIT3; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + FLOAT MiniGunBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = MINIGUN_ANIM_WAIT2; break; + case 1: iAnim = MINIGUN_ANIM_WAIT3; break; + case 2: iAnim = MINIGUN_ANIM_WAIT4; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + FLOAT RocketLauncherBoring(void) { + // play boring anim + m_moWeapon.PlayAnim(ROCKETLAUNCHER_ANIM_WAIT2, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(ROCKETLAUNCHER_ANIM_WAIT2); + }; + + FLOAT GrenadeLauncherBoring(void) { + // play boring anim + m_moWeapon.PlayAnim(GRENADELAUNCHER_ANIM_WAIT2, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(GRENADELAUNCHER_ANIM_WAIT2); + }; + +/* + FLOAT PipeBombBoring(void) { + if (IRnd()&1 && !m_bPipeBombDropped) { + // play boring anim for hand with bomb + INDEX iAnim; + switch (IRnd()%4) { + case 0: iAnim = HANDWITHBOMB_ANIM_BOMBWAIT1; break; + case 1: iAnim = HANDWITHBOMB_ANIM_BOMBWAIT3; break; + case 2: iAnim = HANDWITHBOMB_ANIM_BOMBWAIT4; break; + case 3: iAnim = HANDWITHBOMB_ANIM_BOMBWAIT5; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + } else { + // play boring anim for hand with stick + INDEX iAnimSecond; + if (m_bPipeBombDropped) { + switch (IRnd()%2) { + case 0: iAnimSecond = HANDWITHSTICK_ANIM_STICKTHROWWAIT2; break; + case 1: iAnimSecond = HANDWITHSTICK_ANIM_STICKTHROWWAIT3; break; + } + } else { + switch (IRnd()%3) { + case 0: iAnimSecond = HANDWITHSTICK_ANIM_STICKWAIT2; break; + case 1: iAnimSecond = HANDWITHSTICK_ANIM_STICKWAIT3; break; + case 2: iAnimSecond = HANDWITHSTICK_ANIM_STICKWAIT4; break; + } + } + m_moWeaponSecond.PlayAnim(iAnimSecond, AOF_SMOOTHCHANGE); + return m_moWeaponSecond.GetAnimLength(iAnimSecond); + } + }; + + FLOAT FlamerBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%4) { + case 0: iAnim = FLAMER_ANIM_WAIT02; break; + case 1: iAnim = FLAMER_ANIM_WAIT03; break; + case 2: iAnim = FLAMER_ANIM_WAIT04; break; + case 3: iAnim = FLAMER_ANIM_WAIT05; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + */ + + FLOAT LaserBoring(void) { + // play boring anim + INDEX iAnim; + iAnim = LASER_ANIM_WAIT02; + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + /* + FLOAT GhostBusterBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = GHOSTBUSTER_ANIM_WAIT01; break; + case 1: iAnim = GHOSTBUSTER_ANIM_WAIT02; break; + case 2: iAnim = GHOSTBUSTER_ANIM_WAIT04; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + */ + + FLOAT CannonBoring(void) { + // play boring anim + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = CANNON_ANIM_WAIT02; break; + case 1: iAnim = CANNON_ANIM_WAIT03; break; + case 2: iAnim = CANNON_ANIM_WAIT04; break; + } + m_moWeapon.PlayAnim(iAnim, AOF_SMOOTHCHANGE); + return m_moWeapon.GetAnimLength(iAnim); + }; + + // get secondary weapon for a given primary weapon + WeaponType PrimaryToSecondary(WeaponType wt) + { + if (wt==WEAPON_DOUBLECOLT) { + return WEAPON_COLT; + } else if (wt==WEAPON_DOUBLESHOTGUN) { + return WEAPON_SINGLESHOTGUN; + } else if (wt==WEAPON_MINIGUN) { + return WEAPON_TOMMYGUN; +/* } else if (wt==WEAPON_ROCKETLAUNCHER) { + return WEAPON_GRENADELAUNCHER; + */ +/* + } else if (wt==WEAPON_GHOSTBUSTER) { + return WEAPON_LASER; + */ + } else { + return wt; + } + } + // get primary weapon for a given secondary weapon + WeaponType SecondaryToPrimary(WeaponType wt) + { + if (wt==WEAPON_COLT) { + return WEAPON_DOUBLECOLT; + } else if (wt==WEAPON_SINGLESHOTGUN) { + return WEAPON_DOUBLESHOTGUN; + } else if (wt==WEAPON_TOMMYGUN) { + return WEAPON_MINIGUN; +/* } else if (wt==WEAPON_GRENADELAUNCHER) { + return WEAPON_ROCKETLAUNCHER;*/ +/* } else if (wt==WEAPON_LASER) { + return WEAPON_GHOSTBUSTER; + */ + } else { + return wt; + } + } + + /* + * >>>--- WEAPON CHANGE FUNCTIONS ---<<< + */ + + // find first possible weapon in given direction + WeaponType FindWeaponInDirection(INDEX iDir) + { + WeaponType wtOrg = (WeaponType)m_iWantedWeapon; + WeaponType wt = wtOrg; + FOREVER { + (INDEX&)wt += iDir; + if (wtWEAPON_NUKECANNON) { + if (wt>WEAPON_IRONCANNON) { + wt = WEAPON_KNIFE; + } + if (wt==wtOrg) { + break; + } + if ( ( ((1<<(wt-1))&m_iAvailableWeapons) && HasAmmo(wt)) ) { + return wt; + } + } + return m_iWantedWeapon; + } + + // find first primary weapon in given direction + WeaponType FindPrimaryWeaponInDirection(INDEX iDir) + { + WeaponType wtOrg = (WeaponType)m_iWantedWeapon; + WeaponType wt = wtOrg; + FOREVER { + (INDEX&)wt += iDir; + if (wtWEAPON_NUKECANNON) { + if (wt>WEAPON_IRONCANNON) { + wt = WEAPON_KNIFE; + } + if (wt==wtOrg) { + break; + } + WeaponType wtPri = SecondaryToPrimary(wt); + if (wtPri==wtOrg) { + continue; + } + if (((1<<(wtPri-1))&m_iAvailableWeapons) && HasAmmo(wtPri) ) { + return wtPri; + } else if ( ((1<<(wt -1))&m_iAvailableWeapons) && HasAmmo(wt ) ) { + return wt; + } + } + return m_iWantedWeapon; + } + + // select new weapon + void SelectWeaponChange(INDEX iSelect) + { + WeaponType EwtTemp; + // mark that weapon change is required + m_tmWeaponChangeRequired = _pTimer->CurrentTick(); + + // if storing current weapon + if (iSelect==0) { + m_bChangeWeapon = TRUE; + m_iWantedWeapon = WEAPON_NONE; + return; + } + + // if restoring best weapon + if (iSelect==-4) { + SelectNewWeapon() ; + return; + } + + // if flipping weapon + if (iSelect==-3) { + EwtTemp = GetAltWeapon(m_iWantedWeapon); + + // if selecting previous weapon + } else if (iSelect==-2) { + EwtTemp = FindWeaponInDirection(-1); + + // if selecting next weapon + } else if (iSelect==-1) { + EwtTemp = FindWeaponInDirection(+1); + + // if selecting directly + } else { + // flip current weapon + if (iSelect == GetSelectedWeapon(m_iWantedWeapon)) { + EwtTemp = GetAltWeapon(m_iWantedWeapon); + + // change to wanted weapon + } else { + EwtTemp = GetStrongerWeapon(iSelect); + + // if weapon don't exist or don't have ammo flip it + if ( !((1<<(EwtTemp-1))&m_iAvailableWeapons) || !HasAmmo(EwtTemp)) { + EwtTemp = GetAltWeapon(EwtTemp); + } + } + } + + // wanted weapon exist and has ammo + m_bChangeWeapon = ( ((1<<(EwtTemp-1))&m_iAvailableWeapons) && HasAmmo(EwtTemp)); + if (m_bChangeWeapon) { + m_iWantedWeapon = EwtTemp; + } + }; + + + + void MinigunSmoke() + { + if( !hud_bShowWeapon) + { + return; + } + // smoke + CPlayer &pl = (CPlayer&)*m_penPlayer; + if( pl.m_pstState!=PST_DIVE) + { + BOOL b3rdPersonView = TRUE; + if(pl.m_penCamera==NULL && pl.m_pen3rdPersonView==NULL) + { + b3rdPersonView = FALSE; + } + + INDEX ctBulletsFired = ClampUp(m_iBulletsOnFireStart-m_iBullets, INDEX(200)); + for( INDEX iSmoke=0; iSmokesld_vPos = plPipe.pl_PositionVector+pl.en_vCurrentTranslationAbsolute*iSmoke*_pTimer->TickQuantum; + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + psldSmoke->sld_vUp = vUp; + psldSmoke->sld_tmLaunch = _pTimer->CurrentTick()+iSmoke*_pTimer->TickQuantum; + psldSmoke->sld_estType = ESL_BULLET_SMOKE; + psldSmoke->sld_fSize = 0.75f+ctBulletsFired/50.0f; + FLOAT3D vSpeedRelative = FLOAT3D(-0.06f, FRnd()/4.0f, -0.06f); + psldSmoke->sld_vSpeed = vSpeedRelative*m+pl.en_vCurrentTranslationAbsolute; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + } + }; + +procedures: + /* + * >>>--- WEAPON CHANGE PROCEDURE ---<<< + */ + ChangeWeapon() { + // weapon is changed + m_bChangeWeapon = FALSE; + // if this is not current weapon change it + if (m_iCurrentWeapon!=m_iWantedWeapon) { +/* + // iron/nuke cannon changing is special + if( (m_iCurrentWeapon == WEAPON_IRONCANNON) && (m_iWantedWeapon == WEAPON_NUKECANNON) ) + { + autocall ChangeToNukeCannon() EEnd; + // mark that weapon change has ended + m_tmWeaponChangeRequired = 0.0f; + jump Idle(); + } + else if( (m_iCurrentWeapon == WEAPON_NUKECANNON) && (m_iWantedWeapon == WEAPON_IRONCANNON) ) + { + autocall ChangeToIronCannon() EEnd; + // mark that weapon change has ended + m_tmWeaponChangeRequired = 0.0f; + jump Idle(); + } + */ + + // store current weapon + m_iPreviousWeapon = m_iCurrentWeapon; + autocall PutDown() EEnd; + // set new weapon + m_iCurrentWeapon = m_iWantedWeapon; + // remember current weapon for console usage + wpn_iCurrent = m_iCurrentWeapon; + autocall BringUp() EEnd; + + // knife change stand + } else if (m_iWantedWeapon == WEAPON_KNIFE) { + // mark that weapon change has ended + m_tmWeaponChangeRequired = 0.0f; + autocall ChangeKnifeStand() EEnd; +/* // pipebomb reload + } else if (m_iWantedWeapon == WEAPON_PIPEBOMB) { + // mark that weapon change has ended + m_tmWeaponChangeRequired = 0.0f; + jump Reload(); + */ + } + jump Idle(); + }; + + + // put weapon down + PutDown() { + // start weapon put down animation + switch (m_iCurrentWeapon) { + case WEAPON_NONE: + break; + // knife have different stands + case WEAPON_KNIFE: + if (m_iKnifeStand==1) { + m_iAnim = KNIFE_ANIM_PULLOUT; + } else if (m_iKnifeStand==3) { + m_iAnim = KNIFE_ANIM_PULLOUT; + } + break; + case WEAPON_DOUBLECOLT: case WEAPON_COLT: + m_iAnim = COLT_ANIM_DEACTIVATE; + break; + case WEAPON_SINGLESHOTGUN: + m_iAnim = SINGLESHOTGUN_ANIM_DEACTIVATE; + break; + case WEAPON_DOUBLESHOTGUN: + m_iAnim = DOUBLESHOTGUN_ANIM_DEACTIVATE; + break; + case WEAPON_TOMMYGUN: + m_iAnim = TOMMYGUN_ANIM_DEACTIVATE; + break; + case WEAPON_MINIGUN: + m_iAnim = MINIGUN_ANIM_DEACTIVATE; + break; + case WEAPON_ROCKETLAUNCHER: + m_iAnim = ROCKETLAUNCHER_ANIM_DEACTIVATE; + break; + case WEAPON_GRENADELAUNCHER: + m_iAnim = GRENADELAUNCHER_ANIM_DEACTIVATE; + break; +/* case WEAPON_PIPEBOMB: + m_iAnim = HANDWITHBOMB_ANIM_DEACTIVATE; + break; + case WEAPON_FLAMER: + m_iAnim = FLAMER_ANIM_DEACTIVATE; + break; + */ + case WEAPON_LASER: + m_iAnim = LASER_ANIM_DEACTIVATE; + break; +/* + case WEAPON_GHOSTBUSTER: + m_iAnim = GHOSTBUSTER_ANIM_DEACTIVATE; + break; + */ + case WEAPON_IRONCANNON: +// case WEAPON_NUKECANNON: + m_iAnim = CANNON_ANIM_DEACTIVATE; + break; + default: ASSERTALWAYS("Unknown weapon."); + } + // start animator + CPlayerAnimator &plan = (CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator; + plan.BodyPushAnimation(); + if (m_iCurrentWeapon==WEAPON_NONE) { + return EEnd(); + } + + // --->>> COLT -> DOUBLE COLT SPECIFIC <<<--- + if (m_iCurrentWeapon==WEAPON_COLT && m_iWantedWeapon==WEAPON_DOUBLECOLT) { + return EEnd(); + } + + // --->>> DOUBLE COLT SPECIFIC <<<--- + if (m_iCurrentWeapon==WEAPON_DOUBLECOLT) { + m_moWeaponSecond.PlayAnim(m_iAnim, 0); + } + + // --->>> DOUBLE COLT -> COLT SPECIFIC <<<--- + if (m_iCurrentWeapon==WEAPON_DOUBLECOLT && m_iWantedWeapon==WEAPON_COLT) { + autowait(m_moWeapon.GetAnimLength(m_iAnim)); + return EEnd(); + } + +/* + // --->>> PIPEBOMB SPECIFIC <<<--- + if (m_iCurrentWeapon==WEAPON_PIPEBOMB) { + m_moWeapon.PlayAnim(m_iAnim, 0); + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_DEACTIVATE, 0); + autowait(Max(m_moWeapon.GetAnimLength(m_iAnim), m_moWeaponSecond.GetAnimLength(HANDWITHSTICK_ANIM_DEACTIVATE))); + return EEnd(); + } +*/ + + // reload colts automagicaly when puting them away + BOOL bNowColt = m_iCurrentWeapon==WEAPON_COLT || m_iCurrentWeapon==WEAPON_DOUBLECOLT; + BOOL bWantedColt = m_iWantedWeapon==WEAPON_COLT || m_iWantedWeapon==WEAPON_DOUBLECOLT; + if (bNowColt&&!bWantedColt) { + m_iColtBullets = 6; + } + + m_moWeapon.PlayAnim(m_iAnim, 0); + autowait(m_moWeapon.GetAnimLength(m_iAnim)); + return EEnd(); + }; + + // bring up weapon + BringUp() { + // reset weapon draw offset + ResetWeaponMovingOffset(); + // set weapon model for current weapon + SetCurrentWeaponModel(); + // start current weapon bring up animation + switch (m_iCurrentWeapon) { + case WEAPON_KNIFE: + m_iAnim = KNIFE_ANIM_PULL; + m_iKnifeStand = 1; + break; + case WEAPON_COLT: case WEAPON_DOUBLECOLT: + m_iAnim = COLT_ANIM_ACTIVATE; + SetFlare(0, FLARE_REMOVE); + SetFlare(1, FLARE_REMOVE); + break; + case WEAPON_SINGLESHOTGUN: + m_iAnim = SINGLESHOTGUN_ANIM_ACTIVATE; + SetFlare(0, FLARE_REMOVE); + break; + case WEAPON_DOUBLESHOTGUN: + m_iAnim = DOUBLESHOTGUN_ANIM_ACTIVATE; + SetFlare(0, FLARE_REMOVE); + break; + case WEAPON_TOMMYGUN: + m_iAnim = TOMMYGUN_ANIM_ACTIVATE; + SetFlare(0, FLARE_REMOVE); + break; + case WEAPON_MINIGUN: { + CAttachmentModelObject *amo = m_moWeapon.GetAttachmentModel(MINIGUN_ATTACHMENT_BARRELS); + m_aMiniGunLast = m_aMiniGun = amo->amo_plRelative.pl_OrientationAngle(3); + m_iAnim = MINIGUN_ANIM_ACTIVATE; + SetFlare(0, FLARE_REMOVE); + break; } + case WEAPON_ROCKETLAUNCHER: + m_iAnim = ROCKETLAUNCHER_ANIM_ACTIVATE; + break; + case WEAPON_GRENADELAUNCHER: + m_iAnim = GRENADELAUNCHER_ANIM_ACTIVATE; + break; +/* + case WEAPON_PIPEBOMB: + m_iAnim = HANDWITHBOMB_ANIM_ACTIVATE; + break; + case WEAPON_FLAMER: + m_iAnim = FLAMER_ANIM_ACTIVATE; + break; + */ + case WEAPON_LASER: + m_iAnim = LASER_ANIM_ACTIVATE; + break; +/* + case WEAPON_GHOSTBUSTER: + m_iAnim = GHOSTBUSTER_ANIM_ACTIVATE; + break; + */ + case WEAPON_IRONCANNON: +// case WEAPON_NUKECANNON: + m_iAnim = CANNON_ANIM_ACTIVATE; + break; + case WEAPON_NONE: + break; + default: ASSERTALWAYS("Unknown weapon."); + } + // start animator + CPlayerAnimator &plan = (CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator; + plan.BodyPullAnimation(); + + // --->>> DOUBLE COLT -> COLT SPECIFIC <<<--- + if (m_iPreviousWeapon==WEAPON_DOUBLECOLT && m_iCurrentWeapon==WEAPON_COLT) { + // mark that weapon change has ended + m_tmWeaponChangeRequired -= hud_tmWeaponsOnScreen/2; + return EEnd(); + } + + // --->>> DOUBLE COLT SPECIFIC <<<--- + if (m_iCurrentWeapon==WEAPON_DOUBLECOLT) { + m_moWeaponSecond.PlayAnim(m_iAnim, 0); + } + + // --->>> COLT -> COLT DOUBLE SPECIFIC <<<--- + if (m_iPreviousWeapon==WEAPON_COLT && m_iCurrentWeapon==WEAPON_DOUBLECOLT) { + autowait(m_moWeapon.GetAnimLength(m_iAnim)); + // mark that weapon change has ended + m_tmWeaponChangeRequired -= hud_tmWeaponsOnScreen/2; + return EEnd(); + } + + /* + // --->>> PIPEBOMB SPECIFIC <<<--- + if (m_iCurrentWeapon==WEAPON_PIPEBOMB) { + m_moWeapon.PlayAnim(m_iAnim, 0); + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_ACTIVATE, 0); + autowait(Max(m_moWeapon.GetAnimLength(m_iAnim), m_moWeaponSecond.GetAnimLength(HANDWITHSTICK_ANIM_ACTIVATE))); + m_bPipeBombDropped = FALSE; + // mark that weapon change has ended + m_tmWeaponChangeRequired -= hud_tmWeaponsOnScreen/2; + return EEnd(); + } + */ + + m_moWeapon.PlayAnim(m_iAnim, 0); + autowait(m_moWeapon.GetAnimLength(m_iAnim)); + +/* + if( m_iCurrentWeapon == WEAPON_NUKECANNON) + { + autocall ChangeToNukeCannon() EEnd; + } + */ + + // mark that weapon change has ended + m_tmWeaponChangeRequired -= hud_tmWeaponsOnScreen/2; + + return EEnd(); + }; + + + /* + * >>>--- FIRE WEAPON ---<<< + */ + Fire() + { + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_SILENCE, SOF_3D|SOF_VOLUMETRIC); // stop possible sounds + // force ending of weapon change + m_tmWeaponChangeRequired = 0; + + m_bFireWeapon = TRUE; + m_bHasAmmo = HasAmmo(m_iCurrentWeapon); + + // if has no ammo select new weapon + if (!m_bHasAmmo) { + SelectNewWeapon(); + jump Idle(); + } + + // setup 3D sound parameters + Setup3DSoundParameters(); + + // start weapon firing animation for continuous fireing + if (m_iCurrentWeapon==WEAPON_MINIGUN) { + jump MiniGunSpinUp(); +/* } else if (m_iCurrentWeapon==WEAPON_FLAMER) { + jump FlamerStart(); + } else if (m_iCurrentWeapon==WEAPON_GHOSTBUSTER) { + autocall GhostBusterStart() EEnd; + */ + } else if (m_iCurrentWeapon==WEAPON_LASER) { + GetAnimator()->FireAnimation(BODY_ANIM_SHOTGUN_FIRESHORT, AOF_LOOPING); + } else if (m_iCurrentWeapon==WEAPON_TOMMYGUN) { + autocall TommyGunStart() EEnd; + } else if ((m_iCurrentWeapon==WEAPON_IRONCANNON) /*|| (m_iCurrentWeapon==WEAPON_NUKECANNON)*/) { + jump CannonFireStart(); + } + + // clear last lerped bullet position + m_iLastBulletPosition = FLOAT3D(32000.0f, 32000.0f, 32000.0f); + + // reset laser barrel (to start shooting always from left up barrel) + m_iLaserBarrel = 0; + + while (HoldingFire() && m_bHasAmmo) { + // boring animation + ((CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator).m_fLastActionTime = _pTimer->CurrentTick(); + wait() { + on (EBegin) : { + // fire one shot + switch (m_iCurrentWeapon) { + case WEAPON_KNIFE: call SwingKnife(); break; + case WEAPON_COLT: call FireColt(); break; + case WEAPON_DOUBLECOLT: call FireDoubleColt(); break; + case WEAPON_SINGLESHOTGUN: call FireSingleShotgun(); break; + case WEAPON_DOUBLESHOTGUN: call FireDoubleShotgun(); break; + case WEAPON_TOMMYGUN: call FireTommyGun(); break; + case WEAPON_ROCKETLAUNCHER: call FireRocketLauncher(); break; + case WEAPON_GRENADELAUNCHER: call FireGrenadeLauncher(); break; +// case WEAPON_PIPEBOMB: call FirePipeBomb(); break; + case WEAPON_LASER: call FireLaser(); break; +// case WEAPON_GHOSTBUSTER: call FireGhostBuster(); break; + default: ASSERTALWAYS("Unknown weapon."); + } + resume; + } + on (EEnd) : { + stop; + } + } + } + + // stop weapon firing animation for continuous fireing + switch (m_iCurrentWeapon) { + case WEAPON_TOMMYGUN: { jump TommyGunStop(); break; } + case WEAPON_MINIGUN: { jump MiniGunSpinDown(); break; } +// case WEAPON_FLAMER: { jump FlamerStop(); break; } +// case WEAPON_GHOSTBUSTER: { jump GhostBusterStop(); break; } + case WEAPON_LASER: { + GetAnimator()->FireAnimationOff(); + jump Idle(); + } + default: { jump Idle(); } + } + }; + + // ***************** SWING KNIFE ***************** + SwingKnife() { + INDEX iSwing; + + // animator swing + GetAnimator()->FireAnimation(BODY_ANIM_KNIFE_ATTACK, 0); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + // depending on stand choose random attack + switch (m_iKnifeStand) { + case 1: + iSwing = IRnd()%2; + switch (iSwing) { + case 0: m_iAnim = KNIFE_ANIM_ATTACK01; m_fAnimWaitTime = 0.25f; + PlaySound(pl.m_soWeapon0, SOUND_KNIFE_BACK, SOF_3D|SOF_VOLUMETRIC); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Knife_back");} + break; + case 1: m_iAnim = KNIFE_ANIM_ATTACK02; m_fAnimWaitTime = 0.35f; + PlaySound(pl.m_soWeapon1, SOUND_KNIFE_BACK, SOF_3D|SOF_VOLUMETRIC); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Knife_back");} + break; + } + break; + case 3: + iSwing = IRnd()%2; + switch (iSwing) { + case 0: m_iAnim = KNIFE_ANIM_ATTACK01; m_fAnimWaitTime = 0.50f; + PlaySound(pl.m_soWeapon1, SOUND_KNIFE_BACK, SOF_3D|SOF_VOLUMETRIC); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Knife_back");} + break; + case 1: m_iAnim = KNIFE_ANIM_ATTACK02; m_fAnimWaitTime = 0.50f; + PlaySound(pl.m_soWeapon3, SOUND_KNIFE_BACK, SOF_3D|SOF_VOLUMETRIC); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Knife_back");} + break; + } + break; + } + m_moWeapon.PlayAnim(m_iAnim, 0); + if (CutWithKnife(0, 0, /*range=*/3.0f, /*wide=*/2.0f, /*thickness=*/0.5f, /*damage=*/100.0f)) { + autowait(m_fAnimWaitTime); + } else if (TRUE) { + autowait(m_fAnimWaitTime/2); + CutWithKnife(0, 0, /*range=*/3.0f, /*wide=*/2.0f, /*thickness=*/0.5f, /*damage=*/100.0f); + autowait(m_fAnimWaitTime/2); + } + +/* + if (m_iKnifeStand==3) { + InflictRangeDamage(m_penPlayer, DMT_CLOSERANGE, 50.0f, plKnife.pl_PositionVector, 0.75f, 0.75f); + // stand 1 and 2 + } else { + InflictRangeDamage(m_penPlayer, DMT_CLOSERANGE, 100.0f, plKnife.pl_PositionVector, 2.5f, 2.5f); + } + */ + + if (m_moWeapon.GetAnimLength(m_iAnim)-m_fAnimWaitTime>=_pTimer->TickQuantum) { + autowait(m_moWeapon.GetAnimLength(m_iAnim)-m_fAnimWaitTime); + } + return EEnd(); + }; + + // ***************** FIRE COLT ***************** + FireColt() { + GetAnimator()->FireAnimation(BODY_ANIM_COLT_FIRERIGHT, 0); + + // fire bullet + FireOneBullet(wpn_fFX[WEAPON_COLT], wpn_fFY[WEAPON_COLT], 500.0f, 10.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Colt_fire");} + DoRecoil(); + SpawnRangeSound(40.0f); + m_iColtBullets--; + SetFlare(0, FLARE_ADD); + PlayLightAnim(LIGHT_ANIM_COLT_SHOTGUN, 0); + + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_COLT_FIRE, SOF_3D|SOF_VOLUMETRIC); + + /* + if( pl.m_pstState!=PST_DIVE) + { + // smoke + ShellLaunchData &sldRight = pl.m_asldData[pl.m_iFirstEmptySLD]; + sldRight.sld_vPos = FLOAT3D(afRightColtPipe[0], afRightColtPipe[1], afRightColtPipe[2]); + sldRight.sld_tmLaunch = _pTimer->CurrentTick(); + sldRight.sld_estType = ESL_COLT_SMOKE; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + */ + + // random colt fire + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = COLT_ANIM_FIRE1; break; + case 1: iAnim = COLT_ANIM_FIRE2; break; + case 2: iAnim = COLT_ANIM_FIRE3; break; + } + m_moWeapon.PlayAnim(iAnim, 0); + autowait(m_moWeapon.GetAnimLength(iAnim)-0.05f); + m_moWeapon.PlayAnim(COLT_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART); + // no more bullets in colt -> reload + if (m_iColtBullets == 0) { + jump ReloadColt(); + } + return EEnd(); + }; + + // reload colt + ReloadColt() { + if (m_iColtBullets>=6) { + return EEnd(); + } + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon1, SOUND_COLT_RELOAD, SOF_3D|SOF_VOLUMETRIC); + + m_moWeapon.PlayAnim(COLT_ANIM_RELOAD, 0); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Colt_reload");} + autowait(m_moWeapon.GetAnimLength(COLT_ANIM_RELOAD)); + m_iColtBullets = 6; + return EEnd(); + }; + + // ***************** FIRE DOUBLE COLT ***************** + FireDoubleColt() { + // fire first colt - one bullet less in colt + GetAnimator()->FireAnimation(BODY_ANIM_COLT_FIRERIGHT, 0); + FireOneBullet(wpn_fFX[WEAPON_DOUBLECOLT], wpn_fFY[WEAPON_DOUBLECOLT], 500.0f, 10.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Colt_fire");} + + /* + CPlayer &pl1 = (CPlayer&)*m_penPlayer; + if( pl1.m_pstState!=PST_DIVE) + { + // smoke + ShellLaunchData &sldRight = pl1.m_asldData[pl1.m_iFirstEmptySLD]; + sldRight.sld_vPos = FLOAT3D(afRightColtPipe[0], afRightColtPipe[1], afRightColtPipe[2]); + sldRight.sld_tmLaunch = _pTimer->CurrentTick(); + sldRight.sld_estType = ESL_COLT_SMOKE; + pl1.m_iFirstEmptySLD = (pl1.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + */ + + DoRecoil(); + SpawnRangeSound(50.0f); + m_iColtBullets--; + SetFlare(0, FLARE_ADD); + PlayLightAnim(LIGHT_ANIM_COLT_SHOTGUN, 0); + // sound + CPlayer &plSnd = (CPlayer&)*m_penPlayer; + PlaySound(plSnd.m_soWeapon0, SOUND_COLT_FIRE, SOF_3D|SOF_VOLUMETRIC); + + // random colt fire + switch (IRnd()%3) { + case 0: m_iAnim = COLT_ANIM_FIRE1; break; + case 1: m_iAnim = COLT_ANIM_FIRE2; break; + case 2: m_iAnim = COLT_ANIM_FIRE3; break; + } + m_moWeapon.PlayAnim(m_iAnim, 0); // play first colt anim + autowait(m_moWeapon.GetAnimLength(m_iAnim)/2); // wait half of the anim + + // fire second colt + GetAnimator()->FireAnimation(BODY_ANIM_COLT_FIRELEFT, 0); + m_bMirrorFire = TRUE; + FireOneBullet(wpn_fFX[WEAPON_DOUBLECOLT], wpn_fFY[WEAPON_DOUBLECOLT], 500.0f, 10.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Colt_fire");} + + /* + CPlayer &pl2 = (CPlayer&)*m_penPlayer; + if( pl2.m_pstState!=PST_DIVE) + { + // smoke + ShellLaunchData &sldLeft = pl2.m_asldData[pl2.m_iFirstEmptySLD]; + sldLeft.sld_vPos = FLOAT3D(-afRightColtPipe[0], afRightColtPipe[1], afRightColtPipe[2]); + sldLeft.sld_tmLaunch = _pTimer->CurrentTick(); + sldLeft.sld_estType = ESL_COLT_SMOKE; + pl2.m_iFirstEmptySLD = (pl2.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + */ + + DoRecoil(); + m_iSecondFlare = FLARE_ADD; + ((CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator).m_iSecondFlare = FLARE_ADD; + PlayLightAnim(LIGHT_ANIM_COLT_SHOTGUN, 0); + m_bMirrorFire = FALSE; + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon1, SOUND_COLT_FIRE, SOF_3D|SOF_VOLUMETRIC); + + m_moWeaponSecond.PlayAnim(m_iAnim, 0); + autowait(m_moWeapon.GetAnimLength(m_iAnim)/2); // wait half of the anim + + // no more bullets in colt -> reload + if (m_iColtBullets == 0) { + jump ReloadDoubleColt(); + } + return EEnd(); + }; + + // reload double colt + ReloadDoubleColt() { + if (m_iColtBullets>=6) { + return EEnd(); + } + m_moWeapon.PlayAnim(COLT_ANIM_RELOAD, 0); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon2, SOUND_COLT_RELOAD, SOF_3D|SOF_VOLUMETRIC); + // wait half of reload time + autowait(m_moWeapon.GetAnimLength(COLT_ANIM_RELOAD)/2); + + m_moWeaponSecond.PlayAnim(COLT_ANIM_RELOAD, 0); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon3, SOUND_COLT_RELOAD, SOF_3D|SOF_VOLUMETRIC); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Colt_reload");} + + // wait second halt minus half shortest fire animation + autowait(m_moWeapon.GetAnimLength(COLT_ANIM_RELOAD)-0.25f); + + m_iColtBullets = 6; + return EEnd(); + }; + + // ***************** FIRE SINGLESHOTGUN ***************** + FireSingleShotgun() { + // fire one shell + if (m_iShells>0) { + GetAnimator()->FireAnimation(BODY_ANIM_SHOTGUN_FIRELONG, 0); + FireBullets(wpn_fFX[WEAPON_SINGLESHOTGUN], wpn_fFY[WEAPON_SINGLESHOTGUN], + 500.0f, 10.0f, 7, afSingleShotgunPellets, 0.2f, 0.03f); + DoRecoil(); + SpawnRangeSound(60.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Snglshotgun_fire");} + DecAmmo(m_iShells, 1); + SetFlare(0, FLARE_ADD); + PlayLightAnim(LIGHT_ANIM_COLT_SHOTGUN, 0); + m_moWeapon.PlayAnim(GetSP()->sp_bCooperative ? SINGLESHOTGUN_ANIM_FIRE1 : SINGLESHOTGUN_ANIM_FIRE1FAST, 0); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_SINGLESHOTGUN_FIRE, SOF_3D|SOF_VOLUMETRIC); + + if( hud_bShowWeapon) + { + if( pl.m_pstState==PST_DIVE) + { + // bubble + ShellLaunchData &sldBubble = pl.m_asldData[pl.m_iFirstEmptySLD]; + CPlacement3D plShell; + CalcWeaponPosition(FLOAT3D(afSingleShotgunShellPos[0], + afSingleShotgunShellPos[1], afSingleShotgunShellPos[2]), plShell, FALSE); + FLOATmatrix3D m; + MakeRotationMatrixFast(m, plShell.pl_OrientationAngle); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sldBubble.sld_vPos = plShell.pl_PositionVector; + sldBubble.sld_vUp = vUp; + sldBubble.sld_tmLaunch = _pTimer->CurrentTick(); + sldBubble.sld_estType = ESL_BUBBLE; + FLOAT3D vSpeedRelative = FLOAT3D(0.3f, 0.0f, 0.0f); + sldBubble.sld_vSpeed = vSpeedRelative*m; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + else + { + // smoke + ShellLaunchData &sldPipe1 = pl.m_asldData[pl.m_iFirstEmptySLD]; + CPlacement3D plPipe; + CalcWeaponPosition(FLOAT3D(afSingleShotgunPipe[0], afSingleShotgunPipe[1], afSingleShotgunPipe[2]), plPipe, FALSE); + FLOATmatrix3D m; + MakeRotationMatrixFast(m, plPipe.pl_OrientationAngle); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sldPipe1.sld_vPos = plPipe.pl_PositionVector; + sldPipe1.sld_vUp = vUp; + sldPipe1.sld_tmLaunch = _pTimer->CurrentTick(); + sldPipe1.sld_estType = ESL_SHOTGUN_SMOKE; + FLOAT3D vSpeedRelative = FLOAT3D(0, 0.0f, -12.5f); + sldPipe1.sld_vSpeed = vSpeedRelative*m; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + } + + autowait(GetSP()->sp_bCooperative ? 0.5f : 0.375); + /* drop shell */ + + /* add one empty bullet shell */ + CPlacement3D plShell; + CalcWeaponPosition(FLOAT3D(afSingleShotgunShellPos[0], afSingleShotgunShellPos[1], afSingleShotgunShellPos[2]), plShell, FALSE); + + FLOATmatrix3D mRot; + MakeRotationMatrixFast(mRot, plShell.pl_OrientationAngle); + + if( hud_bShowWeapon) + { + CPlayer *penPlayer = GetPlayer(); + ShellLaunchData &sld = penPlayer->m_asldData[penPlayer->m_iFirstEmptySLD]; + sld.sld_vPos = plShell.pl_PositionVector; + FLOAT3D vSpeedRelative = FLOAT3D(FRnd()+2.0f, FRnd()+5.0f, -FRnd()-2.0f); + sld.sld_vSpeed = vSpeedRelative*mRot; + + const FLOATmatrix3D &m = penPlayer->GetRotationMatrix(); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sld.sld_vUp = vUp; + sld.sld_tmLaunch = _pTimer->CurrentTick(); + sld.sld_estType = ESL_SHOTGUN; + // move to next shell position + penPlayer->m_iFirstEmptySLD = (penPlayer->m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + + /* drop shell */ + autowait(m_moWeapon.GetAnimLength( + (GetSP()->sp_bCooperative ? SINGLESHOTGUN_ANIM_FIRE1:SINGLESHOTGUN_ANIM_FIRE1FAST) ) - + (GetSP()->sp_bCooperative ? 0.5f : 0.375f) ); + // no ammo -> change weapon + if (m_iShells<=0) { SelectNewWeapon(); } + } else { + ASSERTALWAYS("SingleShotgun - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + + // ***************** FIRE DOUBLESHOTGUN ***************** + FireDoubleShotgun() { + // fire two shell + if (m_iShells>1) { + GetAnimator()->FireAnimation(BODY_ANIM_SHOTGUN_FIRELONG, 0); + FireBullets(wpn_fFX[WEAPON_DOUBLESHOTGUN], wpn_fFY[WEAPON_DOUBLESHOTGUN], + 500.0f, 10.0f, 14, afDoubleShotgunPellets, 0.3f, 0.03f); + DoRecoil(); + SpawnRangeSound(70.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Dblshotgun_fire");} + DecAmmo(m_iShells, 2); + SetFlare(0, FLARE_ADD); + PlayLightAnim(LIGHT_ANIM_COLT_SHOTGUN, 0); + m_moWeapon.PlayAnim(GetSP()->sp_bCooperative ? DOUBLESHOTGUN_ANIM_FIRE : DOUBLESHOTGUN_ANIM_FIREFAST, 0); + m_moWeaponSecond.PlayAnim(GetSP()->sp_bCooperative ? HANDWITHAMMO_ANIM_FIRE : HANDWITHAMMO_ANIM_FIREFAST, 0); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 1.5f, 1.0f); // fire + PlaySound(pl.m_soWeapon0, SOUND_DOUBLESHOTGUN_FIRE, SOF_3D|SOF_VOLUMETRIC); + + if( hud_bShowWeapon) + { + if( pl.m_pstState==PST_DIVE) + { + // bubble (pipe 1) + ShellLaunchData &sldBubble1 = pl.m_asldData[pl.m_iFirstEmptySLD]; + CPlacement3D plShell; + CalcWeaponPosition(FLOAT3D(-0.11f, 0.1f, -0.3f), plShell, FALSE); + /*CalcWeaponPosition(FLOAT3D(afDoubleShotgunShellPos[0], + afDoubleShotgunShellPos[1], afDoubleShotgunShellPos[2]), plShell, FALSE);*/ + FLOATmatrix3D m; + MakeRotationMatrixFast(m, plShell.pl_OrientationAngle); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sldBubble1.sld_vPos = plShell.pl_PositionVector; + sldBubble1.sld_vUp = vUp; + sldBubble1.sld_tmLaunch = _pTimer->CurrentTick(); + sldBubble1.sld_estType = ESL_BUBBLE; + FLOAT3D vSpeedRelative = FLOAT3D(-0.1f, 0.0f, 0.01f); + sldBubble1.sld_vSpeed = vSpeedRelative*m; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + ShellLaunchData &sldBubble2 = pl.m_asldData[pl.m_iFirstEmptySLD]; + // bubble (pipe 2) + sldBubble2 = sldBubble1; + vSpeedRelative = FLOAT3D(0.1f, 0.0f, -0.2f); + sldBubble2.sld_vSpeed = vSpeedRelative*m; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + else + { + // smoke (pipe 1) + ShellLaunchData &sldPipe1 = pl.m_asldData[pl.m_iFirstEmptySLD]; + CPlacement3D plPipe; + CalcWeaponPosition(FLOAT3D(afDoubleShotgunPipe[0], afDoubleShotgunPipe[1], afDoubleShotgunPipe[2]), plPipe, FALSE); + FLOATmatrix3D m; + MakeRotationMatrixFast(m, plPipe.pl_OrientationAngle); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sldPipe1.sld_vPos = plPipe.pl_PositionVector; + sldPipe1.sld_vUp = vUp; + sldPipe1.sld_tmLaunch = _pTimer->CurrentTick(); + sldPipe1.sld_estType = ESL_SHOTGUN_SMOKE; + FLOAT3D vSpeedRelative = FLOAT3D(-1, 0.0f, -12.5f); + sldPipe1.sld_vSpeed = vSpeedRelative*m; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + // smoke (pipe 2) + ShellLaunchData &sldPipe2 = pl.m_asldData[pl.m_iFirstEmptySLD]; + sldPipe2 = sldPipe1; + vSpeedRelative = FLOAT3D(1, 0.0f, -12.5f); + sldPipe2.sld_vSpeed = vSpeedRelative*m; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + } + + autowait(GetSP()->sp_bCooperative ? 0.25f : 0.15f); + if (m_iShells>=2) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon1, SOUND_DOUBLESHOTGUN_RELOAD, SOF_3D|SOF_VOLUMETRIC); + } + autowait( m_moWeapon.GetAnimLength( + (GetSP()->sp_bCooperative ? DOUBLESHOTGUN_ANIM_FIRE : DOUBLESHOTGUN_ANIM_FIREFAST)) - + (GetSP()->sp_bCooperative ? 0.25f : 0.15f) ); + // no ammo -> change weapon + if (m_iShells<=1) { SelectNewWeapon(); } + } else { + ASSERTALWAYS("DoubleShotgun - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + + // ***************** FIRE TOMMYGUN ***************** + TommyGunStart() { + m_iBulletsOnFireStart = m_iBullets; + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_SILENCE, SOF_3D|SOF_VOLUMETRIC); // stop possible sounds + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 1.5f, 1.0f); // fire + PlaySound(pl.m_soWeapon0, SOUND_TOMMYGUN_FIRE, SOF_LOOP|SOF_3D|SOF_VOLUMETRIC); + PlayLightAnim(LIGHT_ANIM_TOMMYGUN, AOF_LOOPING); + GetAnimator()->FireAnimation(BODY_ANIM_SHOTGUN_FIRESHORT, AOF_LOOPING); + return EEnd(); + }; + + TommyGunStop() { + // smoke + CPlayer &pl = (CPlayer&)*m_penPlayer; + if( pl.m_pstState!=PST_DIVE && hud_bShowWeapon) + { + INDEX ctBulletsFired = ClampUp(m_iBulletsOnFireStart-m_iBullets, INDEX(100)); + for( INDEX iSmoke=0; iSmokesld_vPos = plPipe.pl_PositionVector+pl.en_vCurrentTranslationAbsolute*iSmoke*_pTimer->TickQuantum; + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + psldSmoke->sld_vUp = vUp; + psldSmoke->sld_tmLaunch = _pTimer->CurrentTick()+iSmoke*_pTimer->TickQuantum; + psldSmoke->sld_estType = ESL_BULLET_SMOKE; + psldSmoke->sld_fSize = 0.5f+ctBulletsFired/75.0f; + FLOAT3D vSpeedRelative = FLOAT3D(-0.06f, 0.0f, -0.06f); + psldSmoke->sld_vSpeed = vSpeedRelative*m+pl.en_vCurrentTranslationAbsolute; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + } + + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 0.0f, 1.0f); // mute fire + PlayLightAnim(LIGHT_ANIM_NONE, 0); + GetAnimator()->FireAnimationOff(); + jump Idle(); + }; + + FireTommyGun() { + // fire one bullet + if (m_iBullets>0) { + FireMachineBullet(wpn_fFX[WEAPON_TOMMYGUN], wpn_fFY[WEAPON_TOMMYGUN], + 500.0f, 10.0f, 0.01f, 0.5f); + SpawnRangeSound(50.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Tommygun_fire");} + DecAmmo(m_iBullets, 1); + SetFlare(0, FLARE_ADD); + m_moWeapon.PlayAnim(TOMMYGUN_ANIM_FIRE, AOF_LOOPING|AOF_NORESTART); + + // fireing FX + CPlacement3D plShell; + CalcWeaponPosition(FLOAT3D(afTommygunShellPos[0], afTommygunShellPos[1], afTommygunShellPos[2]), plShell, FALSE); + FLOATmatrix3D mRot; + MakeRotationMatrixFast(mRot, plShell.pl_OrientationAngle); + + if( hud_bShowWeapon) + { + // empty bullet shell + CPlayer &pl = *GetPlayer(); + ShellLaunchData &sld = pl.m_asldData[pl.m_iFirstEmptySLD]; + sld.sld_vPos = plShell.pl_PositionVector; + FLOAT3D vSpeedRelative = FLOAT3D(FRnd()+2.0f, FRnd()+5.0f, -FRnd()-2.0f); + const FLOATmatrix3D &m = pl.GetRotationMatrix(); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sld.sld_vUp = vUp; + sld.sld_vSpeed = vSpeedRelative*mRot; + sld.sld_tmLaunch = _pTimer->CurrentTick(); + sld.sld_estType = ESL_BULLET; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + + // bubble + if( pl.m_pstState==PST_DIVE) + { + ShellLaunchData &sldBubble = pl.m_asldData[pl.m_iFirstEmptySLD]; + CalcWeaponPosition(FLOAT3D(afTommygunShellPos[0], afTommygunShellPos[1], afTommygunShellPos[2]), plShell, FALSE); + MakeRotationMatrixFast(mRot, plShell.pl_OrientationAngle); + sldBubble.sld_vPos = plShell.pl_PositionVector; + sldBubble.sld_vUp = vUp; + sldBubble.sld_tmLaunch = _pTimer->CurrentTick(); + sldBubble.sld_estType = ESL_BUBBLE; + vSpeedRelative = FLOAT3D(0.3f, 0.0f, 0.0f); + sldBubble.sld_vSpeed = vSpeedRelative*mRot; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + } + + autowait(0.1f); + // no ammo -> change weapon + if (m_iBullets<=0) { SelectNewWeapon(); } + } else { + ASSERTALWAYS("TommyGun - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + + // ***************** FIRE MINIGUN ***************** + MiniGunSpinUp() { + // steady anim + m_moWeapon.PlayAnim(MINIGUN_ANIM_WAIT1, AOF_LOOPING|AOF_NORESTART); + // no boring animation + ((CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator).m_fLastActionTime = _pTimer->CurrentTick(); + // clear last lerped bullet position + m_iLastBulletPosition = FLOAT3D(32000.0f, 32000.0f, 32000.0f); + CPlayer &pl = (CPlayer&)*m_penPlayer; + + PlaySound(pl.m_soWeapon0, SOUND_SILENCE, SOF_3D|SOF_VOLUMETRIC); // stop possible sounds + // initialize sound 3D parameters + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 2.0f, 1.0f); // fire + pl.m_soWeapon1.Set3DParameters(25.0f, 1.0f, 1.0f, 1.0f); // spinup/spindown/spin + pl.m_soWeapon2.Set3DParameters(25.0f, 1.0f, 1.0f, 1.0f); // turn on/off click + + // spin start sounds + PlaySound(pl.m_soWeapon2, SOUND_MINIGUN_CLICK, SOF_3D|SOF_VOLUMETRIC); + PlaySound(pl.m_soWeapon1, SOUND_MINIGUN_SPINUP, SOF_3D|SOF_VOLUMETRIC); + pl.m_soWeapon1.SetOffset((m_aMiniGunSpeed/MINIGUN_FULLSPEED)*MINIGUN_SPINUPSOUND); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Minigun_rotateup");} + // while not at full speed and fire is held + while (m_aMiniGunSpeedIsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Minigun_rotate");} + // if firing + if(HoldingFire() && m_iBullets>0) { + // play fire sound + PlaySound(pl.m_soWeapon0, SOUND_MINIGUN_FIRE, SOF_3D|SOF_LOOP|SOF_VOLUMETRIC); + PlayLightAnim(LIGHT_ANIM_TOMMYGUN, AOF_LOOPING); + GetAnimator()->FireAnimation(BODY_ANIM_MINIGUN_FIRESHORT, AOF_LOOPING); + } + + m_iBulletsOnFireStart = m_iBullets; + // while holding fire + while (HoldingFire()) { + // check for ammo pickup during empty spinning + if (!m_bHasAmmo && m_iBullets>0) { + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_MINIGUN_FIRE, SOF_3D|SOF_LOOP|SOF_VOLUMETRIC); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Minigun_fire");} + PlayLightAnim(LIGHT_ANIM_TOMMYGUN, AOF_LOOPING); + GetAnimator()->FireAnimation(BODY_ANIM_MINIGUN_FIRESHORT, AOF_LOOPING); + m_bHasAmmo = TRUE; + } + + // if has ammo + if (m_iBullets>0) { + // fire a bullet + FireMachineBullet(wpn_fFX[WEAPON_MINIGUN], wpn_fFY[WEAPON_MINIGUN], + 750.0f, 10.0f, (GetSP()->sp_bCooperative) ? 0.01f : 0.03f, + ( (GetSP()->sp_bCooperative) ? 0.5f : 0.0f)); + DoRecoil(); + SpawnRangeSound(60.0f); + DecAmmo(m_iBullets, 1); + SetFlare(0, FLARE_ADD); + + /* add one empty bullet shell */ + CPlacement3D plShell; + + // if 1st person view + CPlayer &pl = (CPlayer&)*m_penPlayer; + if(pl.m_penCamera==NULL && pl.m_pen3rdPersonView==NULL) + { + CalcWeaponPosition(FLOAT3D(afMinigunShellPos[0], afMinigunShellPos[1], afMinigunShellPos[2]), plShell, FALSE); + } + // if 3rd person view + else + { + /*CalcWeaponPosition3rdPersonView(FLOAT3D(tmp_af[0], tmp_af[1], tmp_af[2]), plShell, FALSE);*/ + CalcWeaponPosition3rdPersonView(FLOAT3D(afMinigunShellPos3rdView[0], + afMinigunShellPos3rdView[1], afMinigunShellPos3rdView[2]), plShell, FALSE); + } + + FLOATmatrix3D mRot; + MakeRotationMatrixFast(mRot, plShell.pl_OrientationAngle); + + if( hud_bShowWeapon) + { + CPlayer &pl = *GetPlayer(); + ShellLaunchData &sld = pl.m_asldData[pl.m_iFirstEmptySLD]; + sld.sld_vPos = plShell.pl_PositionVector; + FLOAT3D vSpeedRelative = FLOAT3D(FRnd()+2.0f, FRnd()+5.0f, -FRnd()-2.0f); + const FLOATmatrix3D &m = pl.GetRotationMatrix(); + FLOAT3D vUp( m(1,2), m(2,2), m(3,2)); + sld.sld_vUp = vUp; + sld.sld_vSpeed = vSpeedRelative*mRot; + sld.sld_tmLaunch = _pTimer->CurrentTick(); + sld.sld_estType = ESL_BULLET; + // move to next shell position + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + + // bubble + if( pl.m_pstState==PST_DIVE) + { + ShellLaunchData &sldBubble = pl.m_asldData[pl.m_iFirstEmptySLD]; + CalcWeaponPosition(FLOAT3D(afMinigunShellPos[0], afMinigunShellPos[1], afMinigunShellPos[2]), plShell, FALSE); + MakeRotationMatrixFast(mRot, plShell.pl_OrientationAngle); + sldBubble.sld_vPos = plShell.pl_PositionVector; + sldBubble.sld_vUp = vUp; + sldBubble.sld_tmLaunch = _pTimer->CurrentTick(); + sldBubble.sld_estType = ESL_BUBBLE; + vSpeedRelative = FLOAT3D(0.3f, 0.0f, 0.0f); + sldBubble.sld_vSpeed = vSpeedRelative*mRot; + pl.m_iFirstEmptySLD = (pl.m_iFirstEmptySLD+1) % MAX_FLYING_SHELLS; + } + } + // if no ammo + } else { + if( m_bHasAmmo) + { + MinigunSmoke(); + } + // stop fire sound + m_bHasAmmo = FALSE; + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_SILENCE, SOF_3D|SOF_VOLUMETRIC); // stop possible sounds + PlayLightAnim(LIGHT_ANIM_NONE, AOF_LOOPING); + GetAnimator()->FireAnimationOff(); + } + autowait(MINIGUN_TICKTIME); + // spin + m_aMiniGunLast = m_aMiniGun; + m_aMiniGun+=m_aMiniGunSpeed*MINIGUN_TICKTIME; + } + + if( m_bHasAmmo) + { + MinigunSmoke(); + } + + GetAnimator()->FireAnimationOff(); + // stop fire sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 0.0f, 1.0f); // mute fire + PlayLightAnim(LIGHT_ANIM_NONE, AOF_LOOPING); + // start spin down + jump MiniGunSpinDown(); + } + + MiniGunSpinDown() { + CPlayer &pl = (CPlayer&)*m_penPlayer; + // spin down sounds + PlaySound(pl.m_soWeapon3, SOUND_MINIGUN_CLICK, SOF_3D|SOF_VOLUMETRIC); + PlaySound(pl.m_soWeapon1, SOUND_MINIGUN_SPINDOWN, SOF_3D|SOF_VOLUMETRIC|SOF_SMOOTHCHANGE); + pl.m_soWeapon1.SetOffset((1-m_aMiniGunSpeed/MINIGUN_FULLSPEED)*MINIGUN_SPINDNSOUND); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_StopEffect("Minigun_rotate");} + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Minigun_rotatedown");} + + // while still spinning and should not fire + while ( m_aMiniGunSpeed>0 && (!HoldingFire() || m_iBullets<=0)) { + autowait(MINIGUN_TICKTIME); + // spin + m_aMiniGunLast = m_aMiniGun; + m_aMiniGun+=m_aMiniGunSpeed*MINIGUN_TICKTIME; + m_aMiniGunSpeed-=MINIGUN_SPINDNACC*MINIGUN_TICKTIME; + + if (m_iBullets<=0) { + SelectNewWeapon(); + } + + // if weapon should be changed + if (m_bChangeWeapon) { + // stop spinning immediately + m_aMiniGunSpeed = 0.0f; + m_aMiniGunLast = m_aMiniGun; + GetAnimator()->FireAnimationOff(); + jump Idle(); + } + } + // clamp some + m_aMiniGunSpeed = ClampDn( m_aMiniGunSpeed, 0.0f); + m_aMiniGunLast = m_aMiniGun; + + // if should fire + if (HoldingFire() && m_iBullets>0) { + // start spinup + jump MiniGunSpinUp(); + } + + // no boring animation + ((CPlayerAnimator&)*((CPlayer&)*m_penPlayer).m_penAnimator).m_fLastActionTime = _pTimer->CurrentTick(); + + // if out of ammo + if (m_iBullets<=0) { + // can wait without changing while holding fire - specific for movie sequence + while(HoldingFire() && m_iBullets<=0) { + autowait(0.1f); + } + if (m_iBullets<=0) { + // select new weapon + SelectNewWeapon(); + } + } + jump Idle(); + }; + + // ***************** FIRE ROCKETLAUNCHER ***************** + FireRocketLauncher() { + // fire one grenade + if (m_iRockets>0) { + GetAnimator()->FireAnimation(BODY_ANIM_MINIGUN_FIRELONG, 0); + m_moWeapon.PlayAnim(ROCKETLAUNCHER_ANIM_FIRE, 0); + FireRocket(); + + DoRecoil(); + SpawnRangeSound(20.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Rocketlauncher_fire");} + DecAmmo(m_iRockets, 1); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + if( pl.m_soWeapon0.IsPlaying()) + { + PlaySound(pl.m_soWeapon1, SOUND_ROCKETLAUNCHER_FIRE, SOF_3D|SOF_VOLUMETRIC); + } + else + { + PlaySound(pl.m_soWeapon0, SOUND_ROCKETLAUNCHER_FIRE, SOF_3D|SOF_VOLUMETRIC); + } + + autowait(0.05f); + + CModelObject *pmo = &(m_moWeapon.GetAttachmentModel(ROCKETLAUNCHER_ATTACHMENT_ROCKET1)->amo_moModelObject); + pmo->StretchModel(FLOAT3D(0, 0, 0)); + + autowait(m_moWeapon.GetAnimLength(ROCKETLAUNCHER_ANIM_FIRE)-0.05f); + + CModelObject *pmo = &(m_moWeapon.GetAttachmentModel(ROCKETLAUNCHER_ATTACHMENT_ROCKET1)->amo_moModelObject); + pmo->StretchModel(FLOAT3D(1, 1, 1)); + + // no ammo -> change weapon + if (m_iRockets<=0) { SelectNewWeapon(); } + } else { + ASSERTALWAYS("RocketLauncher - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + + // ***************** FIRE GRENADELAUNCHER ***************** + FireGrenadeLauncher() + { + TM_START = _pTimer->CurrentTick(); + // remember time for spring release + F_TEMP = _pTimer->CurrentTick(); + + F_OFFSET_CHG = 0.0f; + m_fWeaponDrawPower = 0.0f; + m_tmDrawStartTime = _pTimer->CurrentTick(); + while (HoldingFire() && ((_pTimer->CurrentTick()-TM_START)<0.75f) ) + { + autowait(_pTimer->TickQuantum); + INDEX iPower = INDEX((_pTimer->CurrentTick()-TM_START)/_pTimer->TickQuantum); + F_OFFSET_CHG = 0.125f/(iPower+2); + m_fWeaponDrawPowerOld = m_fWeaponDrawPower; + m_fWeaponDrawPower += F_OFFSET_CHG; + } + m_tmDrawStartTime = 0.0f; + + + // release spring and fire one grenade + if (m_iGrenades>0) + { + // fire grenade + INDEX iPower = INDEX((_pTimer->CurrentTick()-F_TEMP)/_pTimer->TickQuantum); + FireGrenade( iPower); + SpawnRangeSound(10.0f); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Gnadelauncher");} + DecAmmo(m_iGrenades, 1); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_GRENADELAUNCHER_FIRE, SOF_3D|SOF_VOLUMETRIC); + GetAnimator()->FireAnimation(BODY_ANIM_MINIGUN_FIRELONG, 0); + + // release spring + TM_START = _pTimer->CurrentTick(); + m_fWeaponDrawPowerOld = m_fWeaponDrawPower; + while (m_fWeaponDrawPower>0.0f) + { + autowait(_pTimer->TickQuantum); + m_fWeaponDrawPowerOld = m_fWeaponDrawPower; + m_fWeaponDrawPower -= F_OFFSET_CHG; + m_fWeaponDrawPower = ClampDn( m_fWeaponDrawPower, 0.0f); + F_OFFSET_CHG = F_OFFSET_CHG*10; + } + + // reset moving part's offset + ResetWeaponMovingOffset(); + + // no ammo -> change weapon + if (m_iGrenades<=0) + { + SelectNewWeapon(); + } + else if( TRUE) + { + autowait(0.25f); + } + } else { + ASSERTALWAYS("GrenadeLauncher - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + + return EEnd(); + }; + +/* + // ***************** FIRE PIPEBOMB ***************** + FirePipeBomb() { + // drop one pipebomb + if (m_iGrenades>=0) { + // fire bomb + if (m_bPipeBombDropped) { + m_bPipeBombDropped = FALSE; + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_STICKFIRE, 0); + autowait(0.35f); + // activate pipebomb + SendToTarget(m_penPipebomb, EET_START); + m_penPipebomb = NULL; + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_PIPEBOMB_FIRE, SOF_3D|SOF_VOLUMETRIC); + // no ammo -> change weapon + if (m_iGrenades<=0) { + autowait(m_moWeaponSecond.GetAnimLength(HANDWITHSTICK_ANIM_STICKFIRE)-0.35f); + SelectNewWeapon(); + return EEnd(); + } + // get new bomb + AddAttachmentToModel(this, m_moWeapon, HANDWITHBOMB_ATTACHMENT_BOMB, MODEL_PB_BOMB, + TEXTURE_PB_BOMB, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + m_moWeapon.PlayAnim(HANDWITHBOMB_ANIM_ACTIVATE, 0); + autowait(m_moWeapon.GetAnimLength(HANDWITHBOMB_ANIM_ACTIVATE)); + + // drop bomb + } else if (TRUE) { + m_bPipeBombDropped = TRUE; + // low drop + if (((CPlayer&)*m_penPlayer).en_plViewpoint.pl_OrientationAngle(2) < -20.0f) { + m_moWeapon.PlayAnim(HANDWITHBOMB_ANIM_BOMBTHROW1 ,0); + // high drop + } else { + m_moWeapon.PlayAnim(HANDWITHBOMB_ANIM_BOMBTHROW2 ,0); + } + autowait(0.5f); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon1, SOUND_PIPEBOMB_THROW, SOF_3D|SOF_VOLUMETRIC); + SpawnRangeSound(5.0f); + autowait(0.2f); + // drop bomb + DropPipebomb(); + DecAmmo(m_iGrenades, 1); + RemoveAttachmentFromModel(m_moWeapon, HANDWITHBOMB_ATTACHMENT_BOMB); + autowait(0.2f); + // open stick shield + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_STICKTHROW ,0); + // sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon2, SOUND_PIPEBOMB_OPEN, SOF_3D|SOF_VOLUMETRIC); + autowait(m_moWeaponSecond.GetAnimLength(HANDWITHSTICK_ANIM_STICKTHROW)); + } + } else { + ASSERTALWAYS("Pipebomb - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + + ReloadPipeBomb() { + if (m_bPipeBombDropped) { + m_bPipeBombDropped = FALSE; + // close stick + m_moWeaponSecond.PlayAnim(HANDWITHSTICK_ANIM_STICKRETURN, 0); + // get new bomb + AddAttachmentToModel(this, m_moWeapon, HANDWITHBOMB_ATTACHMENT_BOMB, MODEL_PB_BOMB, + TEXTURE_PB_BOMB, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + m_moWeapon.PlayAnim(HANDWITHBOMB_ANIM_ACTIVATE, 0); + autowait(m_moWeapon.GetAnimLength(HANDWITHBOMB_ANIM_ACTIVATE)); + } + + return EEnd(); + }; + + // ***************** FIRE FLAMER ***************** + FlamerStart() { + m_moWeapon.PlayAnim(FLAMER_ANIM_FIRESTART, 0); + autowait(m_moWeapon.GetAnimLength(FLAMER_ANIM_FIRESTART)); + // play fire sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 1.0f, 0.31f); + pl.m_soWeapon1.Set3DParameters(25.0f, 1.0f, 1.0f, 0.4f); + pl.m_soWeapon2.Set3DParameters(25.0f, 1.0f, 1.0f, 0.3f); + PlaySound(pl.m_soWeapon0, SOUND_FL_FIRE, SOF_3D|SOF_LOOP|SOF_VOLUMETRIC); + PlaySound(pl.m_soWeapon1, SOUND_FL_FIRE, SOF_3D|SOF_LOOP|SOF_VOLUMETRIC); + PlaySound(pl.m_soWeapon2, SOUND_FL_START, SOF_3D|SOF_VOLUMETRIC); + jump FlamerFire(); + }; + + FlamerFire() { + // while holding fire + while (HoldingFire() && m_iNapalm>0) { + // fire + FireFlame(); + DecAmmo(m_iNapalm, 1); + SpawnRangeSound(30.0f); + autowait(0.1f); + } + + if (m_iNapalm<=0) { + m_bHasAmmo = FALSE; + } + + jump FlamerStop(); + }; + + FlamerStop() { + CPlayer &pl = (CPlayer&)*m_penPlayer; + PlaySound(pl.m_soWeapon0, SOUND_FL_STOP, SOF_3D|SOF_VOLUMETRIC|SOF_SMOOTHCHANGE); + PlaySound(pl.m_soWeapon1, SOUND_FL_STOP, SOF_3D|SOF_VOLUMETRIC|SOF_SMOOTHCHANGE); + FireFlame(); + // link last flame with nothing (if not NULL or deleted) + if (m_penFlame!=NULL && !(m_penFlame->GetFlags()&ENF_DELETED)) { + ((CProjectile&)*m_penFlame).m_penParticles = NULL; + m_penFlame = NULL; + } + + m_moWeapon.PlayAnim(FLAMER_ANIM_FIREEND, 0); + autowait(m_moWeapon.GetAnimLength(FLAMER_ANIM_FIREEND)); + + if (m_iNapalm<=0) { + // select new weapon + SelectNewWeapon(); + } + jump Idle(); + }; + */ + // ***************** FIRE LASER ***************** + FireLaser() { + // fire one cell + if (m_iElectricity>0) { + autowait(0.1f); + m_moWeapon.PlayAnim(LASER_ANIM_FIRE, AOF_LOOPING|AOF_NORESTART); + FireLaserRay(); + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Laser_fire");} + DecAmmo(m_iElectricity, 1); + // sound + SpawnRangeSound(20.0f); + CPlayer &pl = (CPlayer&)*m_penPlayer; + // activate barrel anim + switch(m_iLaserBarrel) { + case 0: { // barrel lu + CModelObject *pmo = &(m_moWeapon.GetAttachmentModel(LASER_ATTACHMENT_LEFTUP)->amo_moModelObject); + pmo->PlayAnim(BARREL_ANIM_FIRE, 0); + PlaySound(pl.m_soWeapon0, SOUND_LASER_FIRE, SOF_3D|SOF_VOLUMETRIC); + break; } + case 3: { // barrel rd + CModelObject *pmo = &(m_moWeapon.GetAttachmentModel(LASER_ATTACHMENT_RIGHTDOWN)->amo_moModelObject); + pmo->PlayAnim(BARREL_ANIM_FIRE, 0); + PlaySound(pl.m_soWeapon1, SOUND_LASER_FIRE, SOF_3D|SOF_VOLUMETRIC); + break; } + case 1: { // barrel ld + CModelObject *pmo = &(m_moWeapon.GetAttachmentModel(LASER_ATTACHMENT_LEFTDOWN)->amo_moModelObject); + pmo->PlayAnim(BARREL_ANIM_FIRE, 0); + PlaySound(pl.m_soWeapon2, SOUND_LASER_FIRE, SOF_3D|SOF_VOLUMETRIC); + break; } + case 2: { // barrel ru + CModelObject *pmo = &(m_moWeapon.GetAttachmentModel(LASER_ATTACHMENT_RIGHTUP)->amo_moModelObject); + pmo->PlayAnim(BARREL_ANIM_FIRE, 0); + PlaySound(pl.m_soWeapon3, SOUND_LASER_FIRE, SOF_3D|SOF_VOLUMETRIC); + break; } + } + // next barrel + m_iLaserBarrel = (m_iLaserBarrel+1)&3; + // no napalm -> change weapon + if (m_iElectricity<=0) { SelectNewWeapon(); } + } else { + ASSERTALWAYS("Laser - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + + /* + // ***************** FIRE GHOSTBUSTER ***************** + GhostBusterStart() { + GetAnimator()->FireAnimation(BODY_ANIM_SHOTGUN_FIRESHORT, AOF_LOOPING); + // create ray + m_penGhostBusterRay = CreateEntity(GetPlacement(), CLASS_GHOSTBUSTERRAY); + EGhostBusterRay egbr; + egbr.penOwner = this; + m_penGhostBusterRay->Initialize(egbr); + // play anim + m_moWeapon.PlayAnim(GHOSTBUSTER_ANIM_FIRE, AOF_LOOPING|AOF_NORESTART); + // play fire sound + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 1.0f, 1.0f); // fire + PlaySound(pl.m_soWeapon0, SOUND_GB_FIRE, SOF_3D|SOF_LOOP|SOF_VOLUMETRIC); + return EEnd(); + }; + + GhostBusterStop() { + GetAnimator()->FireAnimationOff(); + // destroy ray + ((CGhostBusterRay&)*m_penGhostBusterRay).DestroyGhostBusterRay(); + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.m_soWeapon0.Stop(); + jump Idle(); + }; + + FireGhostBuster() { + // fire one cell + if (m_iElectricity>0) { + FireGhostBusterRay(); + DecAmmo(m_iElectricity, 1); + SpawnRangeSound(20.0f); + autowait(0.05f); + // no napalm -> change weapon + if (m_iElectricity<=0) { SelectNewWeapon(); } + } else { + ASSERTALWAYS("GhostBuster - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + return EEnd(); + }; + */ + + // ***************** FIRE CANNON ***************** + + CannonFireStart() + { + m_tmDrawStartTime = _pTimer->CurrentTick(); + TM_START = _pTimer->CurrentTick(); + F_OFFSET_CHG = 0.0f; + m_fWeaponDrawPower = 0.0f; + CPlayer &pl = (CPlayer&)*m_penPlayer; + if( m_iIronBalls&1) + { + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 3.0f, 1.0f); + PlaySound(pl.m_soWeapon0, SOUND_CANNON_PREPARE, SOF_3D|SOF_VOLUMETRIC); + } + else + { + pl.m_soWeapon1.Set3DParameters(25.0f, 1.0f, 3.0f, 1.0f); + PlaySound(pl.m_soWeapon1, SOUND_CANNON_PREPARE, SOF_3D|SOF_VOLUMETRIC); + } + + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Canon_prepare");} + while (HoldingFire() && ((_pTimer->CurrentTick()-TM_START)<1.0f) ) + { + autowait(_pTimer->TickQuantum); + INDEX iPower = INDEX((_pTimer->CurrentTick()-TM_START)/_pTimer->TickQuantum); + F_OFFSET_CHG = 0.25f/(iPower+2); + m_fWeaponDrawPowerOld = m_fWeaponDrawPower; + m_fWeaponDrawPower += F_OFFSET_CHG; + } + m_tmDrawStartTime = 0.0f; + CPlayer &pl = (CPlayer&)*m_penPlayer; + if( m_iIronBalls&1) + { + // turn off the sound + pl.m_soWeapon0.Set3DParameters(25.0f, 1.0f, 0.0f, 1.0f); + } + else + { + // turn off the sound + pl.m_soWeapon1.Set3DParameters(25.0f, 1.0f, 0.0f, 1.0f); + } + + // fire one ball + if ( ((m_iIronBalls>0) && (m_iCurrentWeapon == WEAPON_IRONCANNON) ) /*|| + ((m_iNukeBalls>0) && (m_iCurrentWeapon == WEAPON_NUKECANNON) ) */) + { + INDEX iPower = INDEX((_pTimer->CurrentTick()-TM_START)/_pTimer->TickQuantum); + GetAnimator()->FireAnimation(BODY_ANIM_MINIGUN_FIRELONG, 0); + + // adjust volume of cannon fireing acording to launch power + if( m_iIronBalls&1) + { + pl.m_soWeapon2.Set3DParameters(100.0f, 25.0f, 2.0f+iPower*0.05f, 1.0f); + PlaySound(pl.m_soWeapon2, SOUND_CANNON, SOF_3D|SOF_VOLUMETRIC); + } + else + { + pl.m_soWeapon3.Set3DParameters(100.0f, 25.0f, 2.0f+iPower*0.05f, 1.0f); + PlaySound(pl.m_soWeapon3, SOUND_CANNON, SOF_3D|SOF_VOLUMETRIC); + } + + m_moWeapon.PlayAnim(CANNON_ANIM_FIRE, 0); + FireCannonBall( iPower); +/* + if (m_iCurrentWeapon == WEAPON_NUKECANNON) + { + DecAmmo(m_iNukeBalls, 1); + } + else + { + */ + if(_pNetwork->IsPlayerLocal(m_penPlayer)) {IFeel_PlayEffect("Canon");} + DecAmmo(m_iIronBalls, 1); +// } + SpawnRangeSound(30.0f); + + TM_START = _pTimer->CurrentTick(); + m_fWeaponDrawPowerOld = m_fWeaponDrawPower; + while (m_fWeaponDrawPower>0.0f || + ((_pTimer->CurrentTick()-TM_START)TickQuantum); + m_fWeaponDrawPowerOld = m_fWeaponDrawPower; + m_fWeaponDrawPower -= F_OFFSET_CHG; + m_fWeaponDrawPower = ClampDn( m_fWeaponDrawPower, 0.0f); + F_OFFSET_CHG = F_OFFSET_CHG*2; + } + + // reset moving part's offset + ResetWeaponMovingOffset(); + + // no cannon balls -> change weapon + if ( ((m_iIronBalls<=0) && (m_iCurrentWeapon == WEAPON_IRONCANNON) ) /*|| + ((m_iNukeBalls<=0) && (m_iCurrentWeapon == WEAPON_NUKECANNON) ) */) + { + SelectNewWeapon(); + } + } + else + { + ASSERTALWAYS("Cannon - Auto weapon change not working."); + m_bFireWeapon = m_bHasAmmo = FALSE; + } + jump Idle(); + }; + + + /* + * >>>--- RELOAD WEAPON ---<<< + */ + Reload() { + m_bReloadWeapon = FALSE; + + // reload + if (m_iCurrentWeapon == WEAPON_COLT) { + autocall ReloadColt() EEnd; + } else if (m_iCurrentWeapon == WEAPON_DOUBLECOLT) { + autocall ReloadDoubleColt() EEnd; +/* } else if (m_iCurrentWeapon == WEAPON_PIPEBOMB) { + autocall ReloadPipeBomb() EEnd;*/ + } + + jump Idle(); + }; + + + /* + * >>>--- KNIFE STAND CHANGE ---<<< + */ + ChangeKnifeStand(EVoid) { +/* if (m_iKnifeStand==1) { + // change from knife stand 1 to stand 3 + m_moWeapon.PlayAnim(KNIFE_ANIM_STAND1TOSTAND3, 0); + autowait(m_moWeapon.GetAnimLength(KNIFE_ANIM_STAND1TOSTAND3)); + m_iKnifeStand = 3; + } else if (m_iKnifeStand==3) { + // change from knife stand 3 to stand 1 + m_moWeapon.PlayAnim(KNIFE_ANIM_STAND3TOSTAND1, 0); + autowait(m_moWeapon.GetAnimLength(KNIFE_ANIM_STAND3TOSTAND1)); + m_iKnifeStand = 1; + } + */ + return EEnd(); + }; + + ChangeToIronCannon(EVoid) + { +/* CModelObject &moLight = m_moWeapon.GetAttachmentModel(CANNON_ATTACHMENT_LIGHT)->amo_moModelObject; + moLight.PlayAnim( LIGHT_ANIM_DOWN, 0); + autowait(moLight.GetAnimLength(LIGHT_ANIM_DOWN)); + + CModelObject &moNukeBox = m_moWeapon.GetAttachmentModel(CANNON_ATTACHMENT_NUKEBOX)->amo_moModelObject; + moNukeBox.PlayAnim( NUKEBOX_ANIM_CLOSE, 0); + autowait(moNukeBox.GetAnimLength(NUKEBOX_ANIM_CLOSE)); + */ + + m_iPreviousWeapon = m_iCurrentWeapon; + m_iCurrentWeapon = WEAPON_IRONCANNON; + m_iWantedWeapon = m_iCurrentWeapon; + + return EEnd(); + } + +/* ChangeToNukeCannon(EVoid) + { + CModelObject &moNukeBox = m_moWeapon.GetAttachmentModel(CANNON_ATTACHMENT_NUKEBOX)->amo_moModelObject; + moNukeBox.PlayAnim( NUKEBOX_ANIM_OPEN, 0); + autowait(moNukeBox.GetAnimLength(NUKEBOX_ANIM_OPEN)); + + CModelObject &moLight = m_moWeapon.GetAttachmentModel(CANNON_ATTACHMENT_LIGHT)->amo_moModelObject; + moLight.PlayAnim( LIGHT_ANIM_UP, 0); + autowait(moLight.GetAnimLength(LIGHT_ANIM_UP)); + + m_iPreviousWeapon = m_iCurrentWeapon; + m_iCurrentWeapon = WEAPON_NUKECANNON; + m_iWantedWeapon = m_iCurrentWeapon; + + return EEnd(); + }; +*/ + + /* + * >>>--- BORING WEAPON ANIMATION ---<<< + */ + BoringWeaponAnimation() { + // select new mode change animation + FLOAT fWait = 0.0f; + switch (m_iCurrentWeapon) { + case WEAPON_KNIFE: fWait = KnifeBoring(); break; + case WEAPON_COLT: fWait = ColtBoring(); break; + case WEAPON_DOUBLECOLT: fWait = DoubleColtBoring(); break; + case WEAPON_SINGLESHOTGUN: fWait = SingleShotgunBoring(); break; + case WEAPON_DOUBLESHOTGUN: fWait = DoubleShotgunBoring(); break; + case WEAPON_TOMMYGUN: fWait = TommyGunBoring(); break; + case WEAPON_MINIGUN: fWait = MiniGunBoring(); break; + case WEAPON_ROCKETLAUNCHER: fWait = RocketLauncherBoring(); break; + case WEAPON_GRENADELAUNCHER: fWait = GrenadeLauncherBoring(); break; +// case WEAPON_PIPEBOMB: fWait = PipeBombBoring(); break; +// case WEAPON_FLAMER: fWait = FlamerBoring(); break; + case WEAPON_LASER: fWait = LaserBoring(); break; +// case WEAPON_GHOSTBUSTER: fWait = GhostBusterBoring(); break; + case WEAPON_IRONCANNON: /*case WEAPON_NUKECANNON:*/ fWait = CannonBoring(); break; + default: ASSERTALWAYS("Unknown weapon."); + } + if (fWait > 0.0f) { autowait(fWait); } + + return EBegin(); + }; + + + + /* + * >>>--- NO WEAPON ACTION ---<<< + */ + Idle() { + + wait() { + on (EBegin) : { + // play default anim + PlayDefaultAnim(); + + // weapon changed + if (m_bChangeWeapon) { + jump ChangeWeapon(); + } + // fire pressed start fireing + if (m_bFireWeapon) { + jump Fire(); + } + // reload pressed + if (m_bReloadWeapon) { + jump Reload(); + } + resume; + } + // select weapon + on (ESelectWeapon eSelect) : { + // try to change weapon + SelectWeaponChange(eSelect.iWeapon); + if (m_bChangeWeapon) { + jump ChangeWeapon(); + } + resume; + } + // fire pressed + on (EFireWeapon) : { + jump Fire(); + } + // reload pressed + on (EReloadWeapon) : { + jump Reload(); + } + // boring weapon animation + on (EBoringWeapon) : { + call BoringWeaponAnimation(); + } + } + }; + + // weapons wait here while player is dead, so that stupid animations wouldn't play + Stopped() + { + // kill all possible sounds, animations, etc + ResetWeaponMovingOffset(); + CPlayer &pl = (CPlayer&)*m_penPlayer; + pl.m_soWeapon0.Stop(); + pl.m_soWeapon1.Stop(); + pl.m_soWeapon2.Stop(); + pl.m_soWeapon3.Stop(); + PlayLightAnim(LIGHT_ANIM_NONE, 0); + wait() { + // after level change + on (EPostLevelChange) : { return EBegin(); }; + on (EStart) : { return EBegin(); }; + otherwise() : { resume; }; + } + } + + + + /* + * >>>--- M A I N ---<<< + */ + Main(EWeaponsInit eInit) { + // remember the initial parameters + ASSERT(eInit.penOwner!=NULL); + m_penPlayer = eInit.penOwner; + + // declare yourself as a void + InitAsVoid(); + SetFlags(GetFlags()|ENF_CROSSESLEVELS|ENF_NOTIFYLEVELCHANGE); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set weapon model for current weapon + SetCurrentWeaponModel(); + + // play default anim + PlayDefaultAnim(); + + wait() { + on (EBegin) : { call Idle(); } + on (ESelectWeapon eSelect) : { + // try to change weapon + SelectWeaponChange(eSelect.iWeapon); + resume; + }; + // before level change + on (EPreLevelChange) : { + // stop everything + m_bFireWeapon = FALSE; + call Stopped(); + resume; + } + on (EFireWeapon) : { + // start fireing + m_bFireWeapon = TRUE; + resume; + } + on (EReleaseWeapon) : { + // stop fireing + m_bFireWeapon = FALSE; + resume; + } + on (EReloadWeapon) : { + // reload wepon + m_bReloadWeapon = TRUE; + resume; + } + on (EStop) : { call Stopped(); } + on (EEnd) : { stop; } + } + + // cease to exist + Destroy(); + + return; + }; +}; diff --git a/Sources/Entities/PlayerWeaponsEffects.es b/Sources/Entities/PlayerWeaponsEffects.es new file mode 100644 index 0000000..5261868 --- /dev/null +++ b/Sources/Entities/PlayerWeaponsEffects.es @@ -0,0 +1,108 @@ +405 +%{ +#include "Entities/StdH/StdH.h" +#define EPF_MODEL_SHELL (EPF_ONBLOCK_BOUNCE|EPF_TRANSLATEDBYGRAVITY|EPF_MOVABLE) +#define ECF_MODEL_SHELL ( \ + ((ECBI_BRUSH|ECBI_MODEL_HOLDER)<PrecacheModel(MODEL_SG_SHELL); + pdec->PrecacheTexture(TEXTURE_SG_SHELL); + pdec->PrecacheModel(MODEL_MG_SHELL); + pdec->PrecacheTexture(TEXTURE_MG_SHELL); +} +%} + +class CPlayerWeaponsEffects: CMovableEntity { +name "Player Weapons Effects"; +thumbnail ""; +features "CanBePredictable"; + +properties: + 1 CEntityPointer m_penOwner, // class which owns it + 2 enum WeaponEffectType m_EwetEffect = WET_SHOTGUNSHELL, // weapon effect type + +components: +// ************** SHOTGUN SHELL ************ + 1 model MODEL_SG_SHELL "Models\\Weapons\\SingleShotgun\\Shell\\Shell.mdl", + 2 texture TEXTURE_SG_SHELL "Models\\Weapons\\SingleShotgun\\Shell\\Shell.tex", +// ************** MACHINEGUN SHELL ************ + 3 model MODEL_MG_SHELL "Models\\Weapons\\Minigun\\Shell\\Shell.mdl", + 4 texture TEXTURE_MG_SHELL "Models\\Weapons\\Minigun\\Shell\\Shell.tex", + +functions: +procedures: + ShotgunShell(EVoid) { + // init as model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_SHELL); + SetCollisionFlags(ECF_MODEL_SHELL); + // set appearance + GetModelObject()->StretchModel(FLOAT3D(0.5f, 0.5f, 0.5f)); + SetModel(MODEL_SG_SHELL); + ModelChangeNotify(); + SetModelMainTexture(TEXTURE_SG_SHELL); + // speed + LaunchAsFreeProjectile(FLOAT3D(FRnd()+2.0f, FRnd()+5.0f, -FRnd()-2.0f), (CMovableEntity*)&*m_penOwner); + // wait a while + autowait(1.5f); + return EEnd(); + }; + MachinegunShell(EVoid) { + // init as model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_SHELL); + SetCollisionFlags(ECF_MODEL_SHELL); + // set appearance + GetModelObject()->StretchModel(FLOAT3D(0.5f, 0.5f, 0.5f)); + SetModel(MODEL_MG_SHELL); + ModelChangeNotify(); + SetModelMainTexture(TEXTURE_MG_SHELL); + // speed + LaunchAsFreeProjectile(FLOAT3D(FRnd()+2.0f, FRnd()+5.0f, -FRnd()-2.0f), (CMovableEntity*)&*m_penOwner); + // wait a while + autowait(0.5f); + return EEnd(); + }; + + Main(EWeaponEffectInit eInit) { + // remember the initial parameters + ASSERT(eInit.penOwner!=NULL); + m_penOwner = eInit.penOwner; + m_EwetEffect = eInit.EwetEffect; + SetFlags(GetFlags()|ENF_SEETHROUGH); + SetPredictable(TRUE); + + if (m_EwetEffect==WET_SHOTGUNSHELL) { + autocall ShotgunShell() EEnd; + } else if (m_EwetEffect==WET_MACHINEGUNSHELL) { + autocall MachinegunShell() EEnd; + } else { + ASSERTALWAYS("Uknown weapon effect type"); + } + + // cease to exist + Destroy(); + + return; + }; +}; + diff --git a/Sources/Entities/Projectile.es b/Sources/Entities/Projectile.es new file mode 100644 index 0000000..84de6f9 --- /dev/null +++ b/Sources/Entities/Projectile.es @@ -0,0 +1,2543 @@ +501 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Weapons/Laser/Projectile/LaserProjectile.h" +#include "Entities/EnemyBase.h" +//#include "Entities/Dragonman.h" +#include "Models/Enemies/Elementals/Projectile/IcePyramid.h" +#include "Models/Enemies/ElementalLava/Projectile/LavaStone.h" +#include "Models/Enemies/ElementalLava/Projectile/LavaBomb.h" +#include "Models/Enemies/Headman/Projectile/Blade.h" +#include "Models/Enemies/HuanMan/Projectile/Projectile.h" +#include "Models/Enemies/Cyborg/Projectile/LaserProjectile.h" + +#include "Entities/PlayerWeapons.h" + +#define DEVIL_LASER_SPEED 100.0f +#define DEVIL_ROCKET_SPEED 60.0f +%} + +uses "Entities/BasicEffects"; +uses "Entities/Light"; +//uses "Entities/Flame"; + +enum ProjectileType { + 0 PRT_ROCKET "Rocket", // player rocket + 1 PRT_GRENADE "Grenade", // player grenade + 2 PRT_FLAME "Flame", // player flamer flame + 3 PRT_LASER_RAY "Laser", // player laser ray + 4 PRT_WALKER_ROCKET "WalkerRocket", // walker rocket + + 10 PRT_CATMAN_FIRE "Catman", // catman fire + + 11 PRT_HEADMAN_FIRECRACKER "Firecracker", // headman firecracker + 12 PRT_HEADMAN_ROCKETMAN "Rocketman", // headman rocketman + 13 PRT_HEADMAN_BOMBERMAN "Bomberman", // headman bomberman + + 14 PRT_BONEMAN_FIRE "Boneman", // boneman fire + + 15 PRT_WOMAN_FIRE "Woman", // woman fire + + 16 PRT_DRAGONMAN_FIRE "Dragonman", // dragonman fire + 17 PRT_DRAGONMAN_STRONG_FIRE "Dragonman Strong", // dragonman strong fire + + 18 PRT_STONEMAN_FIRE "Stoneman", // stoneman fire rock + 19 PRT_STONEMAN_BIG_FIRE "Stoneman Big", // stoneman big fire rock + 20 PRT_STONEMAN_LARGE_FIRE "Stoneman Large", // stoneman large fire rock + 21 PRT_LAVAMAN_BIG_BOMB "Lavaman Big Bomb", // lavaman big bomb + 22 PRT_LAVAMAN_BOMB "Lavaman Bomb", // lavaman bomb + 23 PRT_LAVAMAN_STONE "Lavaman Stone", // lavaman rock projectile + 27 PRT_ICEMAN_FIRE "Iceman", // iceman ice cube + 28 PRT_ICEMAN_BIG_FIRE "Iceman Big", // iceman big ice cube + 29 PRT_ICEMAN_LARGE_FIRE "Iceman Large", // iceman large ice cube + + 41 PRT_HUANMAN_FIRE "Huanman", // huanman fire + + 42 PRT_FISHMAN_FIRE "Fishman", // fishman fire + + 43 PRT_MANTAMAN_FIRE "Mantaman", // mantaman fire + + 44 PRT_CYBORG_LASER "Cyborg Laser", // cyborg laser + 45 PRT_CYBORG_BOMB "Cyborg Bomb", // cyborg bomb + + 50 PRT_LAVA_COMET "Lava Comet", // lava comet + 51 PRT_BEAST_PROJECTILE "Beast Projectile", // beast projectile + 52 PRT_BEAST_BIG_PROJECTILE "Beast Big Projectile", // big beast projectile + 53 PRT_BEAST_DEBRIS "Beast Debris", // beast projectile's debris + 54 PRT_BEAST_BIG_DEBRIS "Beast Big Debris", // big beast projectile's debris + 55 PRT_DEVIL_LASER "Devil Laser", // devil laser + 56 PRT_DEVIL_ROCKET "Devil Rocket", // devil rocket + 57 PRT_DEVIL_GUIDED_PROJECTILE "Devil Guided Projectile", // devil guided projectile +}; + +enum ProjectileMovingType { + 0 PMT_FLYING "", // flying through space + 1 PMT_SLIDING "", // sliding on floor + 2 PMT_GUIDED "", // guided projectile +}; + + +// input parameter for launching the projectile +event ELaunchProjectile { + CEntityPointer penLauncher, // who launched it + enum ProjectileType prtType, // type of projectile + FLOAT fSpeed, // optional - projectile speed (only for some projectiles) +}; + + +%{ +#define DRAGONMAN_NORMAL 0 +#define DRAGONMAN_STRONG 1 + +#define ELEMENTAL_LARGE 2 +#define ELEMENTAL_BIG 1 +#define ELEMENTAL_NORMAL 0 + +#define ELEMENTAL_STONEMAN 0 +#define ELEMENTAL_LAVAMAN 1 +#define ELEMENTAL_ICEMAN 2 + +void CProjectile_OnInitClass(void) +{ +} + +void CProjectile_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) +{ + pdec->PrecacheTexture(TEX_REFL_BWRIPLES01); + pdec->PrecacheTexture(TEX_REFL_BWRIPLES02); + pdec->PrecacheTexture(TEX_REFL_LIGHTMETAL01); + pdec->PrecacheTexture(TEX_REFL_LIGHTBLUEMETAL01); + pdec->PrecacheTexture(TEX_REFL_DARKMETAL); + pdec->PrecacheTexture(TEX_REFL_PURPLE01); + + pdec->PrecacheTexture(TEX_SPEC_WEAK); + pdec->PrecacheTexture(TEX_SPEC_MEDIUM); + pdec->PrecacheTexture(TEX_SPEC_STRONG); + + switch ((ProjectileType)iUser) { + case PRT_ROCKET : + case PRT_WALKER_ROCKET : + case PRT_DEVIL_ROCKET : + pdec->PrecacheModel(MODEL_ROCKET ); + pdec->PrecacheTexture(TEXTURE_ROCKET); + pdec->PrecacheSound(SOUND_FLYING ); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_ROCKET); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_SHOCKWAVE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_ROCKET_PLANE); + break; + case PRT_GRENADE: + pdec->PrecacheModel(MODEL_GRENADE); + pdec->PrecacheTexture(TEXTURE_GRENADE); + pdec->PrecacheSound(SOUND_GRENADE_BOUNCE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_GRENADE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_SHOCKWAVE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_GRENADE_PLANE); + break; + case PRT_FLAME: + pdec->PrecacheModel(MODEL_FLAME); + pdec->PrecacheClass(CLASS_FLAME); + + break; + case PRT_LASER_RAY: + pdec->PrecacheModel(MODEL_LASER ); + pdec->PrecacheTexture(TEXTURE_GREEN_LASER ); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_LASERWAVE); + break; + + case PRT_CATMAN_FIRE: + pdec->PrecacheModel(MODEL_CATMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_CATMAN_FIRE ); + break; + + case PRT_HEADMAN_FIRECRACKER: + pdec->PrecacheModel(MODEL_HEADMAN_FIRECRACKER ); + pdec->PrecacheTexture(TEXTURE_HEADMAN_FIRECRACKER ); + break; + case PRT_HEADMAN_ROCKETMAN: + pdec->PrecacheModel(MODEL_HEADMAN_BLADE ); + pdec->PrecacheTexture(TEXTURE_HEADMAN_BLADE ); + pdec->PrecacheModel(MODEL_HEADMAN_BLADE_FLAME ); + pdec->PrecacheTexture(TEXTURE_HEADMAN_BLADE_FLAME ); + break; + case PRT_HEADMAN_BOMBERMAN: + pdec->PrecacheModel(MODEL_HEADMAN_BOMB ); + pdec->PrecacheTexture(TEXTURE_HEADMAN_BOMB ); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BOMB); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_GRENADE_PLANE); + break; + + case PRT_BONEMAN_FIRE: + pdec->PrecacheModel(MODEL_BONEMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_BONEMAN_FIRE ); + break; + + case PRT_WOMAN_FIRE: + pdec->PrecacheModel(MODEL_WOMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_WOMAN_FIRE ); + break; + + case PRT_DRAGONMAN_FIRE: + case PRT_DRAGONMAN_STRONG_FIRE: + pdec->PrecacheModel(MODEL_DRAGONMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_DRAGONMAN_FIRE1 ); + pdec->PrecacheTexture(TEXTURE_DRAGONMAN_FIRE2 ); + break; + + case PRT_STONEMAN_FIRE: + case PRT_STONEMAN_BIG_FIRE: + case PRT_STONEMAN_LARGE_FIRE: + pdec->PrecacheModel(MODEL_ELEM_STONE ); + pdec->PrecacheTexture(TEXTURE_ELEM_STONE ); + break; + case PRT_LAVAMAN_BIG_BOMB: + case PRT_LAVAMAN_BOMB: + case PRT_LAVAMAN_STONE: + pdec->PrecacheModel(MODEL_ELEM_LAVA_STONE); + pdec->PrecacheModel(MODEL_ELEM_LAVA_STONE_FLARE); + pdec->PrecacheModel(MODEL_ELEM_LAVA_BOMB); + pdec->PrecacheModel(MODEL_ELEM_LAVA_BOMB_FLARE); + pdec->PrecacheTexture(TEXTURE_ELEM_LAVA_STONE); + pdec->PrecacheTexture(TEXTURE_ELEM_LAVA_STONE_FLARE ); + pdec->PrecacheTexture(TEXTURE_ELEM_LAVA_BOMB); + pdec->PrecacheTexture(TEXTURE_ELEM_LAVA_BOMB_FLARE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_SHOCKWAVE); + pdec->PrecacheClass(CLASS_BLOOD_SPRAY); + break; + case PRT_ICEMAN_FIRE: + case PRT_ICEMAN_BIG_FIRE: + case PRT_ICEMAN_LARGE_FIRE: + pdec->PrecacheModel(MODEL_ELEM_ICE ); + pdec->PrecacheModel(MODEL_ELEM_ICE_FLARE ); + pdec->PrecacheTexture(TEXTURE_ELEM_ICE ); + //pdec->PrecacheTexture(TEXTURE_ELEM_ICE_FLARE); + break; + + case PRT_HUANMAN_FIRE: + pdec->PrecacheModel(MODEL_HUANMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_HUANMAN_FIRE ); + pdec->PrecacheModel(MODEL_HUANMAN_FLARE ); + pdec->PrecacheTexture(TEXTURE_HUANMAN_FLARE ); + break; + + case PRT_FISHMAN_FIRE: + pdec->PrecacheModel(MODEL_FISHMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_FISHMAN_FIRE ); + break; + + case PRT_MANTAMAN_FIRE: + pdec->PrecacheModel(MODEL_MANTAMAN_FIRE ); + pdec->PrecacheTexture(TEXTURE_MANTAMAN_FIRE ); + break; + + case PRT_DEVIL_LASER: + /* + pdec->PrecacheModel(MODEL_DEVIL_LASER ); + pdec->PrecacheTexture(TEXTURE_DEVIL_LASER ); + break; + */ + + case PRT_CYBORG_LASER: + case PRT_CYBORG_BOMB: + pdec->PrecacheModel(MODEL_CYBORG_LASER ); + pdec->PrecacheTexture(TEXTURE_CYBORG_LASER ); + pdec->PrecacheModel(MODEL_CYBORG_BOMB ); + pdec->PrecacheTexture(TEXTURE_CYBORG_BOMB ); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_BOMB); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_GRENADE_PLANE); + break; + + case PRT_LAVA_COMET: + pdec->PrecacheModel(MODEL_LAVA ); + pdec->PrecacheTexture(TEXTURE_LAVA ); + pdec->PrecacheModel(MODEL_LAVA_FLARE ); + pdec->PrecacheTexture(TEXTURE_LAVA_FLARE); + break; + case PRT_BEAST_PROJECTILE: + case PRT_BEAST_DEBRIS: + pdec->PrecacheSound(SOUND_BEAST_FLYING ); + pdec->PrecacheModel(MODEL_BEAST_FIRE); + pdec->PrecacheTexture(TEXTURE_BEAST_FIRE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_CANNON); + break; + case PRT_BEAST_BIG_PROJECTILE: + case PRT_DEVIL_GUIDED_PROJECTILE: + case PRT_BEAST_BIG_DEBRIS: + pdec->PrecacheSound(SOUND_BEAST_FLYING ); + pdec->PrecacheModel(MODEL_BEAST_FIRE); + pdec->PrecacheTexture(TEXTURE_BEAST_BIG_FIRE); + pdec->PrecacheClass(CLASS_BASIC_EFFECT, BET_LIGHT_CANNON); + break; + default: + ASSERT(FALSE); + } +} +%} + + +class export CProjectile : CMovableModelEntity { +name "Projectile"; +thumbnail ""; +features "ImplementsOnInitClass", "ImplementsOnPrecache", "CanBePredictable"; + +properties: + 1 CEntityPointer m_penLauncher, // who lanuched it + 2 enum ProjectileType m_prtType = PRT_ROCKET, // type of the projectile + 3 enum ProjectileMovingType m_pmtMove = PMT_FLYING, // projectile moving type + 4 CEntityPointer m_penParticles, // another entity for particles + 5 CEntityPointer m_penTarget, // guided projectile's target + + 10 FLOAT m_fSpeed = 0.0f, // projectile speed (optional, only for some projectiles) + 11 FLOAT m_fIgnoreTime = 0.0f, // time when laucher will be ignored + 12 FLOAT m_fFlyTime = 0.0f, // fly time before explode/disappear + 13 FLOAT m_fStartTime = 0.0f, // start time when launched + 14 FLOAT m_fDamageAmount = 0.0f, // damage amount when hit something + 15 FLOAT m_fRangeDamageAmount = 0.0f, // range damage amount + 16 FLOAT m_fDamageHotSpotRange = 0.0f, // hot spot range damage for exploding projectile + 17 FLOAT m_fDamageFallOffRange = 0.0f, // fall off range damage for exploding projectile + 18 FLOAT m_fSoundRange = 0.0f, // sound range where explosion can be heard + 19 BOOL m_bExplode = FALSE, // explode -> range damage + 20 BOOL m_bLightSource = FALSE, // projectile is also light source + 21 BOOL m_bCanHitHimself = FALSE, // projectile can him himself + 22 BOOL m_bCanBeDestroyed = FALSE, // projectile can be destroyed from something else + 23 FLOAT m_fWaitAfterDeath = 0.0f, // wait after death for particles + 24 FLOAT m_aRotateSpeed = 0.0f, // speed of rotation for guided projectiles + 25 FLOAT m_tmExpandBox = 0.0f, // expand collision after a few seconds + 26 FLOAT m_tmInvisibility = 0.0f, // don't render before given time + + 30 CSoundObject m_soEffect, // sound channel + +{ + CLightSource m_lsLightSource; +} + +components: + 1 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 2 class CLASS_LIGHT "Classes\\Light.ecl", + 3 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + 4 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", + +// ********* PLAYER ROCKET ********* + 5 model MODEL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.mdl", + 6 texture TEXTURE_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.tex", + 8 sound SOUND_FLYING "Sounds\\Weapons\\RocketFly.wav", + 9 sound SOUND_BEAST_FLYING "Sounds\\Weapons\\ProjectileFly.wav", + +// ********* PLAYER GRENADE ********* + 10 model MODEL_GRENADE "Models\\Weapons\\GrenadeLauncher\\Grenade\\Grenade.mdl", + 11 texture TEXTURE_GRENADE "Models\\Weapons\\GrenadeLauncher\\Grenade\\Grenade.tex", + 12 sound SOUND_GRENADE_BOUNCE "Models\\Weapons\\GrenadeLauncher\\Sounds\\Bounce.wav", + +// ********* PLAYER FLAME ********* + 15 model MODEL_FLAME "Models\\Weapons\\Flamer\\Projectile\\Invisible.mdl", + 16 class CLASS_FLAME "Classes\\Flame.ecl", + +// ********* CATMAN FIRE ********* + 20 model MODEL_CATMAN_FIRE "Models\\Enemies\\Catman\\Projectile\\Projectile.mdl", + 21 texture TEXTURE_CATMAN_FIRE "Models\\Enemies\\Catman\\Projectile\\Projectile.tex", + +// ********* HEADMAN FIRE ********* + 30 model MODEL_HEADMAN_FIRECRACKER "Models\\Enemies\\Headman\\Projectile\\FireCracker.mdl", + 31 texture TEXTURE_HEADMAN_FIRECRACKER "Models\\Enemies\\Headman\\Projectile\\Texture.tex", + 32 model MODEL_HEADMAN_BLADE "Models\\Enemies\\Headman\\Projectile\\Blade.mdl", + 33 texture TEXTURE_HEADMAN_BLADE "Models\\Enemies\\Headman\\Projectile\\Blade.tex", + 34 model MODEL_HEADMAN_BLADE_FLAME "Models\\Enemies\\Headman\\Projectile\\FireTrail.mdl", + 35 texture TEXTURE_HEADMAN_BLADE_FLAME "Models\\Enemies\\Headman\\Projectile\\FireTrail.tex", + 36 model MODEL_HEADMAN_BOMB "Models\\Enemies\\Headman\\Projectile\\Bomb.mdl", + 37 texture TEXTURE_HEADMAN_BOMB "Models\\Enemies\\Headman\\Projectile\\Bomb.tex", + +// ********* LAVA ********* + 40 model MODEL_LAVA "Models\\Effects\\Debris\\Lava01\\Lava.mdl", + 41 texture TEXTURE_LAVA "Models\\Effects\\Debris\\Lava01\\Lava.tex", + 42 model MODEL_LAVA_FLARE "Models\\Effects\\Debris\\Lava01\\LavaFlare.mdl", + 43 texture TEXTURE_LAVA_FLARE "Models\\Effects\\Debris\\Lava01\\Flare.tex", + +// ********* PLAYER LASER ********* + 50 model MODEL_LASER "Models\\Weapons\\Laser\\Projectile\\LaserProjectile.mdl", + 51 texture TEXTURE_GREEN_LASER "Models\\Weapons\\Laser\\Projectile\\LaserProjectile.tex", + 52 texture TEXTURE_BLUE_LASER "Models\\Weapons\\Laser\\Projectile\\LaserProjectileBlue.tex", + +// ********* BONEMAN FIRE ********* + 60 model MODEL_BONEMAN_FIRE "Models\\Enemies\\Boneman\\Projectile\\Projectile.mdl", + 61 texture TEXTURE_BONEMAN_FIRE "Models\\Enemies\\Boneman\\Projectile\\Projectile.tex", + +// ********* WOMAN FIRE ********* + 65 model MODEL_WOMAN_FIRE "Models\\Enemies\\Woman\\Projectile\\Projectile.mdl", + 66 texture TEXTURE_WOMAN_FIRE "Models\\Enemies\\Woman\\Projectile\\Projectile.tex", + +// ********* DRAGONMAN FIRE ********* + 70 model MODEL_DRAGONMAN_FIRE "Models\\Enemies\\Dragonman\\Projectile\\Projectile.mdl", + 71 texture TEXTURE_DRAGONMAN_FIRE1 "Models\\Enemies\\Dragonman\\Projectile\\Projectile1.tex", + 72 texture TEXTURE_DRAGONMAN_FIRE2 "Models\\Enemies\\Dragonman\\Projectile\\Projectile2.tex", + +// ********* ELEMENTAL FIRE ********* + 80 model MODEL_ELEM_STONE "Models\\Enemies\\Elementals\\Projectile\\Stone.mdl", + 81 model MODEL_ELEM_ICE "Models\\Enemies\\Elementals\\Projectile\\IcePyramid.mdl", + 82 model MODEL_ELEM_ICE_FLARE "Models\\Enemies\\Elementals\\Projectile\\IcePyramidFlare.mdl", + 83 model MODEL_ELEM_LAVA_BOMB "Models\\Enemies\\Elementals\\Projectile\\LavaBomb.mdl", + 84 model MODEL_ELEM_LAVA_BOMB_FLARE "Models\\Enemies\\Elementals\\Projectile\\LavaBombFlare.mdl", + 85 model MODEL_ELEM_LAVA_STONE "Models\\Enemies\\Elementals\\Projectile\\LavaStone.mdl", + 86 model MODEL_ELEM_LAVA_STONE_FLARE "Models\\Enemies\\Elementals\\Projectile\\LavaStoneFlare.mdl", + + 90 texture TEXTURE_ELEM_STONE "Models\\Enemies\\Elementals\\Projectile\\Stone.tex", + 91 texture TEXTURE_ELEM_ICE "Models\\Enemies\\Elementals\\Projectile\\IcePyramid.tex", + //92 texture TEXTURE_ELEM_ICE_FLARE "Textures\\Effects\\Flares\\03\\Flare06.tex", + 93 texture TEXTURE_ELEM_LAVA_BOMB "Models\\Enemies\\Elementals\\Projectile\\LavaBomb.tex", + 94 texture TEXTURE_ELEM_LAVA_BOMB_FLARE "Models\\Enemies\\Elementals\\Projectile\\LavaBombFlare.tex", + 95 texture TEXTURE_ELEM_LAVA_STONE "Models\\Enemies\\Elementals\\Projectile\\LavaStone.tex", + 96 texture TEXTURE_ELEM_LAVA_STONE_FLARE "Models\\Enemies\\Elementals\\Projectile\\LavaBombFlare.tex", + +// ********* HUANMAN FIRE ********* +105 model MODEL_HUANMAN_FIRE "Models\\Enemies\\Huanman\\Projectile\\Projectile.mdl", +106 texture TEXTURE_HUANMAN_FIRE "Models\\Enemies\\Huanman\\Projectile\\Projectile.tex", +107 model MODEL_HUANMAN_FLARE "Models\\Enemies\\Huanman\\Projectile\\Flare.mdl", +108 texture TEXTURE_HUANMAN_FLARE "Textures\\Effects\\Flares\\01\\WhiteRedRing66.tex", + +// ********* FISHMAN FIRE ********* +110 model MODEL_FISHMAN_FIRE "Models\\Enemies\\Fishman\\Projectile\\Projectile.mdl", +111 texture TEXTURE_FISHMAN_FIRE "Models\\Enemies\\Fishman\\Projectile\\Water.tex", + +// ********* FISHMAN FIRE ********* +120 model MODEL_MANTAMAN_FIRE "Models\\Enemies\\Mantaman\\Projectile\\Projectile.mdl", +121 texture TEXTURE_MANTAMAN_FIRE "Models\\Enemies\\Mantaman\\Projectile\\Water.tex", + +// ********* CYBORG FIRE ********* +130 model MODEL_CYBORG_LASER "Models\\Weapons\\Laser\\Projectile\\LaserProjectile.mdl", +132 texture TEXTURE_CYBORG_LASER "Models\\Weapons\\Laser\\Projectile\\LaserProjectileBlue.tex", +133 model MODEL_CYBORG_BOMB "Models\\Enemies\\Cyborg\\Projectile\\Projectile.mdl", +134 texture TEXTURE_CYBORG_BOMB "Models\\Enemies\\Cyborg\\Projectile\\Projectile.tex", + +// ********* DEVIL FIRE ********* +/* +135 model MODEL_DEVIL_LASER "Models\\Enemies\\Devil\\Weapons\\DevilLaserProjectile.mdl", +136 texture TEXTURE_DEVIL_LASER "Models\\Enemies\\Devil\\Weapons\\DevilLaserProjectile.tex", +*/ + +// ********* BEAST FIRE ********* +140 model MODEL_BEAST_FIRE "Models\\Enemies\\Beast\\Projectile\\Projectile.mdl", +141 texture TEXTURE_BEAST_FIRE "Models\\Enemies\\Beast\\Projectile\\Projectile.tex", +142 texture TEXTURE_BEAST_BIG_FIRE "Models\\Enemies\\Beast\\Projectile\\ProjectileBig.tex", + +// ************** REFLECTIONS ************** +200 texture TEX_REFL_BWRIPLES01 "Models\\ReflectionTextures\\BWRiples01.tex", +201 texture TEX_REFL_BWRIPLES02 "Models\\ReflectionTextures\\BWRiples02.tex", +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", +203 texture TEX_REFL_LIGHTBLUEMETAL01 "Models\\ReflectionTextures\\LightBlueMetal01.tex", +204 texture TEX_REFL_DARKMETAL "Models\\ReflectionTextures\\DarkMetal.tex", +205 texture TEX_REFL_PURPLE01 "Models\\ReflectionTextures\\Purple01.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + + +functions: + // premoving + void PreMoving(void) { + if (m_tmExpandBox>0) { + if (_pTimer->CurrentTick()>m_fStartTime+m_tmExpandBox) { + ChangeCollisionBoxIndexWhenPossible(1); + m_tmExpandBox = 0; + } + } + CMovableModelEntity::PreMoving(); + } + + // postmoving + void PostMoving(void) { + CMovableModelEntity::PostMoving(); + // if flamer flame + if (m_prtType==PRT_FLAME) { + // if came to water + CContentType &ctDn = GetWorld()->wo_actContentTypes[en_iDnContent]; + // stop existing + if (!(ctDn.ct_ulFlags&CTF_BREATHABLE_LUNGS)) { + m_fWaitAfterDeath = 0.0f; // immediate stop + SendEvent(EEnd()); + } + } + }; + + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CMovableModelEntity::Read_t(istr); + // setup light source + if( m_bLightSource) { + SetupLightSource(TRUE); + } + } + + // dump sync data to text file + export void DumpSync_t(CTStream &strm, INDEX iExtensiveSyncCheck) // throw char * + { + CMovableModelEntity ::DumpSync_t(strm, iExtensiveSyncCheck); + strm.FPrintF_t("projectile type: %d\n", m_prtType); + strm.FPrintF_t("launcher:"); + if (m_penLauncher!=NULL) { + strm.FPrintF_t("id:%05d '%s'(%s) (%g, %g, %g)\n", + m_penLauncher->en_ulID, + (const char*)m_penLauncher->GetName(), m_penLauncher->GetClass()->ec_pdecDLLClass->dec_strName, + m_penLauncher->GetPlacement().pl_PositionVector(1), + m_penLauncher->GetPlacement().pl_PositionVector(2), + m_penLauncher->GetPlacement().pl_PositionVector(3)); + } else { + strm.FPrintF_t("\n"); + } + } + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if( m_bLightSource && !IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + export void Copy(CEntity &enOther, ULONG ulFlags) + { + CMovableModelEntity::Copy(enOther, ulFlags); + CProjectile *penOther = (CProjectile *)(&enOther); + if (ulFlags©_PREDICTOR) { + //m_lsLightSource; + //SetupLightSource(); //? is this ok !!!! + m_bLightSource = FALSE; + } + } + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + // if time now is inside invisibility time, don't render model + CModelObject *pmo = GetModelObject(); + if ( (pmo != NULL) && (_pTimer->GetLerpedCurrentTick() < (m_fStartTime+m_tmInvisibility) ) ) + { + // make it invisible + pmo->mo_colBlendColor = 0; + } + else + { + // make it visible + pmo->mo_colBlendColor = C_WHITE|CT_OPAQUE; + } + return CEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + } + + // Setup light source + void SetupLightSource(BOOL bLive) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 0.0f; + switch (m_prtType) { + case PRT_ROCKET: + case PRT_WALKER_ROCKET: + case PRT_DEVIL_ROCKET: + if( bLive) + { + lsNew.ls_colColor = 0xA0A080FF; + } + else + { + lsNew.ls_colColor = C_BLACK|CT_OPAQUE; + } + lsNew.ls_rFallOff = 5.0f; + lsNew.ls_plftLensFlare = &_lftYellowStarRedRingFar; + break; + case PRT_GRENADE: + lsNew.ls_colColor = 0x2F1F0F00; + lsNew.ls_rFallOff = 2.0f; + lsNew.ls_rHotSpot = 0.2f; + lsNew.ls_plftLensFlare = &_lftYellowStarRedRingFar; + break; + case PRT_FLAME: + lsNew.ls_colColor = C_dRED; + lsNew.ls_rFallOff = 1.0f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_LASER_RAY: + lsNew.ls_colColor = C_vdGREEN; + lsNew.ls_rFallOff = 1.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_CATMAN_FIRE: + lsNew.ls_colColor = C_BLUE; + lsNew.ls_rFallOff = 3.5f; + lsNew.ls_plftLensFlare = &_lftCatmanFireGlow; + break; + case PRT_HEADMAN_FIRECRACKER: + lsNew.ls_colColor = C_ORANGE; + lsNew.ls_rFallOff = 1.5f; + //lsNew.ls_plftLensFlare = &_lftProjectileStarGlow; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_HEADMAN_ROCKETMAN: + lsNew.ls_colColor = C_YELLOW; + lsNew.ls_rFallOff = 1.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_WOMAN_FIRE: + lsNew.ls_colColor = C_WHITE; + lsNew.ls_rFallOff = 3.5f; + lsNew.ls_plftLensFlare = &_lftCatmanFireGlow; + break; + case PRT_DRAGONMAN_FIRE: + lsNew.ls_colColor = C_YELLOW; + lsNew.ls_rFallOff = 3.5f; + lsNew.ls_plftLensFlare = &_lftProjectileYellowBubbleGlow; + break; + case PRT_DRAGONMAN_STRONG_FIRE: + lsNew.ls_colColor = C_RED; + lsNew.ls_rFallOff = 3.5f; + lsNew.ls_plftLensFlare = &_lftProjectileStarGlow; + break; + case PRT_HUANMAN_FIRE: + lsNew.ls_colColor = C_lBLUE; + lsNew.ls_rFallOff = 2.0f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_FISHMAN_FIRE: + lsNew.ls_colColor = C_lBLUE; + lsNew.ls_rFallOff = 2.0f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_MANTAMAN_FIRE: + lsNew.ls_colColor = C_lBLUE; + lsNew.ls_rFallOff = 2.0f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_CYBORG_LASER: + lsNew.ls_colColor = C_dBLUE; + lsNew.ls_rFallOff = 1.5f; + lsNew.ls_plftLensFlare = NULL; + break; + case PRT_DEVIL_LASER: + lsNew.ls_colColor = C_dBLUE; + lsNew.ls_rFallOff = 5.0f; + lsNew.ls_plftLensFlare = &_lftYellowStarRedRingFar; + break; + default: + ASSERTALWAYS("Unknown light source"); + } + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + + // render particles + void RenderParticles(void) { + switch (m_prtType) { + case PRT_ROCKET: + case PRT_WALKER_ROCKET: + { + Particles_RocketTrail(this, 1.0f); + break; + } + case PRT_DEVIL_ROCKET: + { + Particles_RocketTrail(this, 8.0f); + break; + } + case PRT_GRENADE: { + //Particles_GrenadeTrail(this); + FLOAT fSpeedRatio = en_vCurrentTranslationAbsolute.Length()/140.0f; + Particles_CannonBall(this, fSpeedRatio); + break; + } + case PRT_FLAME: { + // elapsed time + FLOAT fTimeElapsed, fParticlesTimeElapsed; + fTimeElapsed = _pTimer->GetLerpedCurrentTick() - m_fStartTime; + // not NULL or deleted + if (m_penParticles!=NULL && !(m_penParticles->GetFlags()&ENF_DELETED)) { + // draw particles with another projectile + if (IsOfClass(m_penParticles, "Projectile")) { + fParticlesTimeElapsed = _pTimer->GetLerpedCurrentTick() - ((CProjectile&)*m_penParticles).m_fStartTime; + Particles_FlameThrower(GetLerpedPlacement(), m_penParticles->GetLerpedPlacement(), + fTimeElapsed, fParticlesTimeElapsed); + // draw particles with player weapons +/* + } else if (IsOfClass(m_penParticles, "Player Weapons")) { + CPlacement3D plFlame; + ((CPlayerWeapons&)*m_penParticles).GetFlamerSourcePlacement(plFlame); + Particles_FlameThrower(GetLerpedPlacement(), plFlame, fTimeElapsed, 0.0f); + */ +/* // draw particles with dragonman + } else if (IsOfClass(m_penParticles, "Dragonman")) { + CPlacement3D plFlame; + ((CDragonman&)*m_penParticles).GetFlamerSourcePlacement(plFlame); + Particles_FlameThrower(GetLerpedPlacement(), plFlame, fTimeElapsed, 0.0f); + */ + } + } + break; + } + case PRT_CATMAN_FIRE: Particles_RocketTrail(this, 1.0f); break; + case PRT_HEADMAN_FIRECRACKER: Particles_FirecrackerTrail(this); break; + case PRT_HEADMAN_ROCKETMAN: Particles_Fireball01Trail(this); break; + case PRT_HEADMAN_BOMBERMAN: Particles_BombTrail(this); break; + case PRT_LAVA_COMET: Particles_LavaTrail(this); break; + case PRT_LAVAMAN_BIG_BOMB: Particles_LavaBombTrail(this, 4.0f); break; + case PRT_LAVAMAN_BOMB: Particles_LavaBombTrail(this, 1.0f); break; + case PRT_BEAST_PROJECTILE: Particles_BeastProjectileTrail( this, 2.0f, 0.25f, 48); break; + case PRT_BEAST_BIG_PROJECTILE: + Particles_BeastBigProjectileTrail( this, 4.0f, 0.25f, 0.0f, 64); + break; + case PRT_DEVIL_GUIDED_PROJECTILE: + Particles_BeastBigProjectileTrail( this, 6.0f, 0.375f, 0.0f, 64); + break; + case PRT_BEAST_DEBRIS: Particles_BeastProjectileDebrisTrail(this, 0.20f); break; + case PRT_BEAST_BIG_DEBRIS: Particles_BeastProjectileDebrisTrail(this, 0.25f); break; + } + } + + + + +/************************************************************ + * PLAYER ROCKET / GRENADE * + ************************************************************/ +void PlayerRocket(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetModel(MODEL_ROCKET); + SetModelMainTexture(TEXTURE_ROCKET); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + // play the flying sound + m_soEffect.Set3DParameters(20.0f, 2.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_FLYING, SOF_3D|SOF_LOOP); + m_fFlyTime = 30.0f; + if( GetSP()->sp_bCooperative) + { + m_fDamageAmount = 100.0f; + m_fRangeDamageAmount = 50.0f; + } + else + { + m_fDamageAmount = 75.0f; + m_fRangeDamageAmount = 75.0f; + } + m_fDamageHotSpotRange = 4.0f; + m_fDamageFallOffRange = 8.0f; + m_fSoundRange = 50.0f; + m_bExplode = TRUE; + m_bLightSource = TRUE; + m_bCanHitHimself = TRUE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 1.125f; + m_tmExpandBox = 0.1f; + m_tmInvisibility = 0.05f; + SetHealth(5.0f); + m_pmtMove = PMT_FLYING; +}; + +void WalkerRocket(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetModel(MODEL_ROCKET); + SetModelMainTexture(TEXTURE_ROCKET); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + // play the flying sound + m_soEffect.Set3DParameters(20.0f, 2.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_FLYING, SOF_3D|SOF_LOOP); + m_fFlyTime = 30.0f; + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + m_fDamageAmount = 40.0f; + m_fRangeDamageAmount = 20.0f; + } else { + m_fDamageAmount = 100.0f; + m_fRangeDamageAmount = 50.0f; + } + m_fDamageHotSpotRange = 4.0f; + m_fDamageFallOffRange = 8.0f; + m_fSoundRange = 50.0f; + m_bExplode = TRUE; + m_bLightSource = TRUE; + m_bCanHitHimself = TRUE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 1.125f; + m_tmExpandBox = 0.1f; + m_tmInvisibility = 0.05f; + SetHealth(5.0f); + m_pmtMove = PMT_FLYING; +}; + +void WalkerRocketExplosion(void) { + PlayerRocketExplosion(); +} + +void PlayerRocketExplosion(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_ROCKET; + ese.vStretch = FLOAT3D(1,1,1); + SpawnEffect(GetPlacement(), ese); + // spawn sound event in range + if( IsDerivedFromClass( m_penLauncher, "Player")) { + SpawnRangeSound( m_penLauncher, this, SNDT_PLAYER, m_fSoundRange); + } + + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // stain + ese.betType = BET_EXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // shock wave + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // second explosion on plane + ese.betType = BET_ROCKET_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + } + } +}; + + +void PlayerGrenade(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetModel(MODEL_GRENADE); + SetModelMainTexture(TEXTURE_GRENADE); + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 5.0f, -m_fSpeed), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, FRnd()*120.0f+120.0f, FRnd()*250.0f-125.0f)); + en_fBounceDampNormal = 0.75f; + en_fBounceDampParallel = 0.6f; + en_fJumpControlMultiplier = 0.0f; + en_fCollisionSpeedLimit = 45.0f; + en_fCollisionDamageFactor = 10.0f; + m_fFlyTime = 3.0f; + m_fDamageAmount = 75.0f; + m_fRangeDamageAmount = 100.0f; + m_fDamageHotSpotRange = 4.0f; + m_fDamageFallOffRange = 8.0f; + m_fSoundRange = 50.0f; + m_bExplode = TRUE; + en_fDeceleration = 25.0f; + m_bLightSource = TRUE; + m_bCanHitHimself = TRUE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + SetHealth(20.0f); + m_pmtMove = PMT_SLIDING; + m_tmInvisibility = 0.05f; + m_tmExpandBox = 0.1f; +}; + +void PlayerGrenadeExplosion(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_GRENADE; + ese.vStretch = FLOAT3D(1,1,1); + SpawnEffect(GetPlacement(), ese); + // spawn sound event in range + if( IsDerivedFromClass( m_penLauncher, "Player")) { + SpawnRangeSound( m_penLauncher, this, SNDT_PLAYER, m_fSoundRange); + } + + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // wall stain + ese.betType = BET_EXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // shock wave + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // second explosion on plane + ese.betType = BET_GRENADE_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + } + } +}; + + + +/************************************************************ + * PLAYER FLAME * + ************************************************************/ +void PlayerFlame(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_FLAME); + // add player's forward velocity to flame + CMovableEntity *penPlayer = (CMovableEntity*)(CEntity*)m_penLauncher; + FLOAT3D vDirection = penPlayer->en_vCurrentTranslationAbsolute; + FLOAT3D vFront = -GetRotationMatrix().GetColumn(3); + FLOAT fSpeedFwd = ClampDn( vDirection%vFront, 0.0f); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -(15.0f+fSpeedFwd)), penPlayer); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 0.7f; + m_fDamageAmount = 10.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.3f; + m_pmtMove = PMT_FLYING; +}; + + + +/************************************************************ + * PLAYER LASER * + ************************************************************/ +void PlayerLaserRay(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_LASER); + CModelObject *pmo = GetModelObject(); + if(pmo != NULL) + { + pmo->PlayAnim( LASERPROJECTILE_ANIM_GROW, 0); + } + SetModelMainTexture(TEXTURE_GREEN_LASER); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -120.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 4.0f; + m_fDamageAmount = 20.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_tmExpandBox = 0.1f; + // time when laser ray becomes visible + m_tmInvisibility = 0.025f; + m_pmtMove = PMT_FLYING; +}; + +void PlayerLaserWave(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // shock wave + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_LASERWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + } + } +}; + + + +/************************************************************ + * CATMAN PROJECTILE * + ************************************************************/ +void CatmanProjectile(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_CATMAN_FIRE); + SetModelMainTexture(TEXTURE_CATMAN_FIRE); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -15.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 5.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + + + +/************************************************************ + * HEADMAN PROJECTILE * + ************************************************************/ +void HeadmanFirecracker(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_SLIDING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_HEADMAN_FIRECRACKER); + SetModelMainTexture(TEXTURE_HEADMAN_FIRECRACKER); + GetModelObject()->StretchModel(FLOAT3D(0.75f, 0.75f, 0.75f)); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -25.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, FRnd()*20.0f-10.0f)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 4.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_SLIDING; +}; + +void HeadmanRocketman(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetComponents(this, *GetModelObject(), MODEL_HEADMAN_BLADE, TEXTURE_HEADMAN_BLADE, + TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddAttachmentToModel(this, *GetModelObject(), BLADE_ATTACHMENT_FLAME01, + MODEL_HEADMAN_BLADE_FLAME, TEXTURE_HEADMAN_BLADE_FLAME, 0, 0, 0); + AddAttachmentToModel(this, *GetModelObject(), BLADE_ATTACHMENT_FLAME02, + MODEL_HEADMAN_BLADE_FLAME, TEXTURE_HEADMAN_BLADE_FLAME, 0, 0, 0); + AddAttachmentToModel(this, *GetModelObject(), BLADE_ATTACHMENT_FLAME03, + MODEL_HEADMAN_BLADE_FLAME, TEXTURE_HEADMAN_BLADE_FLAME, 0, 0, 0); + GetModelObject()->StretchModel(FLOAT3D(0.5f, 0.5f, 0.5f)); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 5.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + +void HeadmanBomberman(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetModel(MODEL_HEADMAN_BOMB); + SetModelMainTexture(TEXTURE_HEADMAN_BOMB); + + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -m_fSpeed), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, FRnd()*360.0f-180.0f, FRnd()*360.0f-180.0f)); + m_fFlyTime = 2.5f; + m_fDamageAmount = 10.0f; + m_fRangeDamageAmount = 15.0f; + m_fDamageHotSpotRange = 1.0f; + m_fDamageFallOffRange = 6.0f; + m_fSoundRange = 25.0f; + m_bExplode = TRUE; + m_bLightSource = FALSE; + m_bCanHitHimself = TRUE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + SetHealth(5.0f); + m_pmtMove = PMT_FLYING; +}; + +void HeadmanBombermanExplosion(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_BOMB; + ese.vStretch = FLOAT3D(1.0f,1.0f,1.0f); + SpawnEffect(GetPlacement(), ese); + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // wall stain + ese.betType = BET_EXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + ese.betType = BET_GRENADE_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + } + } +}; + +void CyborgBombExplosion(void) +{ + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_BOMB; + ese.vStretch = FLOAT3D(1.0f,1.0f,1.0f); + SpawnEffect(GetPlacement(), ese); + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // wall stain + ese.betType = BET_EXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + ese.betType = BET_GRENADE_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + } + } +}; + +/************************************************************ + * BONEMAN PROJECTILE * + ************************************************************/ +void BonemanProjectile(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_BONEMAN_FIRE); + SetModelMainTexture(TEXTURE_BONEMAN_FIRE); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 10.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_SLIDING; +}; + + + +/************************************************************ + * WOMAN PROJECTILE * + ************************************************************/ +void WomanProjectile(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_WOMAN_FIRE); + SetModelMainTexture(TEXTURE_WOMAN_FIRE); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 8.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + + + +/************************************************************ + * DRAGONMAN PROJECTILE * + ************************************************************/ +void DragonmanProjectile(INDEX iType) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_ONBLOCK_SLIDE|EPF_PUSHABLE|EPF_MOVABLE); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_DRAGONMAN_FIRE); + if (iType==DRAGONMAN_STRONG) { + SetModelMainTexture(TEXTURE_DRAGONMAN_FIRE2); + } else { + SetModelMainTexture(TEXTURE_DRAGONMAN_FIRE1); + } + // start moving + if (iType==DRAGONMAN_STRONG) { + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -40.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + m_fDamageAmount = 14.0f; + } else { + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + m_fDamageAmount = 7.0f; + } + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + + + +/************************************************************ + * ELEMENTAL PROJECTILE * + ************************************************************/ +void ElementalRock(INDEX iSize, INDEX iType) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_ONBLOCK_SLIDE|EPF_PUSHABLE|EPF_MOVABLE); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + switch (iType) { + case ELEMENTAL_STONEMAN: + SetModel(MODEL_ELEM_STONE); + SetModelMainTexture(TEXTURE_ELEM_STONE); + break; + case ELEMENTAL_LAVAMAN: + SetModel(MODEL_ELEM_LAVA_STONE); + SetModelMainTexture(TEXTURE_ELEM_LAVA_STONE); + AddAttachmentToModel(this, *GetModelObject(), LAVASTONE_ATTACHMENT_FLARE, + MODEL_ELEM_LAVA_STONE_FLARE, TEXTURE_ELEM_LAVA_STONE_FLARE, 0, 0, 0); + break; + case ELEMENTAL_ICEMAN: + SetModel(MODEL_ELEM_ICE); + SetModelMainTexture(TEXTURE_ELEM_ICE); + //AddAttachmentToModel(this, *GetModelObject(), ICEPYRAMID_ATTACHMENT_FLARE, + // MODEL_ELEM_ICE_FLARE, TEXTURE_ELEM_ICE_FLARE, 0, 0, 0); + break; + } + if (iSize==ELEMENTAL_LARGE) { + GetModelObject()->StretchModel(FLOAT3D(2.25f, 2.25f, 2.25f)); + } else if (iSize==ELEMENTAL_BIG) { + GetModelObject()->StretchModel(FLOAT3D(0.75f, 0.75f, 0.75f)); + } else { + GetModelObject()->StretchModel(FLOAT3D(0.4f, 0.4f, 0.4f)); + } + ModelChangeNotify(); + // start moving + if (iSize==ELEMENTAL_LARGE) { + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -80.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + m_fDamageAmount = 20.0f; + SetHealth(40.0f); + } else if (iSize==ELEMENTAL_BIG) { + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -50.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + m_fDamageAmount = 12.5f; + SetHealth(20.0f); + } else { + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + m_fDamageAmount = 7.0f; + SetHealth(10.0f); + } + SetDesiredRotation(ANGLE3D(0, 0, FRnd()*1800.0f-900.0f)); + en_fCollisionSpeedLimit = 1000.0f; + en_fCollisionDamageFactor = 0.0f; + m_fFlyTime = 5.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_SLIDING; +}; + +void LavaManBomb(void) +{ + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + + SetModel(MODEL_ELEM_LAVA_BOMB); + SetModelMainTexture(TEXTURE_ELEM_LAVA_BOMB); + AddAttachmentToModel(this, *GetModelObject(), LAVABOMB_ATTACHMENT_FLARE, + MODEL_ELEM_LAVA_BOMB_FLARE, TEXTURE_ELEM_LAVA_BOMB_FLARE, 0, 0, 0); + + if (m_prtType == PRT_LAVAMAN_BIG_BOMB) + { + GetModelObject()->StretchModel(FLOAT3D(6.0f, 6.0f, 6.0f)); + m_fDamageAmount = 20.0f; + m_fRangeDamageAmount = 10.0f; + m_fDamageHotSpotRange = 7.5f; + m_fDamageFallOffRange = 15.0f; + SetHealth(30.0f); + } + else if (m_prtType == PRT_LAVAMAN_BOMB) + { + GetModelObject()->StretchModel(FLOAT3D(1.5f, 1.5f, 1.5f)); + m_fDamageAmount = 10.0f; + m_fRangeDamageAmount = 5.0f; + m_fDamageHotSpotRange = 5.0f; + m_fDamageFallOffRange = 10.0f; + SetHealth(10.0f); + } + ModelChangeNotify(); + + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -m_fSpeed), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, FRnd()*360.0f-180.0f, 0.0f)); + m_fFlyTime = 20.0f; + m_fSoundRange = 50.0f; + m_bExplode = TRUE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_pmtMove = PMT_FLYING; + m_fWaitAfterDeath = 4.0f; + + + if (m_prtType == PRT_LAVAMAN_BIG_BOMB) + { + // spawn particle debris + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 4.0f; + eSpawnSpray.fSizeMultiplier = 0.5f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); + } +} + +void LavamanBombExplosion(void) +{ + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) + { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) + { + // shock wave + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + } + } + + // shock wave + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(4,4,4); + SpawnEffect(GetPlacement(), ese); + + // spawn particle debris + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 4.0f; + eSpawnSpray.fSizeMultiplier = 0.5f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/32.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); + + // spawn smaller lava bombs + for( INDEX iDebris=0; iDebris<3+IRnd()%3; iDebris++) + { + FLOAT fHeading = (FRnd()-0.5f)*180.0f; + FLOAT fPitch = 10.0f+FRnd()*40.0f; + FLOAT fSpeed = 10.0+FRnd()*50.0f; + + // launch + CPlacement3D pl = GetPlacement(); + pl.pl_PositionVector(2) += 2.0f; + pl.pl_OrientationAngle = m_penLauncher->GetPlacement().pl_OrientationAngle; + pl.pl_OrientationAngle(1) += AngleDeg(fHeading); + pl.pl_OrientationAngle(2) = AngleDeg(fPitch); + + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_LAVAMAN_BOMB; + eLaunch.fSpeed = fSpeed; + penProjectile->Initialize(eLaunch); + + // spawn particle debris + CPlacement3D plSpray = pl; + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( penProjectile); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 1.0f; + eSpawnSpray.fSizeMultiplier = 0.5f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); + eSpawnSpray.penOwner = penProjectile; + penSpray->Initialize( eSpawnSpray); + } +}; + +void LavamanBombDebrisExplosion(void) +{ + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // spawn shock wave + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) + { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) + { + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + } + } + + // spawn explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(2,2,2); + SpawnEffect(GetPlacement(), ese); + + // spawn particle debris + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fSizeMultiplier = 4.0f; + eSpawnSpray.fDamagePower = 2.0f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/16.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); +} + +/************************************************************ + * HUANMAN PROJECTILE * + ************************************************************/ +void HuanmanProjectile(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetComponents(this, *GetModelObject(), MODEL_HUANMAN_FIRE, TEXTURE_HUANMAN_FIRE, + TEX_REFL_LIGHTMETAL01, TEX_SPEC_STRONG, 0); + AddAttachmentToModel(this, *GetModelObject(), PROJECTILE_ATTACHMENT_FLARE, + MODEL_HUANMAN_FLARE, TEXTURE_HUANMAN_FLARE, 0, 0, 0); + GetModelObject()->StretchModel(FLOAT3D(0.5f, 0.5f, 0.5f)); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 10.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + +/************************************************************ + * BEAST PROJECTILE * + ************************************************************/ +void BeastProjectile(void) { + // we need target for guied misile + if (IsDerivedFromClass(m_penLauncher, "Enemy Base")) { + m_penTarget = ((CEnemyBase *) &*m_penLauncher)->m_penEnemy; + } + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_FREE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + + SetModel(MODEL_BEAST_FIRE); + SetModelMainTexture(TEXTURE_BEAST_FIRE); + GetModelObject()->StretchModel(FLOAT3D(1.5f, 1.5f, 1.5f)); + + ModelChangeNotify(); + // play the flying sound + m_soEffect.Set3DParameters(20.0f, 2.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_BEAST_FLYING, SOF_3D|SOF_LOOP); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -60.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 10.0f; + m_fDamageAmount = 10.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_GUIDED; + m_aRotateSpeed = 175.0f; + SetHealth(10.0f); +}; + +void BeastBigProjectile(void) { + // we need target for guied misile + if (IsDerivedFromClass(m_penLauncher, "Enemy Base")) { + m_penTarget = ((CEnemyBase *) &*m_penLauncher)->m_penEnemy; + } + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_FREE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + + SetModel(MODEL_BEAST_FIRE); + SetModelMainTexture(TEXTURE_BEAST_BIG_FIRE); + GetModelObject()->StretchModel(FLOAT3D(1.5f, 1.5f, 1.5f)); + + ModelChangeNotify(); + // play the flying sound + m_soEffect.Set3DParameters(50.0f, 2.0f, 1.0f, 0.75f); + PlaySound(m_soEffect, SOUND_BEAST_FLYING, SOF_3D|SOF_LOOP); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -60.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 10.0f; + m_fDamageAmount = 20.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_GUIDED; + SetHealth(11.0f); + m_aRotateSpeed = 100.0f; +}; + +void BeastDebris(void) +{ + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + + SetModel(MODEL_BEAST_FIRE); + GetModelObject()->StretchModel(FLOAT3D(0.75f, 0.75f, 0.75f)); + SetModelMainTexture(TEXTURE_BEAST_FIRE); + GetModelObject()->StartAnim(1+(ULONG)FRnd()*5.0f); + + ModelChangeNotify(); + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -20.0f), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 10.0f; + m_fDamageAmount = 0.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; + SetHealth(1.0f); + m_aRotateSpeed = 100.0f; +}; + +void BeastBigDebris(void) +{ + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + + SetModel(MODEL_BEAST_FIRE); + SetModelMainTexture(TEXTURE_BEAST_BIG_FIRE); + GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)); + GetModelObject()->StartAnim(1+(ULONG)FRnd()*5.0f); + + ModelChangeNotify(); + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -20.0f), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 10.0f; + m_fDamageAmount = 0.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; + SetHealth(1.0f); + m_aRotateSpeed = 100.0f; +}; + +void BeastDebrisExplosion(void) +{ + // explosion + ESpawnEffect ese; + ese.colMuliplier = C_GREEN|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(0.75,0.75,0.75); + SpawnEffect(GetPlacement(), ese); + + // spawn particles + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 2.0f; + eSpawnSpray.fSizeMultiplier = 0.75f; + eSpawnSpray.sptType = SPT_BEAST_PROJECTILE_SPRAY; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/64.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); +} + +void BeastBigDebrisExplosion(void) +{ + // explosion + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(1,1,1); + SpawnEffect(GetPlacement(), ese); + + // spawn particles + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 2.0f; + eSpawnSpray.fSizeMultiplier = 1.0f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/64.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); +} + +void BeastProjectileExplosion(void) +{ + // explosion + ESpawnEffect ese; + ese.colMuliplier = C_GREEN|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(1.25,1.25,1.25); + SpawnEffect(GetPlacement(), ese); + + // particles + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 2.0f; + eSpawnSpray.fSizeMultiplier = 1.0f; + eSpawnSpray.sptType = SPT_BEAST_PROJECTILE_SPRAY; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/64.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); + + FLOAT fHeading = 20.0f+(FRnd()-0.5f)*60.0f; + // debris + for( INDEX iDebris=0; iDebris<2; iDebris++) + { + FLOAT fPitch = 10.0f+FRnd()*10.0f; + FLOAT fSpeed = 5.0+FRnd()*20.0f; + + // launch + CPlacement3D pl = GetPlacement(); + pl.pl_OrientationAngle(1) += AngleDeg(fHeading); + // turn to other way + fHeading = -fHeading; + pl.pl_OrientationAngle(2) = AngleDeg(fPitch); + + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_BEAST_DEBRIS; + eLaunch.fSpeed = fSpeed; + penProjectile->Initialize(eLaunch); + + // spawn particle debris + CPlacement3D plSpray = pl; + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( penProjectile); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 0.5f; + eSpawnSpray.fSizeMultiplier = 0.25f; + eSpawnSpray.sptType = SPT_BEAST_PROJECTILE_SPRAY; + eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); + eSpawnSpray.penOwner = penProjectile; + penSpray->Initialize( eSpawnSpray); + } +} + +void BeastBigProjectileExplosion(void) +{ + // explosion + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(2,2,2); + SpawnEffect(GetPlacement(), ese); + + // particles + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 4.0f; + eSpawnSpray.fSizeMultiplier = 0.5f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/32.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); + + // debris + for( INDEX iDebris=0; iDebris<3+IRnd()%2; iDebris++) + { + FLOAT fHeading = (FRnd()-0.5f)*180.0f; + FLOAT fPitch = 10.0f+FRnd()*40.0f; + FLOAT fSpeed = 10.0+FRnd()*50.0f; + + // launch + CPlacement3D pl = GetPlacement(); + pl.pl_OrientationAngle(1) += AngleDeg(fHeading); + pl.pl_OrientationAngle(2) += AngleDeg(fPitch); + + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_BEAST_BIG_DEBRIS; + eLaunch.fSpeed = fSpeed; + penProjectile->Initialize(eLaunch); + + // spawn particle debris + CPlacement3D plSpray = pl; + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( penProjectile); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 1.0f; + eSpawnSpray.fSizeMultiplier = 0.5f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); + eSpawnSpray.penOwner = penProjectile; + penSpray->Initialize( eSpawnSpray); + } +} + +/************************************************************ + * FISHMAN PROJECTILE * + ************************************************************/ +void FishmanProjectile(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetComponents(this, *GetModelObject(), MODEL_FISHMAN_FIRE, TEXTURE_FISHMAN_FIRE, 0, 0, 0); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 5.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + + + +/************************************************************ + * MANTAMAN PROJECTILE * + ************************************************************/ +void MantamanProjectile(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetComponents(this, *GetModelObject(), MODEL_MANTAMAN_FIRE, TEXTURE_MANTAMAN_FIRE, 0, 0, 0); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -35.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 7.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + + +/************************************************************ + * DEVIL PROJECTILES * + ************************************************************/ +void DevilLaser(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetComponents(this, *GetModelObject(), MODEL_CYBORG_LASER, TEXTURE_CYBORG_LASER, 0, 0, 0); + GetModelObject()->StretchModel(FLOAT3D(4.0f, 4.0f, 2.0f)); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -DEVIL_LASER_SPEED), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 10.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + +void DevilRocket(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetModel(MODEL_ROCKET); + SetModelMainTexture(TEXTURE_ROCKET); + GetModelObject()->StretchModel(FLOAT3D(12.0f, 12.0f, 8.0f)); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -DEVIL_ROCKET_SPEED), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + // play the flying sound + m_soEffect.Set3DParameters(100.0f, 2.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_FLYING, SOF_3D|SOF_LOOP); + m_fFlyTime = 50.0f; + m_fDamageAmount = 50.0f; + m_fRangeDamageAmount = 50.0f; + m_fDamageHotSpotRange = 2.0f; + m_fDamageFallOffRange = 10.0f; + m_fSoundRange = 100.0f; + m_bExplode = TRUE; + m_bLightSource = TRUE; + m_bCanHitHimself = TRUE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 1.125f; + m_tmExpandBox = 10000.0f; + m_tmInvisibility = 0.05f; + SetHealth(25.0f); + m_pmtMove = PMT_FLYING; +}; + +void DevilRocketExplosion(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + + // explosion + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_GRENADE; + ese.vStretch = FLOAT3D(2,2,2); + SpawnEffect(GetPlacement(), ese); + // spawn sound event in range + if( IsDerivedFromClass( m_penLauncher, "Player")) { + SpawnRangeSound( m_penLauncher, this, SNDT_PLAYER, m_fSoundRange); + } + + // on plane + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // stain + ese.betType = BET_EXPLOSIONSTAIN; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = FLOAT3D(2,2,2); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // shock wave + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = FLOAT3D(2,2,2); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + // second explosion on plane + ese.betType = BET_GRENADE_PLANE; + ese.vNormal = FLOAT3D(vPlaneNormal); + ese.vStretch = FLOAT3D(2,2,2); + SpawnEffect(CPlacement3D(vPoint+ese.vNormal/50.0f, ANGLE3D(0, 0, 0)), ese); + } + } +}; + +void DevilGuidedProjectile(void) { + // we need target for guied misile + if (IsDerivedFromClass(m_penLauncher, "Enemy Base")) { + m_penTarget = ((CEnemyBase *) &*m_penLauncher)->m_penEnemy; + } + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_FREE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + + SetModel(MODEL_BEAST_FIRE); + SetModelMainTexture(TEXTURE_BEAST_BIG_FIRE); + GetModelObject()->StretchModel(FLOAT3D(2.5f, 2.5f, 2.5f)); + ModelChangeNotify(); + // play the flying sound + m_soEffect.Set3DParameters(250.0f, 2.0f, 1.0f, 0.75f); + PlaySound(m_soEffect, SOUND_FLYING, SOF_3D|SOF_LOOP); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -80.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 20.0f; + m_fDamageAmount = 20.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_GUIDED; + SetHealth(30.0f); + m_aRotateSpeed = 100.0f; +}; + +void DevilGuidedProjectileExplosion(void) +{ + // explosion + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_LIGHT_CANNON; + ese.vStretch = FLOAT3D(4,4,4); + SpawnEffect(GetPlacement(), ese); + + // particles + CPlacement3D plSpray = GetPlacement(); + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( this); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 8.0f; + eSpawnSpray.fSizeMultiplier = 1.0f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = en_vCurrentTranslationAbsolute/32.0f; + eSpawnSpray.penOwner = this; + penSpray->Initialize( eSpawnSpray); + + // debris + for( INDEX iDebris=0; iDebris<3+IRnd()%2; iDebris++) + { + FLOAT fHeading = (FRnd()-0.5f)*180.0f; + FLOAT fPitch = 10.0f+FRnd()*40.0f; + FLOAT fSpeed = 10.0+FRnd()*50.0f; + + // launch + CPlacement3D pl = GetPlacement(); + pl.pl_OrientationAngle(1) += AngleDeg(fHeading); + pl.pl_OrientationAngle(2) += AngleDeg(fPitch); + + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_BEAST_BIG_DEBRIS; + eLaunch.fSpeed = fSpeed; + penProjectile->Initialize(eLaunch); + + // spawn particle debris + CPlacement3D plSpray = pl; + CEntityPointer penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY); + penSpray->SetParent( penProjectile); + ESpawnSpray eSpawnSpray; + eSpawnSpray.fDamagePower = 2.0f; + eSpawnSpray.fSizeMultiplier = 1.0f; + eSpawnSpray.sptType = SPT_LAVA_STONES; + eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); + eSpawnSpray.penOwner = penProjectile; + penSpray->Initialize( eSpawnSpray); + } +} + +/************************************************************ + * CYBORG LASER / PROJECTILE * + ************************************************************/ +void CyborgLaser(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_PROJECTILE_FLYING); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetComponents(this, *GetModelObject(), MODEL_CYBORG_LASER, TEXTURE_CYBORG_LASER, 0, 0, 0); + ModelChangeNotify(); + // start moving + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -60.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 5.0f; + m_fSoundRange = 0.0f; + m_bExplode = FALSE; + m_bLightSource = TRUE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + +void CyborgBomb(void) +{ + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_BOUNCING); + SetCollisionFlags(ECF_PROJECTILE_SOLID); + SetModel(MODEL_CYBORG_BOMB); + SetModelMainTexture(TEXTURE_CYBORG_BOMB); + ModelChangeNotify(); + // just freefall + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -m_fSpeed), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, 0, 0)); + m_fFlyTime = 2.5f; + m_fDamageAmount = 10.0f; + m_fRangeDamageAmount = 15.0f; + m_fDamageHotSpotRange = 1.0f; + m_fDamageFallOffRange = 6.0f; + m_fSoundRange = 25.0f; + m_bExplode = TRUE; + m_bLightSource = FALSE; + m_bCanHitHimself = TRUE; + m_bCanBeDestroyed = TRUE; + m_fWaitAfterDeath = 0.0f; + SetHealth(5.0f); + m_pmtMove = PMT_FLYING; +}; + + + +/************************************************************ + * LAVA BALL * + ************************************************************/ +void LavaBall(void) { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_FALL); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetModel(MODEL_LAVA); + SetModelMainTexture(TEXTURE_LAVA); + AddAttachment(0, MODEL_LAVA_FLARE, TEXTURE_LAVA_FLARE); + + // start moving + LaunchAsFreeProjectile(FLOAT3D(0.0f, 0.0f, -m_fSpeed), (CMovableEntity*)&*m_penLauncher); + SetDesiredRotation(ANGLE3D(0, FRnd()*360.0f-180.0f, FRnd()*360.0f-180.0f)); + m_fFlyTime = 5.0f; + m_fDamageAmount = 5.0f; + m_fRangeDamageAmount = 5.0f; + m_fDamageHotSpotRange = 1.0f; + m_fDamageFallOffRange = 4.0f; + m_fSoundRange = 0.0f; + m_bExplode = TRUE; + m_bLightSource = FALSE; + m_bCanHitHimself = FALSE; + m_bCanBeDestroyed = FALSE; + m_fWaitAfterDeath = 0.0f; + m_pmtMove = PMT_FLYING; +}; + +void LavaBallExplosion(void) { + ESpawnEffect ese; + FLOAT3D vPoint; + FLOATplane3D vPlaneNormal; + FLOAT fDistanceToEdge; + if (GetNearestPolygon(vPoint, vPlaneNormal, fDistanceToEdge)) { + if ((vPoint-GetPlacement().pl_PositionVector).Length() < 3.5f) { + // shock wave + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_SHOCKWAVE; + ese.vNormal = FLOAT3D(vPlaneNormal); + SpawnEffect(CPlacement3D(vPoint, ANGLE3D(0, 0, 0)), ese); + } + } +}; + +/************************************************************ + * C O M M O N F U N C T I O N S * + ************************************************************/ +// projectile touch his valid target +void ProjectileTouch(CEntityPointer penHit) { + // explode ... + ProjectileHitted(); + // direct damage + FLOAT3D vDirection; + FLOAT fTransLen = en_vIntendedTranslation.Length(); + if( fTransLen>0.5f) + { + vDirection = en_vIntendedTranslation/fTransLen; + } + else + { + vDirection = -en_vGravityDir; + } + + // spawn flame +/* if (m_prtType==PRT_FLAME && m_fWaitAfterDeath>0.0f) { + SpawnFlame(m_penLauncher, penHit, GetPlacement().pl_PositionVector); + InflictDirectDamage(penHit, m_penLauncher, DMT_BURNING, m_fDamageAmount, + GetPlacement().pl_PositionVector, vDirection); + // projectile + } else */{ + InflictDirectDamage(penHit, m_penLauncher, DMT_PROJECTILE, m_fDamageAmount, + GetPlacement().pl_PositionVector, vDirection); + } +}; + +// projectile hitted (or time expired or can't move any more) +void ProjectileHitted(void) { + // explode ... + if (m_bExplode) { + InflictRangeDamage(m_penLauncher, DMT_EXPLOSION, m_fRangeDamageAmount, + GetPlacement().pl_PositionVector, m_fDamageHotSpotRange, m_fDamageFallOffRange); + } + // sound event + if (m_fSoundRange > 0.0f) { + ESound eSound; + eSound.EsndtSound = SNDT_EXPLOSION; + eSound.penTarget = m_penLauncher; + SendEventInRange(eSound, FLOATaabbox3D(GetPlacement().pl_PositionVector, m_fSoundRange)); + } +}; + + +// spawn effect +void SpawnEffect(const CPlacement3D &plEffect, const ESpawnEffect &eSpawnEffect) { + CEntityPointer penEffect = CreateEntity(plEffect, CLASS_BASIC_EFFECT); + penEffect->Initialize(eSpawnEffect); +}; + + + +/************************************************************ + * S O U N D S * + ************************************************************/ +void BounceSound(void) { + switch (m_prtType) { + case PRT_GRENADE: + if (en_vCurrentTranslationAbsolute.Length() > 3.0f) { + m_soEffect.Set3DParameters(20.0f, 2.0f, 1.0f, 1.0f); + PlaySound(m_soEffect, SOUND_GRENADE_BOUNCE, SOF_3D); + } + break; + } +}; + + + +// Calculate current rotation speed to rich given orientation in future +ANGLE GetRotationSpeed(ANGLE aWantedAngle, ANGLE aRotateSpeed, FLOAT fWaitFrequency) +{ + ANGLE aResult; + // if desired position is smaller + if ( aWantedAngle<-aRotateSpeed*fWaitFrequency) + { + // start decreasing + aResult = -aRotateSpeed; + } + // if desired position is bigger + else if (aWantedAngle>aRotateSpeed*fWaitFrequency) + { + // start increasing + aResult = +aRotateSpeed; + } + // if desired position is more-less ahead + else + { + aResult = aWantedAngle/fWaitFrequency; + } + return aResult; +} + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> PROJECTILE FLY IN SPACE + ProjectileFly(EVoid) { + // if already inside some entity + CEntity *penObstacle; + if (CheckForCollisionNow(0, &penObstacle)) { + // explode now + ProjectileTouch(penObstacle); + return EEnd(); + } + // fly loop + wait(m_fFlyTime) { + on (EBegin) : { resume; } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // ignore another projectile of same type + bHit &= !((!m_bCanHitHimself && IsOfClass(epass.penOther, "Projectile") && + ((CProjectile*)&*epass.penOther)->m_prtType==m_prtType)); + // ignore twister + bHit &= !IsOfClass(epass.penOther, "Twister"); + if (bHit) { + ProjectileTouch(epass.penOther); + stop; + } + resume; + } + on (ETouch etouch) : { + // clear time limit for launcher + m_fIgnoreTime = 0.0f; + // ignore another projectile of same type + BOOL bHit; + bHit = !((!m_bCanHitHimself && IsOfClass(etouch.penOther, "Projectile") && + ((CProjectile*)&*etouch.penOther)->m_prtType==m_prtType)); + if (bHit) { + ProjectileTouch(etouch.penOther); + stop; + } + resume; + } + on (EDeath) : { + if (m_bCanBeDestroyed) { + ProjectileHitted(); + stop; + } + resume; + } + on (ETimer) : { + ProjectileHitted(); + stop; + } + } + return EEnd(); + }; + + // --->>> GUIDED PROJECTILE FLY IN SPACE + ProjectileGuidedFly(EVoid) { + // if already inside some entity + CEntity *penObstacle; + if (CheckForCollisionNow(0, &penObstacle)) { + // explode now + ProjectileTouch(penObstacle); + return EEnd(); + } + // fly loop + while( _pTimer->CurrentTick()<(m_fStartTime+m_fFlyTime)) + { + FLOAT fWaitFrequency = 0.1f; + if (m_penTarget!=NULL) { + // calculate desired position and angle + EntityInfo *pei= (EntityInfo*) (m_penTarget->GetEntityInfo()); + FLOAT3D vDesiredPosition; + GetEntityInfoPosition( m_penTarget, pei->vSourceCenter, vDesiredPosition); + FLOAT3D vDesiredDirection = (vDesiredPosition-GetPlacement().pl_PositionVector).Normalize(); + // for heading + ANGLE aWantedHeading = GetRelativeHeading( vDesiredDirection); + ANGLE aHeading = GetRotationSpeed( aWantedHeading, m_aRotateSpeed, fWaitFrequency); + + // factor used to decrease speed of projectiles oriented opposite of its target + FLOAT fSpeedDecreasingFactor = ((180-abs(aWantedHeading))/180.0f); + // factor used to increase speed when far away from target + FLOAT fSpeedIncreasingFactor = (vDesiredPosition-GetPlacement().pl_PositionVector).Length()/100; + fSpeedIncreasingFactor = ClampDn(fSpeedIncreasingFactor, 1.0f); + // decrease speed acodring to target's direction + FLOAT fMaxSpeed = 30.0f*fSpeedIncreasingFactor; + FLOAT fMinSpeedRatio = 0.5f; + FLOAT fWantedSpeed = fMaxSpeed*( fMinSpeedRatio+(1-fMinSpeedRatio)*fSpeedDecreasingFactor); + // adjust translation velocity + SetDesiredTranslation( FLOAT3D(0, 0, -fWantedSpeed)); + + // adjust rotation speed + m_aRotateSpeed = 75.0f*(1+0.5f*fSpeedDecreasingFactor); + + // calculate distance factor + FLOAT fDistanceFactor = (vDesiredPosition-GetPlacement().pl_PositionVector).Length()/50.0; + fDistanceFactor = ClampUp(fDistanceFactor, 4.0f); + FLOAT fRNDHeading = (FRnd()-0.5f)*180*fDistanceFactor; + FLOAT fRNDPitch = (FRnd()-0.5f)*90*fDistanceFactor; + + // if we are looking near direction of target + if( abs( aWantedHeading) < 30.0f) + { + // calculate pitch speed + ANGLE aWantedPitch = GetRelativePitch( vDesiredDirection); + ANGLE aPitch = GetRotationSpeed( aWantedPitch, m_aRotateSpeed*1.5f, fWaitFrequency); + // adjust heading and pich + SetDesiredRotation(ANGLE3D(aHeading+fRNDHeading,aPitch+fRNDPitch,0)); + } + // just adjust heading + else + { + SetDesiredRotation(ANGLE3D(aHeading,fDistanceFactor*40,0)); + } + } + + wait( fWaitFrequency) + { + on (EBegin) : { resume; } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // ignore another projectile of same type + bHit &= !((!m_bCanHitHimself && IsOfClass(epass.penOther, "Projectile") && + ((CProjectile*)&*epass.penOther)->m_prtType==m_prtType)); + // ignore twister + bHit &= !IsOfClass(epass.penOther, "Twister"); + if (bHit) { + ProjectileTouch(epass.penOther); + return EEnd(); + } + resume; + } + on (EDeath) : + { + if (m_bCanBeDestroyed) + { + ProjectileHitted(); + return EEnd(); + } + resume; + } + on (ETimer) : + { + stop; + } + } + } + return EEnd(); + }; + + // --->>> PROJECTILE SLIDE ON BRUSH + ProjectileSlide(EVoid) { + // if already inside some entity + CEntity *penObstacle; + if (CheckForCollisionNow(0, &penObstacle)) { + // explode now + ProjectileTouch(penObstacle); + return EEnd(); + } + // fly loop + wait(m_fFlyTime) { + on (EBegin) : { resume; } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // ignore another projectile of same type + bHit &= !((!m_bCanHitHimself && IsOfClass(epass.penOther, "Projectile") && + ((CProjectile*)&*epass.penOther)->m_prtType==m_prtType)); + // ignore twister + bHit &= !IsOfClass(epass.penOther, "Twister"); + if (bHit) { + ProjectileTouch(epass.penOther); + stop; + } + resume; + } + on (ETouch etouch) : { + // clear time limit for launcher + m_fIgnoreTime = 0.0f; + // ignore brushes + BOOL bHit; + bHit = !(etouch.penOther->GetRenderType() & RT_BRUSH); + if (!bHit) { BounceSound(); } + // ignore another projectile of same type + bHit &= !((!m_bCanHitHimself && IsOfClass(etouch.penOther, "Projectile") && + ((CProjectile*)&*etouch.penOther)->m_prtType==m_prtType)); + if (bHit) { + ProjectileTouch(etouch.penOther); + stop; + } + // projectile is moving to slow (stuck somewhere) -> kill it + if (en_vCurrentTranslationAbsolute.Length() < 0.25f*en_vDesiredTranslationRelative.Length()) { + ProjectileHitted(); + stop; + } + resume; + } + on (EDeath) : { + if (m_bCanBeDestroyed) { + ProjectileHitted(); + stop; + } + resume; + } + on (ETimer) : { + ProjectileHitted(); + stop; + } + } + return EEnd(); + }; + + // --->>> MAIN + Main(ELaunchProjectile eLaunch) { + // remember the initial parameters + ASSERT(eLaunch.penLauncher!=NULL); + m_penLauncher = eLaunch.penLauncher; + m_prtType = eLaunch.prtType; + m_fSpeed = eLaunch.fSpeed; + SetPredictable(TRUE); + // remember lauching time + m_fIgnoreTime = _pTimer->CurrentTick() + 1.0f; + + switch (m_prtType) { + case PRT_DEVIL_ROCKET: + case PRT_WALKER_ROCKET: + case PRT_ROCKET: + { + Particles_RocketTrail_Prepare(this); + break; + } + case PRT_GRENADE: Particles_GrenadeTrail_Prepare(this); break; + case PRT_CATMAN_FIRE: Particles_RocketTrail_Prepare(this); break; + case PRT_HEADMAN_FIRECRACKER: Particles_FirecrackerTrail_Prepare(this); break; + case PRT_HEADMAN_ROCKETMAN: Particles_Fireball01Trail_Prepare(this); break; + case PRT_HEADMAN_BOMBERMAN: Particles_BombTrail_Prepare(this); break; + case PRT_LAVA_COMET: Particles_LavaTrail_Prepare(this); break; + case PRT_LAVAMAN_BIG_BOMB: Particles_LavaBombTrail_Prepare(this); break; + case PRT_LAVAMAN_BOMB: Particles_LavaBombTrail_Prepare(this); break; + case PRT_BEAST_PROJECTILE: Particles_Fireball01Trail_Prepare(this); break; + case PRT_BEAST_BIG_PROJECTILE: + case PRT_DEVIL_GUIDED_PROJECTILE: + Particles_FirecrackerTrail_Prepare(this); + break; + } + // projectile initialization + switch (m_prtType) + { + case PRT_WALKER_ROCKET: WalkerRocket(); break; + case PRT_ROCKET: PlayerRocket(); break; + case PRT_GRENADE: PlayerGrenade(); break; + case PRT_FLAME: PlayerFlame(); break; + case PRT_LASER_RAY: PlayerLaserRay(); break; + case PRT_CATMAN_FIRE: CatmanProjectile(); break; + case PRT_HEADMAN_FIRECRACKER: HeadmanFirecracker(); break; + case PRT_HEADMAN_ROCKETMAN: HeadmanRocketman(); break; + case PRT_HEADMAN_BOMBERMAN: HeadmanBomberman(); break; + case PRT_BONEMAN_FIRE: BonemanProjectile(); break; + case PRT_WOMAN_FIRE: WomanProjectile(); break; + case PRT_DRAGONMAN_FIRE: DragonmanProjectile(DRAGONMAN_NORMAL); break; + case PRT_DRAGONMAN_STRONG_FIRE: DragonmanProjectile(DRAGONMAN_STRONG); break; + case PRT_STONEMAN_FIRE: ElementalRock(ELEMENTAL_NORMAL, ELEMENTAL_STONEMAN); break; + case PRT_STONEMAN_BIG_FIRE: ElementalRock(ELEMENTAL_BIG, ELEMENTAL_STONEMAN); break; + case PRT_STONEMAN_LARGE_FIRE: ElementalRock(ELEMENTAL_LARGE, ELEMENTAL_STONEMAN); break; + case PRT_LAVAMAN_BIG_BOMB: LavaManBomb(); break; + case PRT_LAVAMAN_BOMB: LavaManBomb(); break; + case PRT_LAVAMAN_STONE: ElementalRock(ELEMENTAL_NORMAL, ELEMENTAL_LAVAMAN); break; + case PRT_ICEMAN_FIRE: ElementalRock(ELEMENTAL_NORMAL, ELEMENTAL_ICEMAN); break; + case PRT_ICEMAN_BIG_FIRE: ElementalRock(ELEMENTAL_BIG, ELEMENTAL_ICEMAN); break; + case PRT_ICEMAN_LARGE_FIRE: ElementalRock(ELEMENTAL_LARGE, ELEMENTAL_ICEMAN); break; + case PRT_HUANMAN_FIRE: HuanmanProjectile(); break; + case PRT_FISHMAN_FIRE: FishmanProjectile(); break; + case PRT_MANTAMAN_FIRE: MantamanProjectile(); break; + case PRT_CYBORG_LASER: CyborgLaser(); break; + case PRT_CYBORG_BOMB: CyborgBomb(); break; + case PRT_LAVA_COMET: LavaBall(); break; + case PRT_BEAST_PROJECTILE: BeastProjectile(); break; + case PRT_BEAST_BIG_PROJECTILE: BeastBigProjectile(); break; + case PRT_BEAST_DEBRIS: BeastDebris(); break; + case PRT_BEAST_BIG_DEBRIS: BeastBigDebris(); break; + case PRT_DEVIL_LASER: DevilLaser(); break; + case PRT_DEVIL_ROCKET: DevilRocket(); break; + case PRT_DEVIL_GUIDED_PROJECTILE: DevilGuidedProjectile(); break; + default: ASSERTALWAYS("Unknown projectile type"); + } + + // setup light source + if (m_bLightSource) { SetupLightSource(TRUE); } + + // fly + m_fStartTime = _pTimer->CurrentTick(); + // if guided projectile + if( m_pmtMove == PMT_GUIDED) + { + autocall ProjectileGuidedFly() EEnd; + } + else if (m_pmtMove==PMT_FLYING) { + autocall ProjectileFly() EEnd; + // slide + } else if (m_pmtMove==PMT_SLIDING) { + autocall ProjectileSlide() EEnd; + } + + // projectile explosion + switch (m_prtType) { + case PRT_WALKER_ROCKET: WalkerRocketExplosion(); break; + case PRT_ROCKET: PlayerRocketExplosion(); break; + case PRT_GRENADE: PlayerGrenadeExplosion(); break; + case PRT_LASER_RAY: PlayerLaserWave(); break; + case PRT_HEADMAN_BOMBERMAN: HeadmanBombermanExplosion(); break; + case PRT_CYBORG_BOMB: CyborgBombExplosion(); break; + case PRT_LAVA_COMET: LavaBallExplosion(); break; + case PRT_LAVAMAN_BIG_BOMB: LavamanBombExplosion(); break; + case PRT_LAVAMAN_BOMB: LavamanBombDebrisExplosion(); break; + case PRT_BEAST_BIG_PROJECTILE: BeastBigProjectileExplosion(); break; + case PRT_BEAST_PROJECTILE: BeastProjectileExplosion(); break; + case PRT_BEAST_DEBRIS: BeastDebrisExplosion(); break; + case PRT_BEAST_BIG_DEBRIS: BeastBigDebrisExplosion(); break; + case PRT_DEVIL_ROCKET: DevilRocketExplosion(); break; + case PRT_DEVIL_GUIDED_PROJECTILE: DevilGuidedProjectileExplosion(); break; + } + + // wait after death + if (m_fWaitAfterDeath>0.0f) { + SwitchToEditorModel(); + ForceFullStop(); + SetCollisionFlags(ECF_IMMATERIAL); + // kill light source + if (m_bLightSource) { SetupLightSource(FALSE); } + autowait(m_fWaitAfterDeath); + } + + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/PyramidSpaceShip.es b/Sources/Entities/PyramidSpaceShip.es new file mode 100644 index 0000000..2573221 --- /dev/null +++ b/Sources/Entities/PyramidSpaceShip.es @@ -0,0 +1,921 @@ +609 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/CutSequences/SpaceShip/SpaceShip.h" +#include "Models/CutSequences/SpaceShip/Door.h" +#include "Models/CutSequences/SpaceShip/LightBeam.h" +#include "Entities/Effector.h" +#include "Entities/Light.h" +%} + +uses "Entities/PyramidSpaceShipMarker"; + +enum PSSState { + 0 PSSS_IDLE "Idle", // idle + 1 PSSS_MOVING "Moving", // process of moving trough markers + 2 PSSS_REACHED_DESTINATION "Reached destination", // process of turning on + 3 PSSS_KILLING_BEAM_FIREING "Killing beam fireing", // killing beam fireing + 4 PSSS_BEAM_DEACTIVATED "Killing beam deactivated", // killing beam gas been deactivated, wait to pick up Sam + 5 PSSS_DOORS_CLOSED "Doors closed", // doors closed +}; + +event EForcePathMarker { + CEntityPointer penForcedPathMarker, +}; + +%{ +#define STRETCH_X (200.0f*m_fStretch) +#define STRETCH_Y (100.0f*m_fStretch) +#define STRETCH_Z (200.0f*m_fStretch) +#define PSS_STRETCH (FLOAT3D(STRETCH_X, STRETCH_Y, STRETCH_Z)*m_fStretch) +#define SND_FALLOFF 1000.0f +#define SND_HOTSPOT 250.0f +#define SND_VOLUME 2.0f + +#define BIG_LIGHT_BEAM_LIFE_TIME (8.0f) +#define SMALL_FLARE_WAIT 2.0f +#define SMALL_FLARES_LIFE_TIME (BIG_LIGHT_BEAM_LIFE_TIME+SMALL_FLARE_WAIT) +#define SMALL_LIGHTNING_WAIT 1.5f +#define SMALL_LIGHTININGS_LIFE_TIME (SMALL_FLARES_LIFE_TIME+SMALL_LIGHTNING_WAIT) +#define BIG_FLARE_WAIT 1.0f +#define BIG_FLARE_LIFE_TIME (SMALL_LIGHTININGS_LIFE_TIME+BIG_FLARE_WAIT) + +#define BM_DX (0.414657f*STRETCH_X) +#define BM_DY (-1.72731f*STRETCH_Y) +#define BM_DZ (0.414657f*STRETCH_Z) +#define BM_FLARE_DY (-0.25f*STRETCH_Y) + +#define BM_MASTER_Y (-1.76648f*STRETCH_Y) +%} + +class CPyramidSpaceShip: CMovableModelEntity { +name "PyramidSpaceShip"; +thumbnail "Thumbnails\\PyramidSpaceShip.tbn"; +features "HasName", "IsTargetable", "IsImportant"; +properties: + 1 CTString m_strName "Name" 'N' = "Pyramid Space Ship", // name + 3 FLOAT m_fMovingSpeed = 0.0f, // current speed + 5 CEntityPointer m_penBeamHit "Beam hit target marker" 'T', // target point for light beam + 6 CEntityPointer m_penLightBeam "Beam model holder" 'B', // light beam model holder + 7 FLOAT m_tmBeamTime =-1.0f, // light beam time var + 8 CEntityPointer m_penHitPlaceFlare "Hit place flare" 'H', // hit place model holder + 9 FLOAT m_tmHitFlareTime =-1.0f, // light beam hit flare time var + 10 FLOAT m_iRingCounter = 0, // ring counter + 11 FLOAT m_fRatio =0.0f, // misc ratio + 12 CTString m_strDescription = "", // description + 13 enum PSSState m_epssState = PSSS_IDLE, // current state + 14 FLOAT m_fStretch "Stretch" 'S' = 1.0f, // stretch factor + // path properties + 20 BOOL m_bStopMoving = FALSE, // stop moving on next marker + 21 CEntityPointer m_penTarget "Target" 'T' COLOR(C_lBLUE|0xFF), // next path target + 29 CEntityPointer m_penFlyAwayTarget "Fly away path marker" COLOR(C_lBLUE|0xFF), // fly away path marker + 22 CEntityPointer m_penLast, // previous marker + 23 BOOL m_bMoving = FALSE, // set while moving + 24 FLOAT m_fRot = 0.0f, // current rotation + 25 FLOAT m_fLastRotSpeed = 0.0f, // last speed rotation + 26 FLOAT m_fRotSpeed = 0.0f, // current speed rotation + 27 BOOL m_bApplyDamageToHitted = TRUE, // if damage should be applied + 28 FLOAT m_tmTemp = 0.0f, // temporary time var + + 30 FLOAT m_tmAtMarker = 0.0f, // time when current marker was reached + 31 FLOAT m_tmDelta = 0.0f, // time to reach next marker + 32 FLOAT3D m_vPNp0 = FLOAT3D(0,0,0), + 33 FLOAT3D m_vPNp1 = FLOAT3D(0,0,0), + 34 FLOAT3D m_vTNp0 = FLOAT3D(0,0,0), + 35 FLOAT3D m_vTNp1 = FLOAT3D(0,0,0), + 36 FLOATquat3D m_qPNp0 = FLOATquat3D(0,0,0,0), + 37 FLOATquat3D m_qPNp1 = FLOATquat3D(0,0,0,0), + 38 FLOATquat3D m_qANp0 = FLOATquat3D(0,0,0,0), + 39 FLOATquat3D m_qANp1 = FLOATquat3D(0,0,0,0), + 40 FLOAT m_fRotSpeedp0 = 0.0f, + 41 FLOAT m_fRotSpeedp1 = 0.0f, + 42 FLOAT m_fTRotSpeedp0 = 0.0f, + 43 FLOAT m_fTRotSpeedp1 = 0.0f, + + 50 CSoundObject m_soPlates, + 51 CSoundObject m_soBeamMachine, + 52 CSoundObject m_soBeam, + 53 CSoundObject m_soFlaresFX, + 54 BOOL m_bFireingDeactivatedBeam=FALSE, + +components: + 1 model MODEL_SPACESHIP "Models\\CutSequences\\SpaceShip\\SpaceShip.mdl", + 2 model MODEL_BODY "Models\\CutSequences\\SpaceShip\\Body.mdl", + 3 texture TEXTURE_BODY "Models\\CutSequences\\SpaceShip\\Body.tex", + 4 model MODEL_DOOR "Models\\CutSequences\\SpaceShip\\Door.mdl", + 5 texture TEXTURE_DOOR "Models\\CutSequences\\SpaceShip\\Door.tex", + 6 model MODEL_BEAMMACHINE "Models\\CutSequences\\SpaceShip\\BeamMachine.mdl", + 7 texture TEXTURE_BEAMMACHINE "Models\\CutSequences\\SpaceShip\\BeamMachine.tex", + 8 model MODEL_BEAMRIM "Models\\CutSequences\\SpaceShip\\BeamMachineRim.mdl", + 9 texture TEXTURE_BEAMRIM "Models\\CutSequences\\SpaceShip\\BeamMachineRim.tex", + 10 class CLASS_EFFECTOR "Classes\\Effector.ecl", + 11 model MODEL_SHIP_INSIDE "Models\\CutSequences\\SpaceShip\\Fillin.mdl", + 20 sound SOUND_PLATES "Sounds\\CutSequences\\SpaceShip\\SSPlates.wav", + 21 sound SOUND_BEAMMACHINE "Sounds\\CutSequences\\SpaceShip\\SSProbe.wav", + 22 sound SOUND_BEAM "Sounds\\CutSequences\\SpaceShip\\LaserBeam.wav", + 23 sound SOUND_WARMUP "Sounds\\CutSequences\\SpaceShip\\Warmup.wav", + +functions: + void Precache(void) { + PrecacheModel (MODEL_SPACESHIP ); + PrecacheModel (MODEL_BODY ); + PrecacheTexture (TEXTURE_BODY ); + PrecacheModel (MODEL_DOOR ); + PrecacheTexture (TEXTURE_DOOR ); + PrecacheModel (MODEL_BEAMMACHINE ); + PrecacheTexture (TEXTURE_BEAMMACHINE ); + PrecacheModel (MODEL_BEAMRIM ); + PrecacheModel (MODEL_SHIP_INSIDE ); + PrecacheTexture (TEXTURE_BEAMRIM ); + PrecacheClass (CLASS_EFFECTOR, ET_SIZING_RING_FLARE); + PrecacheClass (CLASS_EFFECTOR, ET_SIZING_BIG_BLUE_FLARE); + PrecacheClass (CLASS_EFFECTOR, ET_LIGHTNING); + PrecacheClass (CLASS_EFFECTOR, ET_MOVING_RING); + PrecacheSound (SOUND_PLATES ); + PrecacheSound (SOUND_BEAMMACHINE ); + PrecacheSound (SOUND_BEAM ); + PrecacheSound (SOUND_WARMUP ); + } + + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if(penTarget==NULL) + { + return FALSE; + } + if( slPropertyOffset==offsetof(CPyramidSpaceShip, m_penTarget) || + slPropertyOffset==offsetof(CPyramidSpaceShip, m_penFlyAwayTarget)) + { + return( IsDerivedFromClass(penTarget, "Pyramid Space Ship Marker")); + } + return TRUE; + } + + // Check if entity is moved on a route set up by its targets + BOOL MovesByTargetedRoute( CTString &strTargetProperty) const + { + strTargetProperty = "Target"; + return TRUE; + } + + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker( CTFileName &fnmMarkerClass, CTString &strTargetProperty) const + { + fnmMarkerClass = CTFILENAME("Classes\\PyramidSpaceShipMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + + // returns description + const CTString &GetDescription(void) const + { + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s", (const char*)m_penTarget->GetName()); + } else { + ((CTString&)m_strDescription).PrintF("->"); + } + return m_strDescription; + } + + + CPlacement3D GetLerpedPlacement(void) const + { + return CMovableEntity::GetLerpedPlacement(); + } + + void PreMoving() + { + // remember old placement for lerping + en_plLastPlacement = en_plPlacement; + } + + void HideBeamMachine(void) + { + if(GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM_RIM) != NULL) + { + RemoveAttachment(SPACESHIP_ATTACHMENT_BEAM_RIM); + } + if(GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM) != NULL) + { + RemoveAttachment(SPACESHIP_ATTACHMENT_BEAM); + } + } + + void ShowBeamMachine(void) + { + AddAttachment(SPACESHIP_ATTACHMENT_BEAM_RIM, MODEL_BEAMRIM, TEXTURE_BEAMRIM); + AddAttachment(SPACESHIP_ATTACHMENT_BEAM, MODEL_BEAMMACHINE, TEXTURE_BEAMMACHINE); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM_RIM)->amo_moModelObject.StretchModel(PSS_STRETCH); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM)->amo_moModelObject.StretchModel(PSS_STRETCH); + } + + void InitializePathMoving( CPyramidSpaceShipMarker *penStartMarker) + { + // set as current + m_penTarget = penStartMarker; + + m_epssState = PSSS_MOVING; + // check all markers for correct type and numbers + INDEX ctMarkers=1; + CPyramidSpaceShipMarker *pcm0 = (CPyramidSpaceShipMarker*)&*m_penTarget; + if( pcm0 == NULL) + { + return; + } + CPyramidSpaceShipMarker *pcm = (CPyramidSpaceShipMarker*)&*pcm0->m_penTarget; + // loop thru markers + while( pcm!=NULL && pcm->m_penTarget!=pcm0) + { + pcm = (CPyramidSpaceShipMarker*)&*pcm->m_penTarget; + if (pcm==NULL) { + WarningMessage( "Space ship path - broken link!"); + return; + } + ctMarkers++; + if (ctMarkers>500) { + WarningMessage( "Space ship path - invalid marker loop!"); + return; + } + } + // check if we have enough markers to do smooth interpolation + if( ctMarkers<2) { + WarningMessage( "Space ship path requires at least 2 markers in order to work!"); + return; + } + + // prepare internal variables + FLOAT tmCurrent = _pTimer->CurrentTick(); + m_tmAtMarker = tmCurrent; + m_tmDelta = 0.0f; + m_bStopMoving = FALSE; + m_penLast = pcm; // keep last marker + ASSERT( pcm->m_penTarget == m_penTarget); + m_bMoving = TRUE; + AddToMovers(); + } + + void DoMoving() + { + if (!m_bMoving) { + return; + } + // read current tick + FLOAT tmCurrent = _pTimer->CurrentTick(); + // lerping is initially enabled + BOOL bLerping = TRUE; + + // if we hit a marker + if( tmCurrent > (m_tmAtMarker+m_tmDelta - _pTimer->TickQuantum*3/2)) + { + // get markers + CPyramidSpaceShipMarker *pcmNm1 = &(CPyramidSpaceShipMarker&)*m_penLast; + CPyramidSpaceShipMarker *pcmNp0 = &(CPyramidSpaceShipMarker&)*m_penTarget; + CPyramidSpaceShipMarker *pcmNp1 = &(CPyramidSpaceShipMarker&)*pcmNp0->m_penTarget; + CPyramidSpaceShipMarker *pcmNp2 = &(CPyramidSpaceShipMarker&)*pcmNp1->m_penTarget; + + // if there is a trigger at the hit marker + if (pcmNp0->m_penTrigger!=NULL) { + // trigger it + SendToTarget(pcmNp0->m_penTrigger, EET_TRIGGER, NULL); + } + + // update markers for next interval + m_penTarget = pcmNp1; + m_penLast = pcmNp0; + + // get markers + CPyramidSpaceShipMarker &cmNm1 = *pcmNm1; + CPyramidSpaceShipMarker &cmNp0 = *pcmNp0; + CPyramidSpaceShipMarker &cmNp1 = *pcmNp1; + CPyramidSpaceShipMarker &cmNp2 = *pcmNp2; + + // get positions from four markers + const FLOAT3D &vPNm1 = cmNm1.GetPlacement().pl_PositionVector; + const FLOAT3D &vPNp0 = cmNp0.GetPlacement().pl_PositionVector; + const FLOAT3D &vPNp1 = cmNp1.GetPlacement().pl_PositionVector; + const FLOAT3D &vPNp2 = cmNp2.GetPlacement().pl_PositionVector; + ANGLE3D aPNm1 = cmNm1.GetPlacement().pl_OrientationAngle; + ANGLE3D aPNp0 = cmNp0.GetPlacement().pl_OrientationAngle; + ANGLE3D aPNp1 = cmNp1.GetPlacement().pl_OrientationAngle; + ANGLE3D aPNp2 = cmNp2.GetPlacement().pl_OrientationAngle; + FLOAT fRotSpeedm1 = cmNm1.m_fRotSpeed; + FLOAT fRotSpeedp0 = cmNp0.m_fRotSpeed; + FLOAT fRotSpeedp1 = cmNp1.m_fRotSpeed; + FLOAT fRotSpeedp2 = cmNp2.m_fRotSpeed; + + // find quaternions for rotations + FLOATquat3D qPNm1; qPNm1.FromEuler(aPNm1); + FLOATquat3D qPNp0; qPNp0.FromEuler(aPNp0); + FLOATquat3D qPNp1; qPNp1.FromEuler(aPNp1); + FLOATquat3D qPNp2; qPNp2.FromEuler(aPNp2); + + // make all angles between quaternion pairs acute + if( qPNm1%qPNp0<0 ) { + qPNp0 = -qPNp0; + } + if( qPNp0%qPNp1<0 ) { + qPNp1 = -qPNp1; + } + if( qPNp1%qPNp2<0 ) { + qPNp2 = -qPNp2; + } + + // update time and position + m_tmAtMarker = m_tmAtMarker+m_tmDelta; + m_tmDelta = cmNp0.m_fDeltaTime; + m_vPNp0 = vPNp0; + m_vPNp1 = vPNp1; + m_fRotSpeedp0 = fRotSpeedp0; + m_fRotSpeedp1 = fRotSpeedp1; + m_qPNp0 = qPNp0; + m_qPNp1 = qPNp1; + + // determine delta time multipliers + FLOAT tmDNm1 = cmNm1.m_fDeltaTime; + FLOAT tmDNp0 = cmNp0.m_fDeltaTime; + FLOAT tmDNp1 = cmNp1.m_fDeltaTime; + FLOAT fD0 = 2*tmDNp0 / (tmDNm1+tmDNp0); + FLOAT fD1 = 2*tmDNp0 / (tmDNp0+tmDNp1); + + // determine biases, tensions and continuities + FLOAT fBNp0 = cmNp0.m_fBias; + FLOAT fTNp0 = cmNp0.m_fTension; + FLOAT fCNp0 = cmNp0.m_fContinuity; + FLOAT fBNp1 = cmNp1.m_fBias; + FLOAT fTNp1 = cmNp1.m_fTension; + FLOAT fCNp1 = cmNp1.m_fContinuity; + + FLOAT fF00 = (1-fTNp0)*(1-fCNp0)*(1-fBNp0) / 2; + FLOAT fF01 = (1-fTNp0)*(1+fCNp0)*(1+fBNp0) / 2; + FLOAT fF10 = (1-fTNp1)*(1+fCNp1)*(1-fBNp1) / 2; + FLOAT fF11 = (1-fTNp1)*(1-fCNp1)*(1+fBNp1) / 2; + + // find tangents for translation + m_vTNp0 = ( (vPNp1-vPNp0) * fF00 + (vPNp0-vPNm1) * fF01) * fD0; + m_vTNp1 = ( (vPNp2-vPNp1) * fF10 + (vPNp1-vPNp0) * fF11) * fD1; + + // find tangents for moving speed + m_fTRotSpeedp0 = ( (fRotSpeedp1-fRotSpeedp0) * fF00 + (fRotSpeedp0-fRotSpeedm1) * fF01) * fD0; + m_fTRotSpeedp1 = ( (fRotSpeedp2-fRotSpeedp1) * fF10 + (fRotSpeedp1-fRotSpeedp0) * fF11) * fD1; + + // find tangents for rotation + FLOATquat3D qTNp0, qTNp1; + qTNp0 = ( Log(qPNp0.Inv()*qPNp1) * fF00 + Log(qPNm1.Inv()*qPNp0) * fF01) * fD0; + qTNp1 = ( Log(qPNp1.Inv()*qPNp2) * fF10 + Log(qPNp0.Inv()*qPNp1) * fF11) * fD1; + + // find squad parameters + m_qANp0 = qPNp0*Exp( (qTNp0 - Log(qPNp0.Inv()*qPNp1))/2 ); + m_qANp1 = qPNp1*Exp( (Log(qPNp0.Inv()*qPNp1) - qTNp1)/2 ); + + // check for stop moving + if( cmNp0.m_bStopMoving && m_fRotSpeed==0.0f) { + m_bStopMoving = TRUE; + } + } + + // calculate the parameter value and hermit basis + FLOAT fT = (tmCurrent - m_tmAtMarker) / m_tmDelta; + FLOAT fH0 = 2*fT*fT*fT - 3*fT*fT + 1; + FLOAT fH1 = -2*fT*fT*fT + 3*fT*fT; + FLOAT fH2 = fT*fT*fT - 2*fT*fT + fT; + FLOAT fH3 = fT*fT*fT - fT*fT; + + // interpolate position, rotation and fov + FLOAT3D vPos = m_vPNp0*fH0 + m_vPNp1*fH1 + m_vTNp0*fH2 + m_vTNp1*fH3; + FLOAT fRotSpeed = m_fRotSpeedp0*fH0 + m_fRotSpeedp1*fH1 + m_fTRotSpeedp0*fH2 + m_fTRotSpeedp1*fH3; + FLOATquat3D qRot = Squad(fT, m_qPNp0, m_qPNp1, m_qANp0, m_qANp1); + FLOATmatrix3D mRotLocal; + MakeRotationMatrixFast(mRotLocal, ANGLE3D(m_fRot,0,0)); + FLOATmatrix3D mRot; + qRot.ToMatrix(mRot); + mRot = mRotLocal*mRot; + + // just cache near polygons for various engine needs + en_vNextPosition = vPos; + en_mNextRotation = mRot; + CacheNearPolygons(); + + // set new placement + CPlacement3D plNew; + plNew.pl_PositionVector = vPos; + DecomposeRotationMatrixNoSnap(plNew.pl_OrientationAngle, mRot); + SetPlacement_internal(plNew, mRot, TRUE); + // if lerping is disabled + if (!bLerping) { + // make last placement same as this one + en_plLastPlacement = en_plPlacement; + } + // set new speed + m_fLastRotSpeed = m_fRotSpeed; + m_fRotSpeed = fRotSpeed; + m_fRot += m_fRotSpeed; + } + + + void PostMoving() + { + if (!m_bMoving) { + return; + } + // + if( m_bStopMoving) { + m_bMoving = FALSE; + // mark for removing from list of movers + en_ulFlags |= ENF_INRENDERING; + m_epssState = PSSS_REACHED_DESTINATION; + // remember old placement for lerping + en_plLastPlacement = en_plPlacement; + } + } + + void SpawnBeamMachineFlares(void) + { + // spawn small beam machine flares + CPlacement3D plSpaceShip = GetPlacement(); + CPlacement3D plFlare1 = CPlacement3D( FLOAT3D( BM_DX, BM_DY+BM_FLARE_DY, 0), ANGLE3D(0,0,0)); + CPlacement3D plFlare2 = CPlacement3D( FLOAT3D( 0, BM_DY+BM_FLARE_DY, -BM_DZ), ANGLE3D(0,0,0)); + CPlacement3D plFlare3 = CPlacement3D( FLOAT3D( -BM_DX, BM_DY+BM_FLARE_DY, 0), ANGLE3D(0,0,0)); + CPlacement3D plFlare4 = CPlacement3D( FLOAT3D( 0, BM_DY+BM_FLARE_DY, BM_DZ), ANGLE3D(0,0,0)); + + plFlare1.RelativeToAbsolute(plSpaceShip); + plFlare2.RelativeToAbsolute(plSpaceShip); + plFlare3.RelativeToAbsolute(plSpaceShip); + plFlare4.RelativeToAbsolute(plSpaceShip); + + CEntity *penFlare1 = CreateEntity( plFlare1, CLASS_EFFECTOR); + CEntity *penFlare2 = CreateEntity( plFlare2, CLASS_EFFECTOR); + CEntity *penFlare3 = CreateEntity( plFlare3, CLASS_EFFECTOR); + CEntity *penFlare4 = CreateEntity( plFlare4, CLASS_EFFECTOR); + + ESpawnEffector eSpawnFlare; + eSpawnFlare.tmLifeTime = SMALL_FLARES_LIFE_TIME; + eSpawnFlare.tmLifeTime = 20.0f; + eSpawnFlare.eetType = ET_SIZING_RING_FLARE; + + penFlare1->Initialize( eSpawnFlare); + penFlare2->Initialize( eSpawnFlare); + penFlare3->Initialize( eSpawnFlare); + penFlare4->Initialize( eSpawnFlare); + } + + void SpawnBeamMachineMainFlare(void) + { + // spawn main flare + CPlacement3D plSpaceShip = GetPlacement(); + CPlacement3D plFlare = CPlacement3D( FLOAT3D(0, BM_MASTER_Y+BM_FLARE_DY, 0), ANGLE3D(0,0,0)); + plFlare.RelativeToAbsolute(GetPlacement()); + CEntity *penFlare = CreateEntity( plFlare, CLASS_EFFECTOR); + ESpawnEffector eSpawnFlare; + eSpawnFlare.tmLifeTime = 20.0f; + eSpawnFlare.fSize = 1.0f; + eSpawnFlare.eetType = ET_SIZING_BIG_BLUE_FLARE; + penFlare->Initialize( eSpawnFlare); + } + + void ShowBeamMachineHitFlare(void) + { + if( m_penHitPlaceFlare!=NULL && IsOfClass(m_penHitPlaceFlare, "ModelHolder2") ) + { + CModelObject *pmo = m_penHitPlaceFlare->GetModelObject(); + if( pmo != NULL) + { + m_penHitPlaceFlare->SwitchToModel(); + } + } + } + + void HideBeamMachineHitFlare(void) + { + m_tmHitFlareTime = -1; + if( m_penHitPlaceFlare!=NULL && IsOfClass(m_penHitPlaceFlare, "ModelHolder2") ) + { + CModelObject *pmo = m_penHitPlaceFlare->GetModelObject(); + if( pmo != NULL) + { + m_penHitPlaceFlare->SwitchToEditorModel(); + pmo->mo_colBlendColor = C_WHITE|CT_OPAQUE; + } + } + } + + void SpawnBeamMachineLightnings(void) + { + // spawn beam lightnings + CPlacement3D plLightning1 = CPlacement3D( FLOAT3D(BM_DX, BM_DY, 0), ANGLE3D(0,0,0)); + CPlacement3D plLightning2 = CPlacement3D( FLOAT3D(0, BM_DY, -BM_DZ), ANGLE3D(0,0,0)); + CPlacement3D plLightning3 = CPlacement3D( FLOAT3D(-BM_DX, BM_DY, 0), ANGLE3D(0,0,0)); + CPlacement3D plLightning4 = CPlacement3D( FLOAT3D(0, BM_DY, BM_DZ), ANGLE3D(0,0,0)); + + CPlacement3D plLightningDest = CPlacement3D( FLOAT3D(0, BM_MASTER_Y, 0), ANGLE3D(0,0,0)); + CPlacement3D plSpaceShip = GetPlacement(); + plLightningDest.RelativeToAbsolute(plSpaceShip); + + plLightning1.RelativeToAbsolute(plSpaceShip); + plLightning2.RelativeToAbsolute(plSpaceShip); + plLightning3.RelativeToAbsolute(plSpaceShip); + plLightning4.RelativeToAbsolute(plSpaceShip); + + CEntity *penLightning1 = CreateEntity( plLightning1, CLASS_EFFECTOR); + CEntity *penLightning2 = CreateEntity( plLightning2, CLASS_EFFECTOR); + CEntity *penLightning3 = CreateEntity( plLightning3, CLASS_EFFECTOR); + CEntity *penLightning4 = CreateEntity( plLightning4, CLASS_EFFECTOR); + + ESpawnEffector eSpawnLightning; + eSpawnLightning.eetType = ET_LIGHTNING; + eSpawnLightning.tmLifeTime = SMALL_LIGHTININGS_LIFE_TIME; + eSpawnLightning.vDestination = plLightningDest.pl_PositionVector; + eSpawnLightning.fSize = 16.0f; + eSpawnLightning.ctCount = 16; + + penLightning1->Initialize( eSpawnLightning); + penLightning2->Initialize( eSpawnLightning); + penLightning3->Initialize( eSpawnLightning); + penLightning4->Initialize( eSpawnLightning); + } + + void SpawnBeamMachineMainLightning(void) + { + // spawn main lightning + FLOAT3D vDestination = GetPlacement().pl_PositionVector + FLOAT3D( 0, BM_MASTER_Y, 0); + CPlacement3D plSource = CPlacement3D( vDestination, ANGLE3D(0,0,0)); + if( m_penBeamHit != NULL) + { + plSource.pl_PositionVector = m_penBeamHit->GetPlacement().pl_PositionVector; + CEntity *penEffector = CreateEntity( plSource, CLASS_EFFECTOR); + ESpawnEffector eSpawnEffector; + eSpawnEffector.eetType = ET_LIGHTNING; + eSpawnEffector.tmLifeTime = BIG_LIGHT_BEAM_LIFE_TIME; + eSpawnEffector.vDestination = vDestination; + eSpawnEffector.fSize = 32.0f; + eSpawnEffector.ctCount = 32; + penEffector->Initialize( eSpawnEffector); + } + } + + void SpawnMovingRing(void) + { + if( m_penBeamHit != NULL) + { + FLOAT3D vStart = GetPlacement().pl_PositionVector + FLOAT3D( 0, BM_MASTER_Y, 0); + CPlacement3D plSource = CPlacement3D( vStart, ANGLE3D(0,0,0)); + FLOAT3D vHitPlace = m_penBeamHit->GetPlacement().pl_PositionVector; + CEntity *penEffector = CreateEntity( plSource, CLASS_EFFECTOR); + ESpawnEffector eSpawnEffector; + eSpawnEffector.eetType = ET_MOVING_RING; + eSpawnEffector.tmLifeTime = BIG_LIGHT_BEAM_LIFE_TIME; + eSpawnEffector.vDestination = vHitPlace+FLOAT3D(0.0f, 0.0f, 0.0f); + eSpawnEffector.fSize = 16.0f; + eSpawnEffector.ctCount = 2; + penEffector->Initialize( eSpawnEffector); + } + } + + void TurnOnLightBeam(void) + { + if( m_penLightBeam!=NULL && IsOfClass(m_penLightBeam, "ModelHolder2") ) + { + CModelObject *pmo = m_penLightBeam->GetModelObject(); + m_penLightBeam->SwitchToModel(); + pmo->mo_colBlendColor = C_WHITE|CT_OPAQUE; + } + } + + void TurnOffLightBeam(void) + { + m_tmBeamTime=-1.0f; + + if( m_penLightBeam!=NULL && IsOfClass(m_penLightBeam, "ModelHolder2") ) + { + m_penLightBeam->SwitchToEditorModel(); + CModelObject *pmo = m_penLightBeam->GetModelObject(); + } + } + + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) + { + FLOAT fBeamRatio = 1.0f; + + // light beam + if( m_penLightBeam!=NULL && IsOfClass(m_penLightBeam, "ModelHolder2") ) + { + CModelObject *pmo = m_penLightBeam->GetModelObject(); + if( pmo != NULL) + { + if( m_tmBeamTime>-1.0f) + { + FLOAT fT = _pTimer->CurrentTick()-m_tmBeamTime; + fBeamRatio = 1.0f-ClampUp(fT/2.0f, 1.0f); + UBYTE ub = UBYTE (255.0f*fBeamRatio); + COLOR col = RGBAToColor(ub,ub,ub,ub); + pmo->mo_colBlendColor = col; + } + } + } + + // hit flare + if( m_penHitPlaceFlare!=NULL && IsOfClass(m_penHitPlaceFlare, "ModelHolder2") ) + { + CModelObject *pmo = m_penHitPlaceFlare->GetModelObject(); + if( pmo != NULL) + { + if( m_tmHitFlareTime>-1.0f) + { + FLOAT fT = _pTimer->CurrentTick()-m_tmHitFlareTime; + FLOAT fRatio = (Sin(fT*2000)*0.5f+0.5f)*(Sin(fT*1333)*0.5f+0.5f); + /*if(fRatio>0.5f) + { + fRatio=0.0f; + } + else + { + fRatio=1.0f; + }*/ + + UBYTE ub = UBYTE((200+55*fRatio)*fBeamRatio); + //ub = 255; + COLOR col = RGBAToColor(ub,ub,ub,ub); + pmo->mo_colBlendColor = col; + } + } + } + return FALSE; + }; + +procedures: + + OpenDoors() + { + // if ship inside not yet added + if( GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_SHIPINSIDE) == NULL) + { + // add it + AddAttachment( SPACESHIP_ATTACHMENT_SHIPINSIDE, MODEL_SHIP_INSIDE, TEXTURE_BODY); + GetModelObject()->StretchModel(PSS_STRETCH); + } + ShowBeamMachine(); + + PlaySound( m_soPlates, SOUND_PLATES, SOF_3D); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR2)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR3)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR4)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR5)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR6)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR7)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR8)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); + + // all children lights named pulsating should pulsate + FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) + { + if( IsOfClass(iten, "Light")) + { + if( iten->GetName() == "Pulsating") + { + CLight *penLight = (CLight *) &*iten; + EChangeAnim eChange; + eChange.iLightAnim=3; + eChange.bLightLoop=TRUE; + penLight->SendEvent(eChange); + } + else if( iten->GetName() == "Motors") + { + CLight *penLight = (CLight *) &*iten; + EChangeAnim eChange; + eChange.iLightAnim=4; + eChange.bLightLoop=TRUE; + penLight->SendEvent(eChange); + } + } + } + + m_epssState = PSSS_KILLING_BEAM_FIREING; + return EReturn(); + } + + CloseDoors() + { + m_epssState=PSSS_DOORS_CLOSED; + // if ship inside attachment added + if( GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_SHIPINSIDE) != NULL) + { + PlaySound( m_soPlates, SOUND_PLATES, SOF_3D); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR2)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR3)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR4)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR5)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR6)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR7)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR8)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); + + autowait( GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.GetAnimLength(DOOR_ANIM_CLOSING)); + // remove ship inside attachment + RemoveAttachment( SPACESHIP_ATTACHMENT_SHIPINSIDE); + } + + HideBeamMachine(); + InitializePathMoving( (CPyramidSpaceShipMarker*)&*m_penFlyAwayTarget); + return EReturn(); + } + + FireLightBeam() + { + if(m_epssState==PSSS_DOORS_CLOSED) + { + return; + } + + if(m_epssState==PSSS_BEAM_DEACTIVATED) + { + m_bFireingDeactivatedBeam=TRUE; + } + + PlaySound( m_soBeamMachine, SOUND_BEAMMACHINE, SOF_3D); + GetModelObject()->PlayAnim(SPACESHIP_ANIM_OPENING, 0); + autowait( GetModelObject()->GetAnimLength(SPACESHIP_ANIM_OPENING)); + + PlaySound( m_soBeamMachine, SOUND_WARMUP, SOF_3D); + SpawnBeamMachineFlares(); + autowait( SMALL_FLARE_WAIT); + + SpawnBeamMachineLightnings(); + autowait( SMALL_LIGHTNING_WAIT); + + SpawnBeamMachineMainFlare(); + autowait( BIG_FLARE_WAIT); + + // turn on light beam + TurnOnLightBeam(); + if(!m_bFireingDeactivatedBeam) + { + SpawnBeamMachineMainLightning(); + } + + m_soBeam.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME, 1.0f); + PlaySound( m_soBeam, SOUND_BEAM, SOF_3D|SOF_LOOP); + ShowBeamMachineHitFlare(); + m_tmHitFlareTime = _pTimer->CurrentTick(); + + m_iRingCounter = 0; + while(_pTimer->CurrentTick()CurrentTick(); + while( _pTimer->CurrentTick() < m_tmTemp+0.49f) + { + autowait(_pTimer->TickQuantum); + // cast ray for possible damage + if( m_penBeamHit != NULL && !m_bFireingDeactivatedBeam) + { + // cast ray + FLOAT3D vSource = GetPlacement().pl_PositionVector + FLOAT3D( 0, BM_MASTER_Y, 0); + FLOAT3D vDestination = m_penBeamHit->GetPlacement().pl_PositionVector; + CCastRay crRay( this, vSource, vDestination); + crRay.cr_bHitTranslucentPortals = FALSE; + crRay.cr_bPhysical = FALSE; + crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; + crRay.cr_fTestR = 16.0f; + GetWorld()->CastRay(crRay); + + // if entity is hit + if( crRay.cr_penHit != NULL) + { + InflictDirectDamage( crRay.cr_penHit, this, DMT_BULLET, + 10000.0f/GetGameDamageMultiplier()*_pTimer->TickQuantum/0.5f/16.0f, + FLOAT3D(0, 0, 0), (vSource-vDestination).Normalize()); + crRay.cr_penHit->SendEvent( EHitBySpaceShipBeam()); + } + } + } + } + + m_tmBeamTime = _pTimer->CurrentTick(); + while(_pTimer->CurrentTick()TickQuantum); + FLOAT tmNow = _pTimer->CurrentTick(); + FLOAT fRatio = CalculateRatio(tmNow, m_tmBeamTime, m_tmBeamTime+2.0f, 0, 1.0f); + m_soBeam.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, fRatio*SND_VOLUME, 1.0f); + } + + // turn off light beam + TurnOffLightBeam(); + HideBeamMachineHitFlare(); + + // little pause + autowait( 2.0f); + + GetModelObject()->PlayAnim(SPACESHIP_ANIM_CLOSING, 0); + PlaySound( m_soBeamMachine, SOUND_BEAMMACHINE, SOF_3D); + autowait( GetModelObject()->GetAnimLength(SPACESHIP_ANIM_CLOSING)); + + m_tmHitFlareTime = -1.0f; + m_tmBeamTime = -1.0f; + + if(m_bFireingDeactivatedBeam) + { + jump CloseDoors(); + } + return EReturn(); + } + + Main() { + // declare yourself as a model + InitAsEditorModel(); + //InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); + SetCollisionFlags(ECF_MODEL_HOLDER); + + en_fAcceleration = 1e6f; + en_fDeceleration = 1e6f; + + m_soBeam.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME, 1.0f); + m_soBeamMachine.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME/2.0f, 1.0f); + m_soPlates.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME/2.0f, 1.0f); + m_soFlaresFX.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME, 1.0f); + + // set appearance + SetModel(MODEL_SPACESHIP); + SetModelMainTexture(TEXTURE_BODY); + AddAttachment(SPACESHIP_ATTACHMENT_BODY, MODEL_BODY, TEXTURE_BODY); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR1, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR2, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR3, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR4, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR5, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR6, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR7, MODEL_DOOR, TEXTURE_DOOR); + AddAttachment(SPACESHIP_ATTACHMENT_DOOR8, MODEL_DOOR, TEXTURE_DOOR); + + GetModelObject()->StretchModel(PSS_STRETCH); + ModelChangeNotify(); + m_bMoving = FALSE; + m_epssState = PSSS_IDLE; + m_bFireingDeactivatedBeam=FALSE; + + autowait( 0.25f); + + // turn off light beam + TurnOffLightBeam(); + // turn off light beam hit flare + HideBeamMachineHitFlare(); + + // start moving + wait() { + on( EActivate): + { + SwitchToModel(); + InitializePathMoving((CPyramidSpaceShipMarker*)&*m_penTarget); + resume; + } + on( ETrigger): + { + if(m_epssState == PSSS_IDLE) + { + // ignore all triggs + } + else if( m_epssState==PSSS_KILLING_BEAM_FIREING) + { + call FireLightBeam(); + } + else if(m_epssState==PSSS_BEAM_DEACTIVATED) + { + call FireLightBeam(); + } + else if(m_epssState == PSSS_REACHED_DESTINATION) + { + call OpenDoors(); + } + resume; + } + on (EForcePathMarker eForcePathMarker): + { + if(m_epssState != PSSS_IDLE) + { + m_penTarget = eForcePathMarker.penForcedPathMarker; + InitializePathMoving((CPyramidSpaceShipMarker*)&*m_penTarget); + } + resume; + } + on( EDeactivate): + { + m_epssState = PSSS_BEAM_DEACTIVATED; + resume; + } + on( EReturn): + { + resume; + } + } + + Destroy(); + return; + } +}; diff --git a/Sources/Entities/PyramidSpaceShipMarker.es b/Sources/Entities/PyramidSpaceShipMarker.es new file mode 100644 index 0000000..8bbe09e --- /dev/null +++ b/Sources/Entities/PyramidSpaceShipMarker.es @@ -0,0 +1,100 @@ +610 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/PyramidSpaceShip.h" +%} + +uses "Entities/Marker"; + +class CPyramidSpaceShipMarker: CMarker +{ +name "Pyramid Space Ship Marker"; +thumbnail "Thumbnails\\PyramidSpaceShipMarker.tbn"; + +properties: + + 1 FLOAT m_fDeltaTime "Delta time" 'D' = 5.0f, + 2 FLOAT m_fBias "Bias" 'B' = 0.0f, + 3 FLOAT m_fTension "Tension" 'E' = 0.0f, + 4 FLOAT m_fContinuity "Continuity" 'C' = 0.0f, + 5 BOOL m_bStopMoving "Stop moving" 'O' = FALSE, + 6 CEntityPointer m_penTrigger "Trigger" 'G', // PyramidSpaceShip triggers when at this marker + 7 FLOAT m_fRotSpeed "Rotation speed" 'R' = 0.0f, // current speed of rotation + 8 CEntityPointer m_penSpaceShip "Space ship" 'S', // pointer to PyramidSpaceShip, for forcing next path marker + +components: + + 1 model MODEL_MARKER "Models\\Editor\\Axis.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\Vector.tex" + + +functions: + BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) + { + if(penTarget==NULL) + { + return FALSE; + } + if(slPropertyOffset == offsetof(CPyramidSpaceShipMarker, m_penTarget)) + { + return( IsDerivedFromClass(penTarget, "Pyramid Space Ship Marker") || + IsDerivedFromClass(penTarget, "PyramidSpaceShip") ); + } + return TRUE; + } + + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker( CTFileName &fnmMarkerClass, CTString &strTargetProperty) const + { + fnmMarkerClass = CTFILENAME("Classes\\PyramidSpaceShipMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + if (ee.ee_slEvent==EVENTCODE_ETrigger) + { + if(m_penSpaceShip!=NULL && m_penTarget!=NULL) + { + EForcePathMarker eForcePathMarker; + eForcePathMarker.penForcedPathMarker = m_penTarget; + m_penSpaceShip->SendEvent(eForcePathMarker); + return TRUE; + } + } + return FALSE; + } + +procedures: + + Main() + { + // clamp parameters + m_fDeltaTime = ClampDn( m_fDeltaTime, 0.001f); + m_fBias = Clamp( m_fBias, -1.0f, +1.0f); + m_fTension = Clamp( m_fTension, -1.0f, +1.0f); + m_fContinuity = Clamp( m_fContinuity, -1.0f, +1.0f); + + // init model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + GetModelObject()->StretchModel(FLOAT3D(4,4,4)); + ModelChangeNotify(); + + if( m_penTarget!=NULL && !IsOfClass( m_penTarget, "Pyramid Space Ship Marker")) { + WarningMessage( "Entity '%s' is not of Pyramid Space Ship Marker class!", (const char*)m_penTarget->GetName()); + m_penTarget = NULL; + } + + return; + } + +}; + diff --git a/Sources/Entities/Reminder.es b/Sources/Entities/Reminder.es new file mode 100644 index 0000000..e527add --- /dev/null +++ b/Sources/Entities/Reminder.es @@ -0,0 +1,52 @@ +703 +%{ +#include "Entities/StdH/StdH.h" +%} + +// input parameter for timer +event EReminderInit { + CEntityPointer penOwner, // who owns it + FLOAT fWaitTime, // wait time + INDEX iValue, // reminder event value +}; + +class export CReminder : CRationalEntity { +name "Reminder"; +thumbnail ""; + +properties: + 1 CEntityPointer m_penOwner, // entity which owns it + 2 FLOAT m_fWaitTime = 0.0f, // wait time + 3 INDEX m_iValue = 0, // reminder event value + +components: +functions: +procedures: + Main(EReminderInit eri) { + // remember the initial parameters + ASSERT(eri.penOwner!=NULL); + m_penOwner = eri.penOwner; + m_fWaitTime = eri.fWaitTime; + m_iValue = eri.iValue; + + // init as nothing + InitAsVoid(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // wait + if (m_fWaitTime > 0.0f) { + autowait(m_fWaitTime); + EReminder er; + er.iValue = m_iValue; + if (m_penOwner!=NULL) { + m_penOwner->SendEvent(er); + } + } + + // cease to exist + Destroy(); + + return; + }; +}; \ No newline at end of file diff --git a/Sources/Entities/RobotDriving.es b/Sources/Entities/RobotDriving.es new file mode 100644 index 0000000..1abfbac --- /dev/null +++ b/Sources/Entities/RobotDriving.es @@ -0,0 +1,263 @@ +333 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Projectile"; + +enum RobotDrivingChar { + 0 RDC_R2D2 "R2D2", + 1 RDC_SPIDER "Spider", +}; + +%{ +// info structure +static EntityInfo eiRobotDriving = { + EIBT_ROBOT, 100.0f, // mass[kg] + 0.0f, 1.5f, 0.0f, // source + 0.0f, 1.5f, 0.0f, // target +}; + +#define FIRE_POS FLOAT3D(0.0f, 1.0f, -1.0f) +%} + + +class CRobotDriving : CEnemyBase { +name "RobotDriving"; +thumbnail "Thumbnails\\RobotDriving.tbn"; + +properties: + 1 enum RobotDrivingChar m_rdcChar "Character" 'C' = RDC_R2D2, + 2 FLOAT m_fSize = 1.0f, + + 10 CSoundObject m_soFire0, + 11 CSoundObject m_soFire1, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + + 10 model MODEL_R2D2 "Models\\Enemies\\Robots\\DrivingWheel\\Robot.mdl", + 11 texture TEXTURE_R2D2 "Models\\Enemies\\Robots\\DrivingWheel\\Robot.tex", + + 12 model MODEL_SPIDER "Models\\Enemies\\Robots\\DrivingSpider\\DrivingSpider.mdl", + 13 texture TEXTURE_SPIDER "Models\\Enemies\\Robots\\SentryBall\\Ball.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Walker\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Walker\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Walker\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE_LASER "Models\\Enemies\\Walker\\Sounds\\FireLaser.wav", + 55 sound SOUND_KICK "Models\\Enemies\\Walker\\Sounds\\Kick.wav", + 56 sound SOUND_DEATH "Models\\Enemies\\Walker\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiRobotDriving; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // can't harm each other + if (!IsOfSameClass(penInflictor, this)) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + // virtual anim functions + void StandingAnim(void) { +// StartModelAnim(WALKER_ANIM_STAND03, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { +// StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { +// StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { +// StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire { + // r2d2 + if (m_rdcChar==RDC_R2D2) { + // to fire + //StartModelAnim(WALKER_ANIM_TOFIRE, 0); + m_fLockOnEnemyTime = 0.5f;//GetModelObject()->GetAnimLenght(WALKER_ANIM_TOFIRE); + autocall CEnemyBase::LockOnEnemy() EReturn; + + StopMoving(); + //StartModelAnim(WALKER_ANIM_ATTACK02LEFT, AOF_LOOPING); + + ShootProjectile(PRT_CYBORG_LASER, FIRE_POS*m_fSize, ANGLE3D(0, 0, 0)); + PlaySound(m_soFire0, SOUND_FIRE_LASER, SOF_3D); + autowait(0.25f); + ShootProjectile(PRT_CYBORG_LASER, FIRE_POS*m_fSize, ANGLE3D(0, 0, 0)); + PlaySound(m_soFire1, SOUND_FIRE_LASER, SOF_3D); + + // wait for a while + StandingAnim(); + autowait(FRnd()*0.1f+0.1f); + + // spider + } else if (TRUE) { + + // don't shoot if enemy above or below you more than 5 meters + if (Abs(en_vGravityDir%CalcDelta(m_penEnemy)) > 5.0f) { + return EEnd(); + } + + m_fLockOnEnemyTime = 0.5f;//GetModelObject()->GetAnimLenght(WALKER_ANIM_TOFIRE); + autocall CEnemyBase::LockOnEnemy() EReturn; + + // hit bomb + + FLOAT fSpeed = Sqrt(en_fGravityA*(CalcDist(m_penEnemy)*1.25f)); + // target enemy body + EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); + FLOAT3D vShootTarget; + GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); + // launch + CPlacement3D pl; + PreparePropelledProjectile(pl, vShootTarget, FLOAT3D(0.0f, 1.5f, -0.7f), ANGLE3D(0, 45.0f, 0)); + CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_HEADMAN_BOMBERMAN; + eLaunch.fSpeed = fSpeed; + penProjectile->Initialize(eLaunch); + + //StartModelAnim(WALKER_ANIM_ATTACK02LEFT, AOF_LOOPING); + PlaySound(m_soFire0, SOUND_FIRE_LASER, SOF_3D); + StopMoving(); + // wait for a while + StandingAnim(); + autowait(FRnd()*0.1f+0.1f); + } + + return EReturn(); + }; + + + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + // stop moving + StopMoving(); + DeathSound(); // death sound + + // set physic flags + SetPhysicsFlags(EPF_MODEL_CORPSE); + SetCollisionFlags(ECF_CORPSE); + // robots don't have different collision boxes, so no need to change + // robots don't have death animations + return EEnd(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + + SetHealth(20.0f); + m_fMaxHealth = 20.0f; + m_fBlowUpAmount = 0.0f; + m_fBodyParts = 4; + m_bRobotBlowup = TRUE; + m_fDamageWounded = 100000.0f; + + en_fDensity = 10000.0f; + + switch (m_rdcChar) { + case RDC_R2D2: { + // set your appearance + m_fSize = 1.0f; + SetComponents(this, *GetModelObject(), + MODEL_R2D2, TEXTURE_R2D2, 0,0,0); + GetModelObject()->StretchModel(FLOAT3D(1,1,1)); + ModelChangeNotify(); + + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd() + 5.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd() + 5.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 8.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 200.0f; + + m_iScore = 100; + } break; + case RDC_SPIDER: { + // set your appearance + m_fSize = 1.0f; + SetComponents(this, *GetModelObject(), + MODEL_SPIDER, TEXTURE_SPIDER, 0,0,0); + GetModelObject()->StretchModel(FLOAT3D(1,1,1)); + ModelChangeNotify(); + + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 500.0f); + m_fAttackRunSpeed = FRnd() + 4.0f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + m_fCloseRunSpeed = FRnd() + 4.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); + // setup attack distances + m_fAttackDistance = 45.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 20.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.5f; + m_fIgnoreRange = 150.0f; + + m_iScore = 500; + } break; + default: ASSERT(FALSE); + } + StandingAnim(); + // set sound default parameters + m_soFire0.Set3DParameters(160.0f, 5.0f, 1.0f, 1.0f); + m_soFire1.Set3DParameters(160.0f, 5.0f, 1.0f, 1.0f); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/RobotFixed.es b/Sources/Entities/RobotFixed.es new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Entities/RobotFlying.es b/Sources/Entities/RobotFlying.es new file mode 100644 index 0000000..22c93c5 --- /dev/null +++ b/Sources/Entities/RobotFlying.es @@ -0,0 +1,209 @@ +334 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/EnemyFly"; + +enum RobotFlyingChar { + 0 RFC_KAMIKAZE "Kamikaze", + 1 RFC_FIGHTER "Fighter", +}; + +%{ +static EntityInfo eiRobotFlying = { + EIBT_ROBOT, 100.0f, // mass[kg] + 0.0f, 0.0f, 0.0f, // source + 0.0f, 0.0f, 0.0f, // target +}; + +#define FIRE_POS FLOAT3D(0.0f, 0.0f, 0.0f) +%} + + +class CRobotFlying : CEnemyFly { +name "RobotFlying"; +thumbnail "Thumbnails\\RobotFlying.tbn"; + +properties: + 1 enum RobotFlyingChar m_rfcChar "Character" 'C' = RFC_FIGHTER, +components: + 0 class CLASS_BASE "Classes\\EnemyFly.ecl", + + 10 model MODEL_KAMIKAZE "Models\\Enemies\\Robots\\FloatKamikaze\\FloatKamikaze.mdl", + 11 texture TEXTURE_KAMIKAZE "Models\\Enemies\\Robots\\SentryBall\\Ball.tex", + + 12 model MODEL_FIGHTER "Models\\Enemies\\Robots\\FlyingFighter\\Ship.mdl", + 13 texture TEXTURE_FIGHTER "Models\\Enemies\\Robots\\FlyingFighter\\Ship.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Woman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Woman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Woman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Woman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Woman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Woman\\Sounds\\Death.wav", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiRobotFlying; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + if (!IsOfSameClass(penInflictor, this)) { + CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + // virtual anim functions + void StandingAnim(void) { +// StartModelAnim(WALKER_ANIM_STAND03, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { +// StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { +// StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { +// StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + FlyHit(EVoid) : CEnemyFly::FlyHit { + if (m_rfcChar==RFC_FIGHTER) { + jump FlyFire(); +// m_fShootTime = _pTimer->CurrentTick() + 1.0f; +// return EReturn(); + } + + // when close enough + if (CalcDist(m_penEnemy) <= 3.0f) { + // explode + SetHealth(-45.0f); + ReceiveDamage(NULL, DMT_EXPLOSION, 10.0f, FLOAT3D(0,0,0), FLOAT3D(0,1,0)); + InflictRangeDamage(this, DMT_EXPLOSION, 20.0f, GetPlacement().pl_PositionVector, + 2.75f, 8.0f); + } + + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.1f; + return EReturn(); + }; + + FlyFire(EVoid) : CEnemyFly::FlyFire { + if (m_rfcChar==RFC_KAMIKAZE) { + m_fShootTime = _pTimer->CurrentTick() + 1.0f; + return EReturn(); + } + + ShootProjectile(PRT_CYBORG_LASER, FIRE_POS, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + + return EReturn(); + }; + + Death(EVoid) : CEnemyBase::Death { + // stop moving + StopMoving(); + DeathSound(); // death sound + + // set physic flags + SetPhysicsFlags(EPF_MODEL_CORPSE); + SetCollisionFlags(ECF_CORPSE); + // robots don't have different collision boxes, so no need to change + // robots don't have death animations + return EEnd(); + }; + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // must always be fly-only + m_EeftType = EFT_FLY_ONLY; + + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(20.0f); + m_fMaxHealth = 20.0f; + en_fDensity = 13000.0f; + // damage/explode properties + m_fBlowUpAmount = 0.0f; + m_fBodyParts = 4; + m_bRobotBlowup = TRUE; + m_fDamageWounded = 100000.0f; + + // set your appearance + switch (m_rfcChar) { + case RFC_KAMIKAZE: { + SetModel(MODEL_KAMIKAZE); + SetModelMainTexture(TEXTURE_KAMIKAZE); + // fly moving properties + m_fFlyWalkSpeed = FRnd()/2 + 1.0f; + m_aFlyWalkRotateSpeed = FRnd()*10.0f + 25.0f; + m_fFlyAttackRunSpeed = FRnd()*2.0f + 8.0f; + m_aFlyAttackRotateSpeed = FRnd()*25 + 150.0f; + m_fFlyCloseRunSpeed = FRnd()*2.0f + 6.0f; + m_aFlyCloseRotateSpeed = FRnd()*50 + 500.0f; + // attack properties - CAN BE SET + m_fFlyAttackDistance = 50.0f; + m_fFlyCloseDistance = 12.5f; + m_fFlyStopDistance = 0.0f; + m_fFlyAttackFireTime = 2.0f; + m_fFlyCloseFireTime = 0.1f; + m_fFlyIgnoreRange = 200.0f; + m_fFlyHeight = 1.0f; + m_iScore = 1000; + } break; + case RFC_FIGHTER: { + SetModel(MODEL_FIGHTER); + SetModelMainTexture(TEXTURE_FIGHTER); + // fly moving properties + m_fFlyWalkSpeed = FRnd()/2 + 1.0f; + m_aFlyWalkRotateSpeed = FRnd()*10.0f + 25.0f; + m_fFlyAttackRunSpeed = FRnd()*2.0f + 7.0f; + m_aFlyAttackRotateSpeed = FRnd()*25 + 150.0f; + m_fFlyCloseRunSpeed = FRnd()*2.0f + 20.0f; + m_aFlyCloseRotateSpeed = 150.0f;//FRnd()*50 + 0.0f; + // attack properties - CAN BE SET + m_fFlyAttackDistance = 50.0f; + m_fFlyCloseDistance = 10.0f; + m_fFlyStopDistance = 0.1f; + m_fFlyAttackFireTime = 3.0f; + m_fFlyCloseFireTime = 0.2f; + m_fFlyIgnoreRange = 200.0f; + m_fFlyHeight = 2.5f; + } break; + default: ASSERT(FALSE); + } + + // continue behavior in base class + jump CEnemyFly::MainLoop(); + }; +}; diff --git a/Sources/Entities/RollingStone.es b/Sources/Entities/RollingStone.es new file mode 100644 index 0000000..0775a1b --- /dev/null +++ b/Sources/Entities/RollingStone.es @@ -0,0 +1,341 @@ +604 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Debris"; + +class CRollingStone: CMovableModelEntity { +name "RollingStone"; +thumbnail "Thumbnails\\RollingStone.tbn"; +features "IsTargetable"; +properties: + 1 FLOAT m_fBounce "Bounce" 'B' = 0.5f, + 2 FLOAT m_fHealth "Health" 'H' = 400.0f, + 3 FLOAT m_fDamage "Damage" 'D' = 1000.0f, + 4 BOOL m_bFixedDamage "Fixed damage" 'F' = FALSE, + 5 FLOAT m_fStretch "Stretch" 'S' = 1.0f, + 6 FLOAT m_fDeceleration "Deceleration" = 0.9f, + 7 FLOAT m_fStartSpeed "Start Speed" 'Z' = 50.0f, + 8 ANGLE3D m_vStartDir "Start Direction" 'A' = ANGLE3D(0,0,0), + + // sound channels for bouncing sound + 20 CSoundObject m_soBounce0, + 21 CSoundObject m_soBounce1, + 22 CSoundObject m_soBounce2, + 23 CSoundObject m_soBounce3, + 24 CSoundObject m_soBounce4, + 30 INDEX m_iNextChannel = 0, // next channel to play sound on + 31 CSoundObject m_soRoll, + 32 BOOL m_bRollPlaying = FALSE, + + // internal vars + 40 FLOATquat3D m_qA = FLOATquat3D(0, 1, 0, 0), + 41 FLOATquat3D m_qALast = FLOATquat3D(0, 1, 0, 0), + 42 FLOAT m_fASpeed = 0.0f, + 43 FLOAT3D m_vR = FLOAT3D(0,0,1), + +components: + 1 model MODEL_ROLLINGSTONE "Models\\Ages\\Egypt\\Traps\\RollingStone\\RollingStone.mdl", + 2 model MODEL_STONESPHERE "Models\\Ages\\Egypt\\Traps\\RollingStone\\Stone.mdl", + 3 texture TEXTURE_ROLLINGSTONE "Models\\Ages\\Egypt\\Traps\\RollingStone\\Stone.tex", + 5 texture TEXTURE_DETAIL "Models\\Ages\\Egypt\\Traps\\RollingStone\\Detail.tex", +// ************** STONE PARTS ************** + 14 model MODEL_STONE "Models\\Effects\\Debris\\Stone\\Stone.mdl", + 15 texture TEXTURE_STONE "Models\\Effects\\Debris\\Stone\\Stone.tex", + 16 class CLASS_DEBRIS "Classes\\Debris.ecl", + 4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + 20 sound SOUND_BOUNCE "Sounds\\Misc\\RollingStone.wav", + 21 sound SOUND_ROLL "Sounds\\Misc\\RollingStoneEnvironment.wav", + +functions: + void Precache(void) + { + PrecacheClass(CLASS_DEBRIS); + PrecacheModel(MODEL_STONE); + PrecacheTexture(TEXTURE_STONE); + PrecacheSound(SOUND_BOUNCE); + PrecacheSound(SOUND_ROLL); + } + void PostMoving() { + CMovableModelEntity::PostMoving(); + + // if touching floor + if (en_penReference!=NULL) { + // adjust rotation and translation speeds + AdjustSpeeds(en_vReferencePlane); + //CPrintF("adjusting\n"); + } else { + //CPrintF("not adjusting\n"); + } +// m_fASpeed *= m_fDeceleration; + + m_qALast = m_qA; + + FLOATquat3D qRot; + qRot.FromAxisAngle(m_vR, m_fASpeed*_pTimer->TickQuantum*PI/180); + FLOATmatrix3D mRot; + qRot.ToMatrix(mRot); + m_qA = qRot*m_qA; + if (en_ulFlags&ENF_INRENDERING) { + m_qALast = m_qA; + } + } + + /* Adjust model mip factor if needed. */ + void AdjustMipFactor(FLOAT &fMipFactor) + { + fMipFactor = 0;// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + FLOATquat3D qA; + qA = Slerp(_pTimer->GetLerpFactor(), m_qALast, m_qA); + + FLOATmatrix3D mA; + qA.ToMatrix(mA); + ANGLE3D vA; + DecomposeRotationMatrixNoSnap(vA, mA); + + CAttachmentModelObject *amo = GetModelObject()->GetAttachmentModel(0); + amo->amo_plRelative.pl_OrientationAngle = vA; + } + + void AdjustSpeedOnOneAxis(FLOAT &fTraNow, FLOAT &aRotNow, BOOL bRolling) + { + // calculate new rotation and translation to make them synchronized + // NOTE: formulae used: + // momentum of the ball : I = 2*m*r^2/5 + // velocity and rotation syncronized: w*r = v + // sum of impulses is constant: w1/r*I+v1*m = w2/r*I+v2*m + // this yields: v2 = (2*r*w1+5*v1)/7 + FLOAT fR = 4.0f*m_fStretch; // size of original sphere model (4m) times stretch + + FLOAT fTraNew = (2*aRotNow*fR+5*fTraNow)/7; + FLOAT aRotNew = fTraNew/fR; + + fTraNow = fTraNew; + aRotNow = aRotNew; + } + + // adjust rotation and translation speeds + void AdjustSpeeds(const FLOAT3D &vPlane) + { + // if going too slow in translation and rotation + if (en_vCurrentTranslationAbsolute.Length()<1.0f && m_fASpeed<1.0f) { + // just stop + en_vCurrentTranslationAbsolute = FLOAT3D(0,0,0); + m_fASpeed = 0.0f; + RollSound(0.0f); + return; + } + + // decompose speed to components regarding the plane + FLOAT3D vTranslationNormal; + FLOAT3D vTranslationParallel; + GetParallelAndNormalComponents(en_vCurrentTranslationAbsolute, vPlane, vTranslationNormal, vTranslationParallel); + + // check if rolling + BOOL bRolling = vTranslationNormal.Length()<0.1f; + // if rolling + if (bRolling) { + // get rotation direction from speed, if possible + FLOAT fSpeedTra = vTranslationParallel.Length(); +/* if (fSpeedTra>0.01f) { + m_vR = (vTranslationParallel/fSpeedTra)*vPlane; + }*/ + RollSound(fSpeedTra); + } else { + RollSound(0); + } + + + // --- find original axes and values + + // what is caused by rotation + FLOAT3D vRotFromRot = m_vR; + FLOAT3D vTraFromRot = vPlane*vRotFromRot; + vTraFromRot.Normalize(); + + FLOAT fTraFromRot = 0; + FLOAT fRotFromRot = m_fASpeed*PI/180.0f; + + // what is caused by translation + FLOAT3D vTraFromTra = vTranslationParallel; + FLOAT fTraFromTra = vTraFromTra.Length(); + FLOAT3D vRotFromTra = FLOAT3D(1,0,0); + FLOAT fRotFromTra = 0; + if (fTraFromTra>0.001f) { + vTraFromTra/=fTraFromTra; + vRotFromTra = vTraFromTra*vPlane; + vRotFromTra.Normalize(); + } + + // if there is any rotation + if (Abs(fRotFromRot)>0.01f) { + // adjust on rotation axis + AdjustSpeedOnOneAxis(fTraFromRot, fRotFromRot, bRolling); + } + // if there is any translation + if (Abs(fTraFromTra)>0.01f) { + // adjust on translation axis + AdjustSpeedOnOneAxis(fTraFromTra, fRotFromTra, bRolling); + } + + // put the speeds back together + FLOATquat3D qTra; + qTra.FromAxisAngle(vRotFromTra, fRotFromTra); + FLOATquat3D qRot; + qRot.FromAxisAngle(vRotFromRot, fRotFromRot); + FLOATquat3D q = qRot*qTra; + FLOAT3D vSpeed = vTraFromTra*fTraFromTra + vTraFromRot*fTraFromRot; + + // set the new speeds + en_vCurrentTranslationAbsolute = vTranslationNormal+vSpeed; + q.ToAxisAngle(m_vR, m_fASpeed); + m_fASpeed *= 180/PI; + } + +/************************************************************ + * S O U N D S * + ************************************************************/ +void BounceSound(FLOAT fSpeed) { + FLOAT fHitStrength = fSpeed*fSpeed; + + FLOAT fVolume = fHitStrength/20.0f; + //CPrintF("bounce %g->%g\n", fHitStrength, fVolume); + fVolume = Clamp( fVolume, 0.0f, 2.0f); + //FLOAT fVolume = Clamp(fHitStrength*5E-3f, 0.0f, 2.0f); + FLOAT fPitch = Lerp(0.2f, 1.0f, Clamp(fHitStrength/100, 0.0f, 1.0f)); + if (fVolume<0.1f) { + return; + } + CSoundObject &so = (&m_soBounce0)[m_iNextChannel]; + m_iNextChannel = (m_iNextChannel+1)%5; + so.Set3DParameters(200.0f*m_fStretch, 100.0f*m_fStretch, fVolume, fPitch); + PlaySound(so, SOUND_BOUNCE, SOF_3D); +}; + +void RollSound(FLOAT fSpeed) +{ + FLOAT fHitStrength = fSpeed*fSpeed*m_fStretch*m_fStretch*m_fStretch; + + FLOAT fVolume = fHitStrength/20.0f; + fVolume = Clamp( fVolume, 0.0f, 1.0f); + FLOAT fPitch = Lerp(0.2f, 1.0f, Clamp(fHitStrength/100, 0.0f, 1.0f)); + if (fVolume<0.1f) { + if (m_bRollPlaying) { + m_soRoll.Stop(); + m_bRollPlaying = FALSE; + } + return; + } + m_soRoll.Set3DParameters(200.0f*m_fStretch, 100.0f*m_fStretch, fVolume, fPitch); + + if (!m_bRollPlaying) { + PlaySound(m_soRoll, SOUND_ROLL, SOF_3D|SOF_LOOP); + m_bRollPlaying = TRUE; + } +} + +procedures: + + Main() + { + // set appearance + InitAsModel(); + SetPhysicsFlags(EPF_ONBLOCK_BOUNCE|EPF_PUSHABLE|EPF_MOVABLE|EPF_TRANSLATEDBYGRAVITY); + SetCollisionFlags(ECF_MODEL); + SetModel(MODEL_ROLLINGSTONE); + SetModelMainTexture(TEXTURE_ROLLINGSTONE); + AddAttachmentToModel(this, *GetModelObject(), 0, MODEL_STONESPHERE, TEXTURE_ROLLINGSTONE, 0, 0, TEXTURE_DETAIL); + + GetModelObject()->StretchModel( FLOAT3D(m_fStretch, m_fStretch, m_fStretch)); + ModelChangeNotify(); + + en_fBounceDampNormal = m_fBounce; + en_fBounceDampParallel = m_fBounce; + en_fAcceleration = en_fDeceleration = m_fDeceleration; + en_fCollisionSpeedLimit = 45.0f; + en_fCollisionDamageFactor = 10.0f; + + SetPlacement(CPlacement3D(GetPlacement().pl_PositionVector, ANGLE3D(0,0,0))); + m_qA = FLOATquat3D(0, 1, 0, 0); + m_qALast= FLOATquat3D(0, 1, 0, 0); + + autowait(0.1f); + + SetHealth( m_fHealth); + AddToMovers(); + + wait() { + on (ETrigger) : { + FLOAT3D v; + AnglesToDirectionVector(m_vStartDir, v); + GiveImpulseTranslationAbsolute(v*m_fStartSpeed); + //CPrintF("triggered\n"); + resume; + } + on (ETouch eTouch) : + { + + //CPrintF("touched\n"); + + if( !m_bFixedDamage) + { + FLOAT fDamageFactor = en_vCurrentTranslationAbsolute.Length()/10.0f; + FLOAT fAppliedDamage = fDamageFactor*m_fDamage; + // inflict damage + InflictDirectDamage( eTouch.penOther, this, DMT_CANNONBALL, fAppliedDamage, + eTouch.penOther->GetPlacement().pl_PositionVector, eTouch.plCollision); + } + else + { + if(en_vCurrentTranslationAbsolute.Length() != 0.0f) + { + // inflict damage + InflictDirectDamage( eTouch.penOther, this, DMT_CANNONBALL, m_fDamage, + eTouch.penOther->GetPlacement().pl_PositionVector, eTouch.plCollision); + } + } + + // adjust rotation and translation speeds + AdjustSpeeds(eTouch.plCollision); + + // if touched a brush + if (eTouch.penOther->GetRenderType() & RT_BRUSH) + { + BounceSound(((FLOAT3D&)eTouch.plCollision) % en_vCurrentTranslationAbsolute); + // calculate speed along impact normal + FLOAT fImpactSpeed = en_vCurrentTranslationAbsolute% (-(FLOAT3D&)eTouch.plCollision); + + // if strong collision + if( fImpactSpeed > 1000) + { + // receive artificial impact damage + ReceiveDamage(eTouch.penOther, DMT_IMPACT, m_fHealth*2.0f, + FLOAT3D(0,0,0), FLOAT3D(0,0,0)); + } + } + resume; + } + on (EDeath) : { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + + Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(1.0f,2.0f,3.0f), FLOAT3D(0,0,0), 1.0f, 0.0f); + for(INDEX iDebris = 0; iDebris<12; iDebris++) { + Debris_Spawn(this, this, MODEL_STONE, TEXTURE_STONE, 0, 0, 0, IRnd()%4, 0.15f, + FLOAT3D(FRnd()*0.8f+0.1f, FRnd()*0.8f+0.1f, FRnd()*0.8f+0.1f)); + } + Destroy(); + stop; + } + } + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/Scorpman.es b/Sources/Entities/Scorpman.es new file mode 100644 index 0000000..1fdf196 --- /dev/null +++ b/Sources/Entities/Scorpman.es @@ -0,0 +1,638 @@ +306 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/SCORPMAN/scorpman.h" +#include "Models/Enemies/SCORPMAN/Gun.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Bullet"; +uses "Entities/Reminder"; + +enum ScorpmanType { + 0 SMT_SOLDIER "Soldier", + 1 SMT_GENERAL "General", + 2 SMT_MONSTER "Obsolete", +}; + + +%{ +#define GUN_X 0.375f +#define GUN_Y 0.6f +#define GUN_Z -1.85f +#define STRETCH_SOLDIER 2 +#define STRETCH_GENERAL 3 +#define STRETCH_MONSTER 4 +// info structure +static EntityInfo eiScorpman = { + EIBT_FLESH, 1000.0f, + 0, 1.6f*STRETCH_SOLDIER, 0, // source (eyes) + 0.0f, 1.0f*STRETCH_SOLDIER, 0.0f, // target (body) +}; + +static EntityInfo eiScorpmanGeneral = { + EIBT_FLESH, 1500.0f, + 0, 1.6f*STRETCH_GENERAL, 0, // source (eyes) + 0.0f, 1.0f*STRETCH_GENERAL, 0.0f, // target (body) +}; + +static EntityInfo eiScorpmanMonster = { + EIBT_FLESH, 2000.0f, + 0, 1.6f*STRETCH_MONSTER, 0, // source (eyes) + 0.0f, 1.0f*STRETCH_MONSTER, 0.0f, // target (body) +}; +#define LIGHT_ANIM_FIRE 3 +#define LIGHT_ANIM_NONE 5 +%} + + +class CScorpman : CEnemyBase { +name "Scorpman"; +thumbnail "Thumbnails\\Scorpman.tbn"; + +properties: + 1 enum ScorpmanType m_smtType "Type" 'Y' = SMT_SOLDIER, + 2 INDEX m_bFireBulletCount = 0, // fire bullet binary divider + 3 INDEX m_iSpawnEffect = 0, // counter for spawn effect every 'x' times + 4 FLOAT m_fFireTime = 0.0f, // time to fire bullets + 5 CAnimObject m_aoLightAnimation, // light animation object + 6 BOOL m_bSleeping "Sleeping" 'S' = FALSE, // set to make scorpman sleep initally + +{ + CEntity *penBullet; // bullet + CLightSource m_lsLightSource; +} + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_BULLET "Classes\\Bullet.ecl", + 5 model MODEL_SCORPMAN "Models\\Enemies\\Scorpman\\Scorpman.mdl", + 6 texture TEXTURE_SOLDIER "Models\\Enemies\\Scorpman\\Soldier.tex", + 7 texture TEXTURE_GENERAL "Models\\Enemies\\Scorpman\\General.tex", +// 8 texture TEXTURE_MONSTER "Models\\Enemies\\Scorpman\\Monster.tex", + 12 texture TEXTURE_SPECULAR "Models\\SpecularTextures\\Medium.tex", + 9 model MODEL_GUN "Models\\Enemies\\Scorpman\\Gun.mdl", + 10 model MODEL_FLARE "Models\\Enemies\\Scorpman\\Flare.mdl", + 11 texture TEXTURE_GUN "Models\\Enemies\\Scorpman\\Gun.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Scorpman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Scorpman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Scorpman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Scorpman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Scorpman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Scorpman\\Sounds\\Death.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + if (eDeath.eLastDamage.dmtType==DMT_CLOSERANGE) { + str.PrintF(TRANS("%s was stabbed by an Arachnoid"), (const char*)strPlayerName); + } else { + str.PrintF(TRANS("An Arachnoid poured lead into %s"), (const char*)strPlayerName); + } + return str; + } + void Precache(void) { + CEnemyBase::Precache(); + PrecacheModel(MODEL_FLARE); + PrecacheSound(SOUND_IDLE ); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_FIRE ); + PrecacheSound(SOUND_KICK ); + PrecacheSound(SOUND_DEATH); + }; + + /* Read from stream. */ + void Read_t( CTStream *istr) { // throw char * + CEnemyBase::Read_t(istr); + + // setup light source + SetupLightSource(); + } + + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + CEnemyBase::FillEntityStatistics(pes); + switch(m_smtType) { + case SMT_MONSTER: { pes->es_strName+=" Monster"; } break; + case SMT_GENERAL: { pes->es_strName+=" General"; } break; + case SMT_SOLDIER: { pes->es_strName+=" Soldier"; } break; + } + return TRUE; + } + + virtual const CTFileName &GetComputerMessageName(void) const { + //static DECLARE_CTFILENAME(fnmMonster, "Data\\Messages\\Enemies\\ScorpmanMonster.txt"); + static DECLARE_CTFILENAME(fnmGeneral, "Data\\Messages\\Enemies\\ScorpmanGeneral.txt"); + static DECLARE_CTFILENAME(fnmSoldier, "Data\\Messages\\Enemies\\ScorpmanSoldier.txt"); + switch(m_smtType) { + default: ASSERT(FALSE); + case SMT_MONSTER: //return fnmMonster; + case SMT_GENERAL: return fnmGeneral; + case SMT_SOLDIER: return fnmSoldier; + } + }; + + /* Get static light source information. */ + CLightSource *GetLightSource(void) { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + } + + BOOL ForcesCannonballToExplode(void) + { + if (m_smtType!=SMT_SOLDIER) { + return TRUE; + } + return CEnemyBase::ForcesCannonballToExplode(); + } + + // Setup light source + void SetupLightSource(void) { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_rHotSpot = 2.0f; + lsNew.ls_rFallOff = 8.0f; + lsNew.ls_colColor = RGBToColor(128, 128, 128); + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = &m_aoLightAnimation; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + } + // play light animation + void PlayLightAnim(INDEX iAnim, ULONG ulFlags) { + if (m_aoLightAnimation.GetData()!=NULL) { + m_aoLightAnimation.PlayAnim(iAnim, ulFlags); + } + }; + + // fire minigun on/off + void MinigunOn(void) + { + PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING); + CModelObject *pmoGun = &GetModelObject()->GetAttachmentModel(SCORPMAN_ATTACHMENT_MINIGUN)-> + amo_moModelObject; + pmoGun->PlayAnim(GUN_ANIM_FIRE, AOF_LOOPING); + AddAttachmentToModel(this, *pmoGun, GUN_ATTACHMENT_FLAME, MODEL_FLARE, TEXTURE_GUN, 0, 0, 0); + switch (m_smtType) { + case SMT_SOLDIER: pmoGun->StretchModel(FLOAT3D(2.0f, 2.0f, 2.0f)); break; + case SMT_GENERAL: pmoGun->StretchModel(FLOAT3D(3.0f, 3.0f, 3.0f)); break; + case SMT_MONSTER: pmoGun->StretchModel(FLOAT3D(4.0f, 4.0f, 4.0f)); break; + } + } + void MinigunOff(void) + { + PlayLightAnim(LIGHT_ANIM_NONE, 0); + CModelObject *pmoGun = &GetModelObject()->GetAttachmentModel(SCORPMAN_ATTACHMENT_MINIGUN)-> + amo_moModelObject; + pmoGun->PlayAnim(GUN_ANIM_IDLE, AOF_LOOPING); + pmoGun->RemoveAttachmentModel(GUN_ATTACHMENT_FLAME); + } + /* Entity info */ + void *GetEntityInfo(void) { + if (m_smtType == SMT_MONSTER) { + return &eiScorpmanMonster; + } else if (m_smtType == SMT_GENERAL) { + return &eiScorpmanGeneral; + } else { + return &eiScorpman; + } + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // scorpman can't harm scorpman + if (!IsOfClass(penInflictor, "Scorpman")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + switch (IRnd()%3) { + case 0: iAnim = SCORPMAN_ANIM_WOUND01; break; + case 1: iAnim = SCORPMAN_ANIM_WOUND02; break; + case 2: iAnim = SCORPMAN_ANIM_WOUND03; break; + default: ASSERTALWAYS("Scorpman unknown damage"); + } + StartModelAnim(iAnim, 0); + MinigunOff(); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + StartModelAnim(SCORPMAN_ANIM_DEATH, 0); + MinigunOff(); + return SCORPMAN_ANIM_DEATH; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(SCORPMAN_COLLISION_BOX_DEATH); + SetCollisionFlags(ECF_MODEL); + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(SCORPMAN_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART); + }; + void WalkingAnim(void) { + StartModelAnim(SCORPMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RunningAnim(void) { + StartModelAnim(SCORPMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + void RotatingAnim(void) { + StartModelAnim(SCORPMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +/************************************************************ + * FIRE BULLET / RAIL * + ************************************************************/ + BOOL CanFireAtPlayer(void) + { + // get ray source and target + FLOAT3D vSource, vTarget; + GetPositionCastRay(this, m_penEnemy, vSource, vTarget); + + // bullet start position + CPlacement3D plBullet; + plBullet.pl_OrientationAngle = ANGLE3D(0,0,0); + plBullet.pl_PositionVector = FLOAT3D(GUN_X, GUN_Y, 0); + // offset are changed according to stretch factor + if (m_smtType == SMT_MONSTER) { + plBullet.pl_PositionVector*=STRETCH_MONSTER; + } else if (m_smtType == SMT_GENERAL) { + plBullet.pl_PositionVector*=STRETCH_GENERAL; + } else { + plBullet.pl_PositionVector*=STRETCH_SOLDIER; + } + plBullet.RelativeToAbsolute(GetPlacement()); + vSource = plBullet.pl_PositionVector; + + // cast the ray + CCastRay crRay(this, vSource, vTarget); + crRay.cr_ttHitModels = CCastRay::TT_NONE; // check for brushes only + crRay.cr_bHitTranslucentPortals = FALSE; + en_pwoWorld->CastRay(crRay); + + // if hit nothing (no brush) the entity can be seen + return (crRay.cr_penHit==NULL); + } + + void PrepareBullet(FLOAT fDamage) { + // bullet start position + CPlacement3D plBullet; + plBullet.pl_OrientationAngle = ANGLE3D(0,0,0); + plBullet.pl_PositionVector = FLOAT3D(GUN_X, GUN_Y, 0); + // offset are changed according to stretch factor + if (m_smtType == SMT_MONSTER) { + plBullet.pl_PositionVector*=STRETCH_MONSTER; + } else if (m_smtType == SMT_GENERAL) { + plBullet.pl_PositionVector*=STRETCH_GENERAL; + } else { + plBullet.pl_PositionVector*=STRETCH_SOLDIER; + } + plBullet.RelativeToAbsolute(GetPlacement()); + // create bullet + penBullet = CreateEntity(plBullet, CLASS_BULLET); + // init bullet + EBulletInit eInit; + eInit.penOwner = this; + eInit.fDamage = fDamage; + penBullet->Initialize(eInit); + }; + + // fire bullet + void FireBullet(void) { + // binary divide counter + m_bFireBulletCount++; + if (m_bFireBulletCount>1) { m_bFireBulletCount = 0; } + if (m_bFireBulletCount==1) { return; } + // bullet + PrepareBullet(3.0f); + ((CBullet&)*penBullet).CalcTarget(m_penEnemy, 250); + ((CBullet&)*penBullet).CalcJitterTarget(10); + ((CBullet&)*penBullet).LaunchBullet( TRUE, TRUE, TRUE); + ((CBullet&)*penBullet).DestroyBullet(); + }; + + + // adjust sound and watcher parameters here if needed + void EnemyPostInit(void) + { + // set sound default parameters + m_soSound.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + }; + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + // shoot + Fire(EVoid) : CEnemyBase::Fire{ + if (!CanFireAtPlayer()) { + return EReturn(); + } + + // confused amount + switch (m_smtType) { + case SMT_MONSTER: + m_fDamageConfused = 200; + m_fFireTime = 8.0f; + break; + case SMT_GENERAL: + m_fDamageConfused = 100; + m_fFireTime = 4.0f; + break; + case SMT_SOLDIER: + m_fDamageConfused = 50; + m_fFireTime = 2.0f; + break; + } + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + m_fFireTime *= 0.5f; + } + // to fire + StartModelAnim(SCORPMAN_ANIM_STANDTOFIRE, 0); + m_fLockOnEnemyTime = GetModelObject()->GetAnimLength(SCORPMAN_ANIM_STANDTOFIRE) + 0.5f + FRnd()/3; + autocall CEnemyBase::LockOnEnemy() EReturn; + + // fire + m_iSpawnEffect = 0; // effect every 'x' frames + m_fFireTime += _pTimer->CurrentTick(); + m_bFireBulletCount = 0; + PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP); + MinigunOn(); + + while (m_fFireTime > _pTimer->CurrentTick()) { + m_fMoveFrequency = 0.1f; + wait(m_fMoveFrequency) { + on (EBegin) : { + // make fuss + AddToFuss(); + // fire bullet + FireBullet(); + m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; + // rotate to enemy + if (!IsInPlaneFrustum(m_penEnemy, CosFast(5.0f))) { + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = 4000.0f; + StartModelAnim(SCORPMAN_ANIM_WALK_AND_FIRE, AOF_LOOPING|AOF_NORESTART); + // stand in place + } else { + m_fMoveSpeed = 0.0f; + m_aRotateSpeed = 0.0f; + StartModelAnim(SCORPMAN_ANIM_FIRE_MINIGUN, AOF_LOOPING|AOF_NORESTART); + } + // adjust direction and speed + SetDesiredMovement(); + resume; + } + on (ETimer) : { stop; } + } + } + m_soSound.Stop(); + MinigunOff(); + // set next shoot time + m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/3.0f); + + // from fire + StartModelAnim(SCORPMAN_ANIM_FIRETOSTAND, 0); + autowait(GetModelObject()->GetAnimLength(SCORPMAN_ANIM_FIRETOSTAND)); + + MaybeSwitchToAnotherPlayer(); + + // shoot completed + return EReturn(); + }; + + // hit enemy + Hit(EVoid) : CEnemyBase::Hit { + // close attack + StartModelAnim(SCORPMAN_ANIM_SPIKEHIT, 0); + autowait(0.5f); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + if (CalcDist(m_penEnemy) < m_fCloseDistance) { + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + if (m_smtType == SMT_MONSTER) { + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 80.0f, FLOAT3D(0, 0, 0), vDirection); + } else if (m_smtType == SMT_GENERAL) { + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 40.0f, FLOAT3D(0, 0, 0), vDirection); + } else { + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 20.0f, FLOAT3D(0, 0, 0), vDirection); + } + } + autowait(0.3f); + MaybeSwitchToAnotherPlayer(); + return EReturn(); + }; + + Sleep(EVoid) + { + // start sleeping anim + StartModelAnim(SCORPMAN_ANIM_SLEEP, AOF_LOOPING); + // repeat + wait() { + // if triggered + on(ETrigger eTrigger) : { + // remember enemy + SetTargetSoft(eTrigger.penCaused); + // wake up + jump WakeUp(); + } + // if damaged + on(EDamage eDamage) : { + // wake up + jump WakeUp(); + } + otherwise() : { + resume; + } + } + } + + WakeUp(EVoid) + { + // wakeup anim + SightSound(); + StartModelAnim(SCORPMAN_ANIM_WAKEUP, 0); + autowait(GetModelObject()->GetCurrentAnimLength()); + + // trigger your target + SendToTarget(m_penDeathTarget, m_eetDeathType); + // proceed with normal functioning + return EReturn(); + } + + // overridable called before main enemy loop actually begins + PreMainLoop(EVoid) : CEnemyBase::PreMainLoop + { + // if sleeping + if (m_bSleeping) { + m_bSleeping = FALSE; + // go to sleep until waken up + wait() { + on (EBegin) : { + call Sleep(); + } + on (EReturn) : { + stop; + }; + // if dead + on(EDeath eDeath) : { + // die + jump CEnemyBase::Die(eDeath); + } + } + } + return EReturn(); + } + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + if (m_smtType==SMT_MONSTER) { + m_smtType=SMT_GENERAL; + } + + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + en_tmMaxHoldBreath = 25.0f; + en_fDensity = 3000.0f; + + // set your appearance + SetModel(MODEL_SCORPMAN); + switch (m_smtType) { + case SMT_SOLDIER: + // set your texture + SetModelMainTexture(TEXTURE_SOLDIER); + SetModelSpecularTexture(TEXTURE_SPECULAR); + SetHealth(300.0f); + m_fMaxHealth = 300.0f; + // damage/explode properties + m_fDamageWounded = 200.0f; + m_fBlowUpAmount = 1E10f; + m_fBodyParts = 30; + // setup attack distances + m_fAttackDistance = 150.0f; + m_fCloseDistance = 5.0f; + m_fStopDistance = 4.5f; + m_fAttackFireTime = 0.5f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 300.0f; + m_iScore = 1000; + break; + + case SMT_GENERAL: + // set your texture + SetModelMainTexture(TEXTURE_GENERAL); + SetModelSpecularTexture(TEXTURE_SPECULAR); + SetHealth(600.0f); + m_fMaxHealth = 600.0f; + // damage/explode properties + m_fDamageWounded = 400.0f; + m_fBlowUpAmount = 1E10f; + m_fBodyParts = 30; + // setup attack distances + m_fAttackDistance = 150.0f; + m_fCloseDistance = 5.0f; + m_fStopDistance = 4.5f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 300.0f; + m_iScore = 5000; + break; + + case SMT_MONSTER: + // set your texture + SetModelMainTexture(TEXTURE_GENERAL); + SetModelSpecularTexture(TEXTURE_SPECULAR); + SetHealth(1200.0f); + m_fMaxHealth = 1200.0f; + // damage/explode properties + m_fDamageWounded = 800.0f; + m_fBlowUpAmount = 1E10f; + m_fBodyParts = 60; + // setup attack distances + m_fAttackDistance = 250.0f; + m_fCloseDistance = 11.0f; + m_fStopDistance = 9.0f; + m_fAttackFireTime = 2.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 500.0f; + m_iScore = 10000; + break; + } + + AddAttachment(SCORPMAN_ATTACHMENT_MINIGUN, MODEL_GUN, TEXTURE_GUN); + + // set stretch factors for height and width - MUST BE DONE BEFORE SETTING MODEL! + switch (m_smtType) { + case SMT_SOLDIER: GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)*STRETCH_SOLDIER); break; + case SMT_GENERAL: GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)*STRETCH_GENERAL); break; + case SMT_MONSTER: GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)*STRETCH_MONSTER); break; + } + + ModelChangeNotify(); + + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*20.0f + 550.0f); + m_fAttackRunSpeed = FRnd()*1.5f + 4.5f; + m_aAttackRotateSpeed = AngleDeg(FRnd()*50.0f + 275.0f); + m_fCloseRunSpeed = FRnd()*1.5f + 4.5f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50.0f + 275.0f); + + // set stretch factors for height and width + CEnemyBase::StretchModel(); + // setup light source + SetupLightSource(); + // set light animation if available + try { + m_aoLightAnimation.SetData_t(CTFILENAME("Animations\\BasicEffects.ani")); + } catch (char *strError) { + WarningMessage(TRANS("Cannot load Animations\\BasicEffects.ani: %s"), strError); + } + MinigunOff(); + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + + }; +}; diff --git a/Sources/Entities/Ship.es b/Sources/Entities/Ship.es new file mode 100644 index 0000000..ae87dbf --- /dev/null +++ b/Sources/Entities/Ship.es @@ -0,0 +1,337 @@ +103 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ShipMarker"; + +event EHarbor { +}; + +%{ + +// adjust angular velocity +ANGLE AdjustRotationSpeed(ANGLE aDiference, ANGLE aMaxSpeed) +{ + aDiference = NormalizeAngle(aDiference); + aDiference = Clamp(aDiference, -aMaxSpeed, +aMaxSpeed); + return aDiference; +} + +%} + +class CShip : CMovableBrushEntity { +name "Ship"; +thumbnail "Thumbnails\\Ship.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Ship", + 2 CTString m_strDescription = "", + + 3 CEntityPointer m_penTarget "Target" 'T', + 4 FLOAT m_fSpeed "Speed [m/s]" 'S' = 10.0f, + 5 FLOAT m_fRotation "Rotation [deg/s]" 'R' = 30.0f, + 6 FLOAT m_fRockingV "Rocking V" 'V' = 10.0f, + 7 FLOAT m_fRockingA "Rocking A" 'A' = 10.0f, + 8 FLOAT m_fAcceleration "Acceleration" 'C' = 10.0f, + + 10 BOOL m_bMoving = TRUE, + 11 FLOAT m_fRockSign = 1.0f, + 12 FLOAT m_fLastTargetDistance = UpperLimit(0.0f), + + 20 CEntityPointer m_penSail "Sail" 'L', + 21 ANIMATION m_iSailUpAnim "Sail roll-up anim"=0, + 22 ANIMATION m_iSailDownAnim "Sail roll-down anim"=0, + 23 ANIMATION m_iSailSailAnim "Sail sailing anim"=0, + 24 ANIMATION m_iSailWaveingAnim "Sail wawing anim"=0, + + 30 FLOAT m_fOriginalRockingV = 0.0f, + 31 FLOAT m_fOriginalRockingA = 0.0f, + 32 FLOAT m_fNextRockingV = 0.0f, + 33 FLOAT m_fNextRockingA = 0.0f, + 34 FLOAT m_tmRockingChange=1, // how many second to change rocking parameters + 35 FLOAT m_tmRockingChangeStart=-1, // when changing of rocking parameters has started +components: +functions: + /* Check if entity is moved on a route set up by its targets. */ + BOOL MovesByTargetedRoute(CTString &strTargetProperty) const { + strTargetProperty = "Target"; + return TRUE; + }; + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\ShipMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s", (const char*)m_penTarget->GetName()); + } + return m_strDescription; + } + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + if((slPropertyOffset==offsetof(CShip, m_iSailUpAnim) + ||slPropertyOffset==offsetof(CShip, m_iSailDownAnim) + ||slPropertyOffset==offsetof(CShip, m_iSailSailAnim) + ||slPropertyOffset==offsetof(CShip, m_iSailWaveingAnim)) + &&m_penSail!=NULL) { + return m_penSail->GetModelObject()->GetData(); + } else { + return CEntity::GetAnimData(slPropertyOffset); + } + }; + + // calculate velocities towards marker + void SetMovingSpeeds(void) + { + // if the brush should not be moving, or there is no target + if (!m_bMoving || m_penTarget==NULL) { + // just rock + SetDesiredRotation(ANGLE3D(0,0,GetRockingSpeed())); + return; + } + + CShipMarker *penTarget = (CShipMarker *)(CEntity*)m_penTarget; + const CPlacement3D &plThis = GetPlacement(); + + // get direction to target + const FLOAT3D &vTarget = penTarget->GetPlacement().pl_PositionVector; + const FLOAT3D &vNow = plThis.pl_PositionVector; + FLOAT3D vDirection = vTarget-vNow; + FLOAT fTargetDistance = vDirection.Length(); + // if got close enough + if (fTargetDistanceTickQuantum) { + // switch to next marker + NextMarker(); + return; + } + + vDirection/=fTargetDistance; + ANGLE3D aAngle; + DirectionVectorToAngles(vDirection, aAngle); + aAngle-=plThis.pl_OrientationAngle; + aAngle(1) = AdjustRotationSpeed(aAngle(1), m_fRotation); + aAngle(2) = 0; + aAngle(3) = GetRockingSpeed(); + + SetDesiredRotation(aAngle); + + // set speed + SetDesiredTranslation(FLOAT3D(0,0,-m_fSpeed)); + + en_fAcceleration = m_fAcceleration; + en_fDeceleration = m_fAcceleration; + } + + // calculate rocking velocity + ANGLE GetRockingSpeed(void) + { + // if rocking changing time has not passed + TIME tmSinceChangeStarted = _pTimer->CurrentTick()-m_tmRockingChangeStart; + if (tmSinceChangeStarted0) { + m_fRockSign = -m_fRockSign; + }; + + if (aRotation<2) { + aRotation = 2; + } + aRotation *=m_fRockSign; + + return aRotation; + } + + // switch to next marker + void NextMarker(void) + { + // get next marker + CShipMarker *penTarget = (CShipMarker *)(CEntity*)m_penTarget; + CShipMarker *penNextTarget = (CShipMarker *)(CEntity*)penTarget->m_penTarget; + + // if this marker is harbor + if (penTarget->m_bHarbor) { + // stop + StopSailing(); + // start being in harbor + SendEvent(EHarbor()); + } + + // if got to end + if (penNextTarget==NULL) { + // stop + StopSailing(); + return; + } + + // get properties from marker + FLOAT fSpeed = penTarget->m_fSpeed; + if (fSpeed>=0) { + m_fSpeed = fSpeed; + } + FLOAT fRotation = penTarget->m_fRotation; + if (fRotation>=0) { + m_fRotation = fRotation; + } + FLOAT fAcceleration = penTarget->m_fAcceleration; + if (fAcceleration>=0) { + m_fAcceleration = fAcceleration; + } + + m_fOriginalRockingV = m_fRockingV; + m_fOriginalRockingA = m_fRockingA; + + FLOAT fRockingV = penTarget->m_fRockingV; + if (fRockingV>=0) { + m_fNextRockingV = fRockingV; + } else { + m_fNextRockingV = m_fRockingV; + } + FLOAT fRockingA = penTarget->m_fRockingA; + if (fRockingA>=0) { + m_fNextRockingA = fRockingA; + } else { + m_fNextRockingA = m_fRockingA; + } + m_tmRockingChange = penTarget->m_tmRockingChange; + m_tmRockingChangeStart = _pTimer->CurrentTick(); + + // remember next marker as current target + m_penTarget = penNextTarget; + SetMovingSpeeds(); + } + + void StartSailing() + { + m_bMoving = TRUE; + // calculate velocities towards marker + SetMovingSpeeds(); + } + + void StopSailing(void) + { + m_bMoving = FALSE; + SetDesiredRotation(ANGLE3D(0,0,GetDesiredRotation()(3))); + SetDesiredTranslation(FLOAT3D(0,0,0)); + } + + // do moving + void PreMoving(void) { + // calculate velocities towards marker + SetMovingSpeeds(); + CMovableBrushEntity::PreMoving(); + }; + +procedures: + Sail() { + // roll the sail down + m_penSail->GetModelObject()->PlayAnim(m_iSailDownAnim, 0); + autowait(m_penSail->GetModelObject()->GetAnimLength(m_iSailDownAnim)); + // start sail waveing + m_penSail->GetModelObject()->PlayAnim(m_iSailWaveingAnim, AOF_LOOPING); + + // wait until touched by a player or started + wait() { + on (EBegin) : { resume; } + on (ETouch eTouch) : { + if (IsDerivedFromClass(eTouch.penOther, "PlayerEntity")) { + stop; + } + } + on (EStart) : { + stop; + } + } + + // blow the sail up + m_penSail->GetModelObject()->PlayAnim(m_iSailSailAnim, 0); + + // start moving + StartSailing(); + // sail until we come to harbor + wait() { + on (EBegin) : { resume; } + on (EHarbor) : { stop; } + } + + // stay in harbor + jump Harbor(); + } + Harbor() { + // roll the sail up + m_penSail->GetModelObject()->PlayAnim(m_iSailUpAnim, 0); + + // stay in harbor until we are triggered + wait() { + on (EBegin) : { resume; } + on (ETrigger) : { stop; } + } + // start sailing + jump Sail(); + } + + + Main() { + // declare yourself as a brush + InitAsBrush(); + SetPhysicsFlags(EPF_BRUSH_MOVING&~(EPF_ABSOLUTETRANSLATE|EPF_NOACCELERATION)); + SetCollisionFlags(ECF_BRUSH); + + // stop moving brush + ForceFullStop(); + + // assure valid target + if (m_penTarget!=NULL && !IsOfClass(m_penTarget, "Ship Marker")) { + WarningMessage("Target '%s' is not of ShipMarker class!", (const char*)m_penTarget->GetName()); + m_penTarget = NULL; + } + // assure valid sail + if (m_penSail!=NULL && m_penSail->GetRenderType()!=RT_MODEL) { + WarningMessage("Sail '%s' is not a model!", (const char*)m_penSail->GetName()); + m_penSail = NULL; + } + + // wait until game starts + autowait(0.1f); + + // if sail is not valid + if (m_penSail==NULL) { + // don't continue + WarningMessage("Ship will not work without a valid sail!"); + return; + } + + // forever + wait() { + // on the beginning + on (EBegin) : { + // start sailing + call Sail(); + } + + // move is obstructed + on (EBlock eBlock) : { + // inflict damage to entity that block brush + InflictDirectDamage(eBlock.penOther, this, DMT_BRUSH, 10.0f, + FLOAT3D(0.0f,0.0f,0.0f), (FLOAT3D &)eBlock.plCollision); + resume; + } + } + } +}; diff --git a/Sources/Entities/ShipMarker.es b/Sources/Entities/ShipMarker.es new file mode 100644 index 0000000..d89dda6 --- /dev/null +++ b/Sources/Entities/ShipMarker.es @@ -0,0 +1,46 @@ +104 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +class CShipMarker: CMarker { +name "Ship Marker"; +thumbnail "Thumbnails\\ShipMarker.tbn"; + +properties: + 1 BOOL m_bHarbor "Harbor" 'H' = FALSE, + 2 FLOAT m_fSpeed "Speed [m/s]" 'S' = -1.0f, + 3 FLOAT m_fRotation "Rotation [deg/s]" 'R' = -1.0f, + 4 FLOAT m_fAcceleration "Acceleration" 'C' = 10.0f, + 5 FLOAT m_fRockingV "Rocking V" 'V' = -1.0f, + 6 FLOAT m_fRockingA "Rocking A" 'A' = -1.0f, + 7 FLOAT m_tmRockingChange "Rocking Change Time" = 3.0f, + +components: + 1 model MODEL_MARKER "Models\\Editor\\ShipMarker.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\ShipMarker.tex" + +functions: + /* Check if entity can drop marker for making linked route. */ + BOOL DropsMarker(CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { + fnmMarkerClass = CTFILENAME("Classes\\ShipMarker.ecl"); + strTargetProperty = "Target"; + return TRUE; + } +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + return; + } +}; + diff --git a/Sources/Entities/SoundHolder.es b/Sources/Entities/SoundHolder.es new file mode 100644 index 0000000..210c05f --- /dev/null +++ b/Sources/Entities/SoundHolder.es @@ -0,0 +1,136 @@ +/* + * Sound Holder. + */ +204 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelDestruction"; + +class CSoundHolder : CRationalEntity { +name "SoundHolder"; +thumbnail "Thumbnails\\SoundHolder.tbn"; +features "HasName", "HasDescription", "IsTargetable"; + + +properties: + + 1 CTFileName m_fnSound "Sound" 'S' = CTFILENAME("Sounds\\Default.wav"), // sound + 2 RANGE m_rFallOffRange "Fall-off" 'F' = 100.0f, + 3 RANGE m_rHotSpotRange "Hot-spot" 'H' = 50.0f, + 4 FLOAT m_fVolume "Volume" 'V' = 1.0f, + 6 BOOL m_bLoop "Looping" 'L' = TRUE, + 7 BOOL m_bSurround "Surround" 'R' = FALSE, + 8 BOOL m_bVolumetric "Volumetric" 'O' = TRUE, + 9 CTString m_strName "Name" 'N' = "", + 10 CTString m_strDescription = "", + 11 BOOL m_bAutoStart "Auto start" 'A' = FALSE, // auto start (environment sounds) + 12 INDEX m_iPlayType = 0, + 13 CSoundObject m_soSound, // sound channel + 14 BOOL m_bDestroyable "Destroyable" 'Q' = FALSE, + + { + CAutoPrecacheSound m_aps; + } + + +components: + + 1 model MODEL_MARKER "Models\\Editor\\SoundHolder.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\SoundHolder.tex" + + +functions: + + void Precache(void) + { + m_aps.Precache(m_fnSound); + } + + // apply mirror and stretch to the entity + void MirrorAndStretch(FLOAT fStretch, BOOL bMirrorX) + { + // stretch its ranges + m_rFallOffRange*=fStretch; + m_rHotSpotRange*=fStretch; + //(void)bMirrorX; // no mirror for sounds + } + + +procedures: + + Main(EVoid) + { + // validate range + if (m_rHotSpotRange<0.0f) { m_rHotSpotRange = 0.0f; } + if (m_rFallOffRangeFLOAT(SL_VOLUME_MAX)) { m_fVolume = FLOAT(SL_VOLUME_MAX); } + + // determine play type + m_iPlayType = SOF_3D; + if (m_bLoop) { m_iPlayType |= SOF_LOOP; } + if (m_bSurround) { m_iPlayType |= SOF_SURROUND; } + if (m_bVolumetric) { m_iPlayType |= SOF_VOLUMETRIC; } + + // init as model + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set stretch factors - MUST BE DONE BEFORE SETTING MODEL! + const float SOUND_MINSIZE=1.0f; + FLOAT fFactor = Log2(m_rFallOffRange)*SOUND_MINSIZE; + if (fFactormo_Stretch = FLOAT3D( fFactor, fFactor, fFactor); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + m_strDescription.PrintF("%s", (const char*)m_fnSound.FileName()); + + // wait for a while to play sound -> Sound Can Be Spawned + autowait(0.5f); + + wait() { + // auto play sound + on (EBegin) : { + if (m_bAutoStart) { + m_soSound.Set3DParameters(FLOAT(m_rFallOffRange), FLOAT(m_rHotSpotRange), m_fVolume, 1.0f); + PlaySound(m_soSound, m_fnSound, m_iPlayType); + } + resume; + } + // play sound + on (EStart) : { + m_soSound.Set3DParameters(FLOAT(m_rFallOffRange), FLOAT(m_rHotSpotRange), m_fVolume, 1.0f); + PlaySound(m_soSound, m_fnSound, m_iPlayType); + resume; + } + // stop playing sound + on (EStop) : { + m_soSound.Stop(); + resume; + } + // when someone in range is destroyed + on (ERangeModelDestruction) : { + // if range destruction is enabled + if (m_bDestroyable) { + // stop playing + m_soSound.Stop(); + } + return TRUE; + } + on (EEnd) : { stop; } + } + + // cease to exist + Destroy(); + return; + } +}; diff --git a/Sources/Entities/StdH/StdH.cpp b/Sources/Entities/StdH/StdH.cpp new file mode 100644 index 0000000..dfa134e --- /dev/null +++ b/Sources/Entities/StdH/StdH.cpp @@ -0,0 +1,17 @@ +/* Copyright (c) 2002-2012 Croteam Ltd. +This program is free software; you can redistribute it and/or modify +it under the terms of version 2 of the GNU General Public License as published by +the Free Software Foundation + + +This program 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 this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "StdH.h" + diff --git a/Sources/Entities/StdH/StdH.h b/Sources/Entities/StdH/StdH.h new file mode 100644 index 0000000..bfdea61 --- /dev/null +++ b/Sources/Entities/StdH/StdH.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2002-2012 Croteam Ltd. +This program is free software; you can redistribute it and/or modify +it under the terms of version 2 of the GNU General Public License as published by +the Free Software Foundation + + +This program 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 this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include +#include +#include + +/* rcg10042001 protect against Visual C-isms. */ +#ifdef _MSC_VER +#define DECL_DLL _declspec(dllexport) +#endif + +#ifdef PLATFORM_UNIX +#define DECL_DLL +#endif + +#include "../Global.h" +#include "../Common/Flags.h" +#include "../Common/Common.h" +#include "../Common/Particles.h" +#include "../Common/PathFinding.h" +#include "../Common/GameInterface.h" +#include "../Common/HUD.h" + diff --git a/Sources/Entities/StormController.es b/Sources/Entities/StormController.es new file mode 100644 index 0000000..59c8e8e --- /dev/null +++ b/Sources/Entities/StormController.es @@ -0,0 +1,239 @@ +606 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/BackgroundViewer.h" +#include "Entities/WorldSettingsController.h" +#include "Entities/Lightning.h" +%} + +class CStormController: CRationalEntity { +name "Storm controller"; +thumbnail "Thumbnails\\StormController.tbn"; +features "IsTargetable", "HasName", "IsImportant"; + +properties: + 1 CEntityPointer m_penwsc, // ptr to world settings controller + 2 CTString m_strName "Name" 'N' = "Storm controller", // class name + 3 FLOAT m_fNextLightningDelay = 0.0f, + 4 BOOL m_bStormOn = FALSE, + 5 FLOAT m_fNextLightningStrike = 0.0f, + 10 CEntityPointer m_penLightning00 "Lightning 1" 'T' COLOR(C_MAGENTA|0xFF), // lightning + 11 CEntityPointer m_penLightning01 "Lightning 2" 'Y' COLOR(C_MAGENTA|0xFF), // lightning + 12 CEntityPointer m_penLightning02 "Lightning 3" 'U' COLOR(C_MAGENTA|0xFF), // lightning + 13 CEntityPointer m_penLightning03 "Lightning 4" 'I' COLOR(C_MAGENTA|0xFF), // lightning + 14 CEntityPointer m_penLightning04 "Lightning 5" 'O' COLOR(C_MAGENTA|0xFF), // lightning + 15 CEntityPointer m_penLightning05 "Lightning 6" 'P' COLOR(C_MAGENTA|0xFF), // lightning + 16 CEntityPointer m_penLightning06 "Lightning 7" COLOR(C_MAGENTA|0xFF), // lightning + 17 CEntityPointer m_penLightning07 "Lightning 8" COLOR(C_MAGENTA|0xFF), // lightning + 18 CEntityPointer m_penLightning08 "Lightning 9" COLOR(C_MAGENTA|0xFF), // lightning + 19 CEntityPointer m_penLightning09 "Lightning 10" COLOR(C_MAGENTA|0xFF), // lightning + 20 CEntityPointer m_penLightning10 "Lightning 11" COLOR(C_MAGENTA|0xFF), // lightning + 21 CEntityPointer m_penLightning11 "Lightning 12" COLOR(C_MAGENTA|0xFF), // lightning + 22 CEntityPointer m_penLightning12 "Lightning 13" COLOR(C_MAGENTA|0xFF), // lightning + 23 CEntityPointer m_penLightning13 "Lightning 14" COLOR(C_MAGENTA|0xFF), // lightning + 24 CEntityPointer m_penLightning14 "Lightning 15" COLOR(C_MAGENTA|0xFF), // lightning + 25 CEntityPointer m_penLightning15 "Lightning 16" COLOR(C_MAGENTA|0xFF), // lightning + 26 CEntityPointer m_penLightning16 "Lightning 17" COLOR(C_MAGENTA|0xFF), // lightning + 27 CEntityPointer m_penLightning17 "Lightning 18" COLOR(C_MAGENTA|0xFF), // lightning + 28 CEntityPointer m_penLightning18 "Lightning 19" COLOR(C_MAGENTA|0xFF), // lightning + 29 CEntityPointer m_penLightning19 "Lightning 20" COLOR(C_MAGENTA|0xFF), // lightning + +components: + 1 model MODEL_STORM_CONTROLLER "Models\\Editor\\StormController.mdl", + 2 texture TEXTURE_STORM_CONTROLLER "Models\\Editor\\StormController.tex" + +functions: + // check if one lightning target is valid + void CheckOneLightningTarget(CEntityPointer &pen) + { + if (pen!=NULL && !IsOfClass(pen, "Lightning")) + { + WarningMessage("Target '%s' is not of class Lightning!", (const char*)pen->GetName()); + pen=NULL; + } + } + + // get number of lightnings set by user + INDEX GetLightningsCount(void) const + { + // note: only first N that are no NULL are used + if (m_penLightning00==NULL) { return 0; }; + if (m_penLightning01==NULL) { return 1; }; + if (m_penLightning02==NULL) { return 2; }; + if (m_penLightning03==NULL) { return 3; }; + if (m_penLightning04==NULL) { return 4; }; + if (m_penLightning05==NULL) { return 5; }; + if (m_penLightning06==NULL) { return 6; }; + if (m_penLightning07==NULL) { return 7; }; + if (m_penLightning08==NULL) { return 8; }; + if (m_penLightning09==NULL) { return 9; }; + if (m_penLightning10==NULL) { return 10; }; + if (m_penLightning11==NULL) { return 11; }; + if (m_penLightning12==NULL) { return 12; }; + if (m_penLightning13==NULL) { return 13; }; + if (m_penLightning14==NULL) { return 14; }; + if (m_penLightning15==NULL) { return 15; }; + if (m_penLightning16==NULL) { return 16; }; + if (m_penLightning17==NULL) { return 17; }; + if (m_penLightning18==NULL) { return 18; }; + return 20; + } + +procedures: + Storm() + { + // wait before first lightning + autowait( 10.0f); + jump StormInternal(); + } + + StormInternal() + { + m_fNextLightningDelay = 5.0f; + + while( m_bStormOn && _pTimer->CurrentTick() < ((CWorldSettingsController *)&*m_penwsc)->m_tmStormEnd) + { + m_fNextLightningStrike = _pTimer->CurrentTick() + 1.0f + FRnd()*3.0f + m_fNextLightningDelay; + while( _pTimer->CurrentTick()CurrentTick()<((CWorldSettingsController *)&*m_penwsc)->m_tmStormEnd && + m_bStormOn) + { + // wait until next lightning + wait(_pTimer->TickQuantum) + { + on (EBegin) : + { + resume; + } + on (EDeactivate) : + { + m_fNextLightningStrike+=1.0f; + resume; + } + on (ETimer) : { stop; } + } + } + // decrease lightning delay + m_fNextLightningDelay = ClampDn(m_fNextLightningDelay-0.75f, 1.0f); + // choose random lightning + INDEX ctLightnings = GetLightningsCount(); + // if there are some lightnings + if (ctLightnings!=0) + { + // choose by random + CLightning *penLightning = (CLightning *) &*(&m_penLightning00)[IRnd()%ctLightnings]; + SendToTarget(penLightning, EET_TRIGGER); + } + } + return EReturn(); + } + + Main(EVoid) + { + // check lightning targets + CheckOneLightningTarget( m_penLightning00); + CheckOneLightningTarget( m_penLightning01); + CheckOneLightningTarget( m_penLightning02); + CheckOneLightningTarget( m_penLightning03); + CheckOneLightningTarget( m_penLightning04); + CheckOneLightningTarget( m_penLightning05); + CheckOneLightningTarget( m_penLightning06); + CheckOneLightningTarget( m_penLightning07); + CheckOneLightningTarget( m_penLightning08); + CheckOneLightningTarget( m_penLightning09); + CheckOneLightningTarget( m_penLightning10); + CheckOneLightningTarget( m_penLightning11); + CheckOneLightningTarget( m_penLightning12); + CheckOneLightningTarget( m_penLightning13); + CheckOneLightningTarget( m_penLightning14); + CheckOneLightningTarget( m_penLightning15); + CheckOneLightningTarget( m_penLightning16); + CheckOneLightningTarget( m_penLightning17); + CheckOneLightningTarget( m_penLightning18); + CheckOneLightningTarget( m_penLightning19); + + // set appearance + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_STORM_CONTROLLER); + SetModelMainTexture(TEXTURE_STORM_CONTROLLER); + + // spawn in world editor + autowait(0.1f); + + // obtain bcg viewer entity + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); + if( penBcgViewer == NULL) + { + // don't do anything + return; + } + + // obtain world settings controller + m_penwsc = penBcgViewer->m_penWorldSettingsController; + if( m_penwsc == NULL) + { + // don't do anything + return; + } + + // must be world settings controller entity + if (!IsOfClass(m_penwsc, "WorldSettingsController")) + { + // don't do anything + return; + } + + m_bStormOn = FALSE; + while (TRUE) + { + wait() + { + on (EEnvironmentStart eEnvironmentStart) : + { + TIME tmNow = _pTimer->CurrentTick(); + ((CWorldSettingsController *)&*m_penwsc)->m_tmStormStart = tmNow-10.0f; + // force storm end in far future + ((CWorldSettingsController *)&*m_penwsc)->m_tmStormEnd = 1e6; + // set delay between lightnings + m_bStormOn = TRUE; + call StormInternal(); + resume; + } + on (EStart eStart) : + { + if( !m_bStormOn) + { + TIME tmNow = _pTimer->CurrentTick(); + // remember current time as storm start time in world settings controller + ((CWorldSettingsController *)&*m_penwsc)->m_tmStormStart = tmNow; + // force storm end in far future + ((CWorldSettingsController *)&*m_penwsc)->m_tmStormEnd = 1e6; + // set delay between lightnings + m_bStormOn = TRUE; + call Storm(); + } + resume; + } + on (EStop eStop) : + { + if( m_bStormOn) + { + TIME tmNow = _pTimer->CurrentTick(); + m_bStormOn = FALSE; + // remember current time as storm end time in world settings controller + ((CWorldSettingsController *)&*m_penwsc)->m_tmStormEnd = tmNow; + } + resume; + } + otherwise() : + { + resume; + }; + }; + } + } +}; diff --git a/Sources/Entities/Switch.es b/Sources/Entities/Switch.es new file mode 100644 index 0000000..f756f46 --- /dev/null +++ b/Sources/Entities/Switch.es @@ -0,0 +1,193 @@ +209 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/ModelHolder2"; + +enum SwitchType { + 0 SWT_ONCE "Once", + 1 SWT_ONOFF "On/Off", +}; + +class CSwitch: CModelHolder2 { +name "Switch"; +thumbnail "Thumbnails\\Switch.tbn"; +features "HasName", "HasTarget", "IsTargetable"; + +properties: + 4 ANIMATION m_iModelONAnimation "Model ON animation" 'D' = 0, + 5 ANIMATION m_iTextureONAnimation "Texture ON animation" = 0, + 6 ANIMATION m_iModelOFFAnimation "Model OFF animation" 'G' = 0, + 7 ANIMATION m_iTextureOFFAnimation "Texture OFF animation" = 0, + + 10 CEntityPointer m_penTarget "ON-OFF Target" 'T' COLOR(C_dBLUE|0xFF), // send event to entity + 11 enum EventEType m_eetEvent "ON Event type" 'U' = EET_START, // type of event to send + 12 enum EventEType m_eetOffEvent "OFF Event type" 'I' = EET_IGNORE, // type of event to send + + 18 enum SwitchType m_swtType "Type" 'Y' = SWT_ONOFF, + 19 CTString m_strMessage "Message" 'M' = "", + + // internal -> do not use + 20 BOOL m_bSwitchON = FALSE, + 21 CEntityPointer m_penCaused, // who triggered it last time + 22 BOOL m_bUseable = FALSE, // set while the switch can be triggered + 23 BOOL m_bInvisible "Invisible" = FALSE, // make it editor model + +components: + +functions: + /* Get anim data for given animation property - return NULL for none. */ + CAnimData *GetAnimData(SLONG slPropertyOffset) + { + if (slPropertyOffset==offsetof(CSwitch, m_iModelONAnimation) || + slPropertyOffset==offsetof(CSwitch, m_iModelOFFAnimation)) { + return GetModelObject()->GetData(); + } else if (slPropertyOffset==offsetof(CSwitch, m_iTextureONAnimation) || + slPropertyOffset==offsetof(CSwitch, m_iTextureOFFAnimation)) { + return GetModelObject()->mo_toTexture.GetData(); + } else { + return CModelHolder2::GetAnimData(slPropertyOffset); + } + } + + // test if this door reacts on this entity + BOOL CanReactOnEntity(CEntity *pen) + { + if (pen==NULL) { + return FALSE; + } + // never react on non-live or dead entities + if (!(pen->GetFlags()&ENF_ALIVE)) { + return FALSE; + } + + return TRUE; + } + +procedures: + // turn the switch on + SwitchON() { + // if already on + if (m_bSwitchON) { + // do nothing + return; + } + // switch ON + GetModelObject()->PlayAnim(m_iModelONAnimation, 0); + GetModelObject()->mo_toTexture.PlayAnim(m_iTextureONAnimation, 0); + m_bSwitchON = TRUE; + // send event to target + SendToTarget(m_penTarget, m_eetEvent, m_penCaused); + // wait for anim end + wait(GetModelObject()->GetAnimLength(m_iModelONAnimation)) { + on (EBegin) : { resume; } on (ETimer) : { stop; } otherwise(): { resume; } + } + + return EReturn(); // to notify that can be usable + }; + + // turn the switch off + SwitchOFF() { + // if already off + if (!m_bSwitchON) { + // do nothing + return; + } + // switch off + GetModelObject()->PlayAnim(m_iModelOFFAnimation, 0); + GetModelObject()->mo_toTexture.PlayAnim(m_iTextureOFFAnimation, 0); + m_bSwitchON = FALSE; + // send off event to target + SendToTarget(m_penTarget, m_eetOffEvent, m_penCaused); + // wait for anim end + wait(GetModelObject()->GetAnimLength(m_iModelOFFAnimation)) { + on (EBegin) : { resume; } on (ETimer) : { stop; } otherwise(): { resume; } + } + + return EReturn(); // to notify that can be usable + }; + + MainLoop_Once() { + m_bUseable = TRUE; + + //main loop + wait() { + // trigger event -> change switch + on (ETrigger eTrigger) : { + if (CanReactOnEntity(eTrigger.penCaused) && m_bUseable) { + m_bUseable = FALSE; + m_penCaused = eTrigger.penCaused; + call SwitchON(); + } + } + // start -> switch ON + on (EStart) : { + m_bUseable = FALSE; + call SwitchON(); + } + // stop -> switch OFF + on (EStop) : { + m_bUseable = FALSE; + call SwitchOFF(); + } + on (EReturn) : { + m_bUseable = !m_bSwitchON; + resume; + } + } + }; + + MainLoop_OnOff() { + m_bUseable = TRUE; + + //main loop + wait() { + // trigger event -> change switch + on (ETrigger eTrigger) : { + if (CanReactOnEntity(eTrigger.penCaused) && m_bUseable) { + m_bUseable = FALSE; + m_penCaused = eTrigger.penCaused; + // if switch is ON make it OFF + if (m_bSwitchON) { + call SwitchOFF(); + // else if switch is OFF make it ON + } else { + call SwitchON(); + } + } + } + // start -> switch ON + on (EStart) : { + m_bUseable = FALSE; + call SwitchON(); + } + // stop -> switch OFF + on (EStop) : { + m_bUseable = FALSE; + call SwitchOFF(); + } + on (EReturn) : { + m_bUseable = TRUE; + resume; + } + } + }; + + Main() { + // init as model + CModelHolder2::InitModelHolder(); + + if (m_bInvisible) { + SwitchToEditorModel(); + } + + if (m_swtType==SWT_ONCE) { + jump MainLoop_Once(); + } else { + jump MainLoop_OnOff(); + } + + return; + }; +}; diff --git a/Sources/Entities/Teleport.es b/Sources/Entities/Teleport.es new file mode 100644 index 0000000..74fa93a --- /dev/null +++ b/Sources/Entities/Teleport.es @@ -0,0 +1,94 @@ +219 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/BasicEffects"; + +class CTeleport : CRationalEntity { +name "Teleport"; +thumbnail "Thumbnails\\Teleport.tbn"; +features "HasName", "HasTarget", "IsTargetable", "IsImportant"; + +properties: + 1 CTString m_strName "Name" 'N' = "Teleport", + 3 CTString m_strDescription = "", + 2 CEntityPointer m_penTarget "Target" 'T' COLOR(C_BROWN|0xFF), + 4 FLOAT m_fWidth "Width" 'W' = 2.0f, + 5 FLOAT m_fHeight "Height" 'H' = 3.0f, + 6 BOOL m_bActive "Active" 'A' = TRUE, + +components: + 1 model MODEL_TELEPORT "Models\\Editor\\Teleport.mdl", + 2 texture TEXTURE_TELEPORT "Models\\Editor\\Teleport.tex", + 3 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl", + +functions: + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("->"); + if (m_penTarget!=NULL) { + ((CTString&)m_strDescription).PrintF("->%s", (const char*)m_penTarget->GetName()); + } + return m_strDescription; + } + + void TeleportEntity(CEntity *pen, const CPlacement3D &pl) + { + // teleport back + pen->Teleport(pl); + + // spawn teleport effect + ESpawnEffect ese; + ese.colMuliplier = C_WHITE|CT_OPAQUE; + ese.betType = BET_TELEPORT; + ese.vNormal = FLOAT3D(0,1,0); + FLOATaabbox3D box; + pen->GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm()*2; + ese.vStretch = FLOAT3D(fEntitySize, fEntitySize, fEntitySize); + CEntityPointer penEffect = CreateEntity(pl, CLASS_BASIC_EFFECT); + penEffect->Initialize(ese); + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_TOUCHMODEL); + + // set appearance + GetModelObject()->StretchModel(FLOAT3D(m_fWidth, m_fHeight, m_fWidth)); + SetModel(MODEL_TELEPORT); + ModelChangeNotify(); + SetModelMainTexture(TEXTURE_TELEPORT); + + while (TRUE) { + // wait to someone enter and teleport it + wait() { + on (EPass ePass) : { + if (m_penTarget!=NULL && m_bActive) { + TeleportEntity(ePass.penOther, m_penTarget->GetPlacement()); + stop; + } + resume; + } + on (EActivate) : { + m_bActive = TRUE; + resume; + } + on (EDeactivate) : { + m_bActive = FALSE; + resume; + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } +}; + diff --git a/Sources/Entities/TouchField.es b/Sources/Entities/TouchField.es new file mode 100644 index 0000000..458a102 --- /dev/null +++ b/Sources/Entities/TouchField.es @@ -0,0 +1,140 @@ +206 +%{ +#include "Entities/StdH/StdH.h" +%} + +%{ + +BOOL ConsiderAll(CEntity*pen) +{ + return TRUE; +} +BOOL ConsiderPlayers(CEntity*pen) +{ + return IsDerivedFromClass(pen, "Player"); +} +%} + +class CTouchField: CRationalEntity { +name "Touch Field"; +thumbnail "Thumbnails\\TouchField.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "Touch Field", // class name + 2 CEntityPointer m_penEnter "Enter Target" 'T' COLOR(C_BROWN|0xFF), // target to send event to + 3 enum EventEType m_eetEnter "Enter Event" 'E' = EET_TRIGGER, // event to send on enter + 7 CEntityPointer m_penExit "Exit Target" COLOR(C_dRED|0xFF), // target to send event to + 8 enum EventEType m_eetExit "Exit Event" = EET_TRIGGER, // event to send on exit + 4 BOOL m_bActive "Active" 'A' = TRUE, // is field active + 5 BOOL m_bPlayersOnly "Players only" 'P' = TRUE, // reacts only on players + 6 FLOAT m_tmExitCheck "Exit check time" 'X' = 0.0f, // how often to check for exit + 9 BOOL m_bBlockNonPlayers "Block non-players" 'B' = FALSE, // everything except players cannot pass + + 100 CEntityPointer m_penLastIn, +{ + CFieldSettings m_fsField; +} + +components: + 1 texture TEXTURE_FIELD "Models\\Editor\\CollisionBox.tex", + +functions: + void SetupFieldSettings(void) { + m_fsField.fs_toTexture.SetData(GetTextureDataForComponent(TEXTURE_FIELD)); + m_fsField.fs_colColor = C_WHITE|CT_OPAQUE; + } + + CFieldSettings *GetFieldSettings(void) { + if (m_fsField.fs_toTexture.GetData()==NULL) { + SetupFieldSettings(); + } + return &m_fsField; + }; + +procedures: + // field is active + WaitingEntry() { + m_bActive = TRUE; + wait() { + on (EBegin) : { resume; } + on (EDeactivate) : { jump Frozen(); } + // when someone passes the polygons + on (EPass ep) : { + // if should react only on players and not player + if (m_bPlayersOnly && !IsDerivedFromClass(ep.penOther, "Player")) { + // ignore + resume; + } + // send event + SendToTarget(m_penEnter, m_eetEnter, ep.penOther); + // if checking for exit + if (m_tmExitCheck>0) { + // remember who entered + m_penLastIn = ep.penOther; + // wait for exit + jump WaitingExit(); + } + resume; + } + } + }; + + // waiting for entity to exit + WaitingExit() { + while(TRUE) { + // wait + wait(m_tmExitCheck) { + on (EBegin) : { resume; } + on (EDeactivate) : { jump Frozen(); } + on (ETimer) : { + // check for entities inside + CEntity *penNewIn; + if (m_bPlayersOnly) { + penNewIn = TouchingEntity(ConsiderPlayers, m_penLastIn); + } else { + penNewIn = TouchingEntity(ConsiderAll, m_penLastIn); + } + // if there are no entities in anymore + if (penNewIn==NULL) { + // send event + SendToTarget(m_penExit, m_eetExit, m_penLastIn); + // wait new entry + jump WaitingEntry(); + } + m_penLastIn = penNewIn; + stop; + } + } + } + }; + + // field is frozen + Frozen() { + m_bActive = FALSE; + wait() { + on (EBegin) : { resume; } + on (EActivate) : { jump WaitingEntry(); } + } + }; + + // main initialization + Main(EVoid) { + InitAsFieldBrush(); + SetPhysicsFlags(EPF_BRUSH_FIXED); + if ( !m_bBlockNonPlayers ) { + SetCollisionFlags( ((ECBI_MODEL)< 0.0f) { + wait (m_fWaitTime) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + on (EDeactivate) : { pass; } + otherwise(): { resume; } + } + } + + // send event to all targets + SendToTarget(m_penTarget1, m_eetEvent1, m_penCaused); + SendToTarget(m_penTarget2, m_eetEvent2, m_penCaused); + SendToTarget(m_penTarget3, m_eetEvent3, m_penCaused); + SendToTarget(m_penTarget4, m_eetEvent4, m_penCaused); + SendToTarget(m_penTarget5, m_eetEvent5, m_penCaused); + SendToTarget(m_penTarget6, m_eetEvent6, m_penCaused); + SendToTarget(m_penTarget7, m_eetEvent7, m_penCaused); + SendToTarget(m_penTarget8, m_eetEvent8, m_penCaused); + SendToTarget(m_penTarget9, m_eetEvent9, m_penCaused); + SendToTarget(m_penTarget10, m_eetEvent10, m_penCaused); + + // if there is event to send in range + if (m_eetRange!=EET_IGNORE) { + // send in range also + SendInRange(this, m_eetRange, FLOATaabbox3D(GetPlacement().pl_PositionVector, m_fSendRange)); + } + + // if trigger gives score + if (m_fScore>0) { + CEntity *penCaused = FixupCausedToPlayer(this, m_penCaused); + + // if we have causer + if (penCaused!=NULL) { + // send the score + EReceiveScore eScore; + eScore.iPoints = m_fScore; + penCaused->SendEvent(eScore); + penCaused->SendEvent(ESecretFound()); + } + + // kill score to never be reported again + m_fScore = 0; + } + if (m_strMessage!="") { + PrintCenterMessage(this, m_penCaused, + TranslateConst(m_strMessage), + m_fMessageTime, m_mssMessageSound); + } + + // if max trig count is used for counting + if(m_ctMaxTrigs > 0) + { + // decrease count + m_ctMaxTrigs-=1; + // if we trigged max times + if( m_ctMaxTrigs <= 0) + { + // cease to exist + Destroy(); + } + } + return; + }; + + Active() { + ASSERT(m_bActive); + // store count start value + m_iCountTmp = m_iCount; + + //main loop + wait() { + on (EBegin) : { + // if auto start send event on init + if (m_bAutoStart) { + call SendEventToTargets(); + } + resume; + } + // re-roots start events as triggers + on (EStart eStart) : { + SendToTarget(this, EET_TRIGGER, eStart.penCaused); + resume; + } + // cascade trigger + on (ETrigger eTrigger) : { + m_penCaused = eTrigger.penCaused; + // if using count + if (m_bUseCount) { + // count reach lowest value + if (m_iCountTmp > 0) { + // decrease count + m_iCountTmp--; + // send event if count is less than one (is zero) + if (m_iCountTmp < 1) { + if (m_bReuseCount) { + m_iCountTmp = m_iCount; + } else { + m_iCountTmp = 0; + } + call SendEventToTargets(); + } else if (m_bTellCount) { + CTString strRemaining; + strRemaining.PrintF(TRANS("%d more to go..."), m_iCountTmp); + PrintCenterMessage(this, m_penCaused, strRemaining, 3.0f, MSS_INFO); + } + } + // else send event + } else { + call SendEventToTargets(); + } + resume; + } + // if deactivated + on (EDeactivate) : { + // go to inactive state + m_bActive = FALSE; + jump Inactive(); + } + } + }; + Inactive() { + ASSERT(!m_bActive); + while (TRUE) { + // wait + wait() { + // if activated + on (EActivate) : { + // go to active state + m_bActive = TRUE; + jump Active(); + } + otherwise() : { + resume; + }; + }; + + // wait a bit to recover + autowait(0.1f); + } + } + + Main() { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + + m_fSendRange = ClampDn(m_fSendRange, 0.01f); + + // spawn in world editor + autowait(0.1f); + + // go into active or inactive state + if (m_bActive) { + jump Active(); + } else { + jump Inactive(); + } + + // cease to exist + Destroy(); + + return; + }; +}; diff --git a/Sources/Entities/Twister.es b/Sources/Entities/Twister.es new file mode 100644 index 0000000..2a58403 --- /dev/null +++ b/Sources/Entities/Twister.es @@ -0,0 +1,290 @@ +507 +%{ +#include "Entities/StdH/StdH.h" + +#define ECF_TWISTER ( \ + ((ECBI_BRUSH|ECBI_MODEL|ECBI_CORPSE|ECBI_ITEM|ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID)< do not use + 10 FLOAT3D m_vDesiredPosition = FLOAT3D(0,0,0), + 11 FLOAT3D m_vDesiredAngle = FLOAT3D(0,0,0), + 12 FLOAT m_fStopTime = 0.0f, + 13 FLOAT m_fActionRadius = 0.0f, + 14 FLOAT m_fActionTime = 0.0f, + 15 FLOAT m_fDiffMultiply = 0.0f, + 16 FLOAT m_fUpMultiply = 0.0f, + 20 BOOL m_bFadeOut = FALSE, + 21 FLOAT m_fFadeStartTime = 0.0f, + 22 FLOAT m_fFadeTime = 2.0f, + +components: +// ********* TWISTER ********* + 10 model MODEL_TWISTER "Models\\Enemies\\Elementals\\Twister.mdl", + 11 texture TEXTURE_TWISTER "Models\\Enemies\\Elementals\\AirMan01.tex", + +functions: + /* Entity info */ + void *GetEntityInfo(void) { + return &eiTwister; + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + return; + }; + + + +/************************************************************ + * FADE OUT * + ************************************************************/ + BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) { + if (m_bFadeOut) { + FLOAT fTimeRemain = m_fFadeStartTime + m_fFadeTime - _pTimer->CurrentTick(); + if (fTimeRemain < 0.0f) { fTimeRemain = 0.0f; } + COLOR colAlpha = GetModelObject()->mo_colBlendColor; + colAlpha = (colAlpha&0xffffff00) + (COLOR(fTimeRemain/m_fFadeTime*0xff)&0xff); + GetModelObject()->mo_colBlendColor = colAlpha; + } + return CMovableModelEntity::AdjustShadingParameters(vLightDirection, colLight, colAmbient); + }; + + + +/************************************************************ + * MOVING FUNCTIONS * + ************************************************************/ + // calculate rotation + void CalcHeadingRotation(ANGLE aWantedHeadingRelative, ANGLE &aRotation) { + // normalize it to [-180,+180] degrees + aWantedHeadingRelative = NormalizeAngle(aWantedHeadingRelative); + + // if desired position is left + if (aWantedHeadingRelative < -ROTATE_SPEED*MOVE_FREQUENCY) { + // start turning left + aRotation = -ROTATE_SPEED; + // if desired position is right + } else if (aWantedHeadingRelative > ROTATE_SPEED*MOVE_FREQUENCY) { + // start turning right + aRotation = +ROTATE_SPEED; + // if desired position is more-less ahead + } else { + aRotation = aWantedHeadingRelative/MOVE_FREQUENCY; + } + }; + + // calculate angle from position + void CalcAngleFromPosition() { + // find relative orientation towards the desired position + m_vDesiredAngle = (m_vDesiredPosition - GetPlacement().pl_PositionVector).Normalize(); + }; + + // rotate entity to desired angle + void RotateToAngle() { + // find relative heading towards the desired angle + ANGLE aRotation; + CalcHeadingRotation(GetRelativeHeading(m_vDesiredAngle), aRotation); + + // start rotating + SetDesiredRotation(ANGLE3D(aRotation, 0, 0)); + }; + + // move in direction + void MoveInDirection() { + RotateToAngle(); + + // determine translation speed + FLOAT3D vTranslation(0.0f, 0.0f, 0.0f); + vTranslation(3) = -MOVE_SPEED; + + // start moving + SetDesiredTranslation(vTranslation); + }; + + // move entity to desired position + void MoveToPosition() { + CalcAngleFromPosition(); + MoveInDirection(); + }; + + // rotate entity to desired position + void RotateToPosition() { + CalcAngleFromPosition(); + RotateToAngle(); + }; + + // stop moving entity + void StopMoving() { + StopRotating(); + StopTranslating(); + }; + + // stop rotating entity + void StopRotating() { + SetDesiredRotation(ANGLE3D(0, 0, 0)); + }; + + // stop translating + void StopTranslating() { + SetDesiredTranslation(FLOAT3D(0.0f, 0.0f, 0.0f)); + }; + + + +/************************************************************ + * ATTACK SPECIFIC * + ************************************************************/ + void SpinEntity(CEntity *pen) { + // don't spin air elemental and another twister + if (!(IsOfClass(pen, "Elemental") && ((CElemental&)*pen).m_EetType==ELT_AIR) && + !(IsOfClass(pen, "Twister"))) { + if (pen->GetPhysicsFlags()&EPF_MOVABLE) { + // throw target away + FLOAT3D vSpeed; + vSpeed = FLOAT3D(en_mRotation(1, 2), en_mRotation(2, 2), en_mRotation(3, 2)) * m_fUpMultiply; + FLOAT3D vDiff = (pen->GetPlacement().pl_PositionVector - GetPlacement().pl_PositionVector).Normalize(); + vSpeed += (vDiff*m_fDiffMultiply) * pen->en_mRotation; + // give absolute speed + ((CMovableEntity&)*pen).en_vCurrentTranslationAbsolute = vSpeed; + ((CMovableEntity&)*pen).en_aDesiredRotationRelative = ANGLE3D(180.0f, 0, 0); + // damage + FLOAT3D vDirection; + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, vDirection); + InflictDirectDamage(pen, m_penOwner, DMT_IMPACT, 0.1f, GetPlacement().pl_PositionVector, vDirection); + } + } + }; + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> MAIN + Main(ETwister et) { + // remember the initial parameters + ASSERT(et.penOwner!=NULL); + m_penOwner = et.penOwner; + m_EtsSize = et.EtsSize; + + // initialization + InitAsModel(); + SetPhysicsFlags(EPF_TWISTER); + SetCollisionFlags(ECF_TWISTER); + SetFlags(GetFlags() | ENF_SEETHROUGH); + SetModel(MODEL_TWISTER); + SetModelMainTexture(TEXTURE_TWISTER); + + // setup + switch(m_EtsSize) { + case TWS_SMALL: + m_fActionRadius = 10; + m_fActionTime = 10; + m_fUpMultiply = 5.0f; + m_fDiffMultiply = 1.0f; + break; + case TWS_BIG: + m_fActionRadius = 15; + m_fActionTime = 20; + m_fUpMultiply = 10.0f; + m_fDiffMultiply = 4.0f; + GetModelObject()->StretchModel(FLOAT3D(4.0f, 4.0f, 4.0f)); + break; + case TWS_LARGE: + m_fActionRadius = 20; + m_fActionTime = 30; + m_fUpMultiply = 20.0f; + m_fDiffMultiply = 16.0f; + GetModelObject()->StretchModel(FLOAT3D(16.0f, 16.0f, 16.0f)); + break; + } + ModelChangeNotify(); + + // start position + m_vStartPosition = GetPlacement().pl_PositionVector; + + // move in range + m_fStopTime = _pTimer->CurrentTick() + 10.0f; + while(_pTimer->CurrentTick() < m_fStopTime) { + // new destination + FLOAT fR = FRnd()*10.0f; + FLOAT fA = FRnd()*360.0f; + m_vDesiredPosition = m_vStartPosition + FLOAT3D(CosFast(fA)*fR, 0, SinFast(fA)*fR); + while((m_vDesiredPosition - GetPlacement().pl_PositionVector).Length() > MOVE_SPEED*MOVE_FREQUENCY*2.0f && + _pTimer->CurrentTick() < m_fStopTime) { + MoveToPosition(); + wait(MOVE_FREQUENCY) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + on (EPass ep) : { + if (ep.penOther->GetRenderType()&RT_MODEL && + ep.penOther->GetPhysicsFlags()&EPF_MOVABLE) { + SpinEntity(ep.penOther); + } + resume; + } + } + } + } + + // fade out + m_fFadeStartTime = _pTimer->CurrentTick(); + m_bFadeOut = TRUE; + m_fFadeTime = 2.0f; + autowait(m_fFadeTime); + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/VoiceHolder.es b/Sources/Entities/VoiceHolder.es new file mode 100644 index 0000000..208d950 --- /dev/null +++ b/Sources/Entities/VoiceHolder.es @@ -0,0 +1,80 @@ +231 +%{ +#include "Entities/StdH/StdH.h" +extern INDEX ent_bReportBrokenChains; +%} + +class CVoiceHolder : CRationalEntity { +name "VoiceHolder"; +thumbnail "Thumbnails\\VoiceHolder.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CTString m_strName "Name" 'N' = "VoiceHolder", + 3 CTString m_strDescription = "", + 2 CTFileName m_fnmMessage "Message" 'M' = CTString(""), + 5 BOOL m_bActive "Active" 'A' = TRUE, + 6 INDEX m_ctMaxTrigs "Max trigs" 'X' = 1, // how many times could trig + + { + CAutoPrecacheSound m_aps; + } +components: + 1 model MODEL_MARKER "Models\\Editor\\VoiceHolder.mdl", + 2 texture TEXTURE_MARKER "Models\\Editor\\VoiceHolder.tex" + +functions: + void Precache(void) + { + m_aps.Precache(m_fnmMessage); + } + const CTString &GetDescription(void) const { + ((CTString&)m_strDescription).PrintF("%s", (const char*)m_fnmMessage.FileName()); + return m_strDescription; + } + +procedures: + Main() + { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_MARKER); + SetModelMainTexture(TEXTURE_MARKER); + wait() { + on (ETrigger eTrigger): { + if (!m_bActive) { + resume; + } + CEntity *penCaused = FixupCausedToPlayer(this, eTrigger.penCaused); + EVoiceMessage eMsg; + eMsg.fnmMessage = m_fnmMessage; + penCaused->SendEvent(eMsg); + // if max trig count is used for counting + if(m_ctMaxTrigs > 0) { + // decrease count + m_ctMaxTrigs-=1; + // if we trigged max times + if( m_ctMaxTrigs <= 0) { + // cease to exist + Destroy(); + stop; + } + } + resume; + } + on (EActivate): { + m_bActive = TRUE; + resume; + } + on (EDeactivate): { + m_bActive = FALSE; + resume; + } + } + return; + } +}; + diff --git a/Sources/Entities/Walker.es b/Sources/Entities/Walker.es new file mode 100644 index 0000000..80e6108 --- /dev/null +++ b/Sources/Entities/Walker.es @@ -0,0 +1,499 @@ +324 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Walker/Walker.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/Projectile"; + +enum WalkerChar { + 0 WLC_SOLDIER "Soldier", // soldier + 1 WLC_SERGEANT "Sergeant", // sergeant +}; + +%{ +// info structure +static EntityInfo eiWalker = { + EIBT_FLESH, 1000.0f, + 0.0f, 5.4f, 0.0f, + 0.0f, 4.5f, 0.0f, +}; + +#define SIZE_SOLDIER (0.5f) +#define SIZE_SERGEANT (1.0f) +#define FIRE_LEFT_ARM FLOAT3D(-2.5f, 5.0f, 0.0f) +#define FIRE_RIGHT_ARM FLOAT3D(+2.5f, 5.0f, 0.0f) +#define FIRE_DEATH_LEFT FLOAT3D( 0.0f, 7.0f, -2.0f) +#define FIRE_DEATH_RIGHT FLOAT3D(3.75f, 4.2f, -2.5f) + +#define WALKERSOUND(soundname) ((m_EwcChar==WLC_SOLDIER)? (SOUND_SOLDIER_##soundname) : (SOUND_SERGEANT_##soundname)) +%} + + +class CWalker : CEnemyBase { +name "Walker"; +thumbnail "Thumbnails\\Walker.tbn"; + +properties: + 1 enum WalkerChar m_EwcChar "Character" 'C' = WLC_SOLDIER, + 2 INDEX m_iLoopCounter = 0, + 3 FLOAT m_fSize = 1.0f, + 4 BOOL m_bWalkSoundPlaying = FALSE, + 5 FLOAT m_fThreatDistance = 5.0f, + + 10 CSoundObject m_soFeet, + 11 CSoundObject m_soFire1, + 12 CSoundObject m_soFire2, + 13 CSoundObject m_soFire3, + 14 CSoundObject m_soFire4, + +components: + 0 class CLASS_BASE "Classes\\EnemyBase.ecl", + 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + + 10 model MODEL_WALKER "Models\\Enemies\\Walker\\Walker.mdl", + 11 texture TEXTURE_WALKER_SOLDIER "Models\\Enemies\\Walker\\Walker02.tex", + 12 texture TEXTURE_WALKER_SERGEANT "Models\\Enemies\\Walker\\Walker01.tex", + 14 model MODEL_LASER "Models\\Enemies\\Walker\\Laser.mdl", + 15 texture TEXTURE_LASER "Models\\Enemies\\Walker\\Laser.tex", + 16 model MODEL_ROCKETLAUNCHER "Models\\Enemies\\Walker\\RocketLauncher.mdl", + 17 texture TEXTURE_ROCKETLAUNCHER "Models\\Enemies\\Walker\\RocketLauncher.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_SOLDIER_IDLE "Models\\Enemies\\Walker\\Sounds\\Soldier\\Idle.wav", + 51 sound SOUND_SOLDIER_SIGHT "Models\\Enemies\\Walker\\Sounds\\Soldier\\Sight.wav", + 53 sound SOUND_SOLDIER_FIRE_LASER "Models\\Enemies\\Walker\\Sounds\\Soldier\\Fire.wav", + 54 sound SOUND_SOLDIER_DEATH "Models\\Enemies\\Walker\\Sounds\\Soldier\\Death.wav", + 55 sound SOUND_SOLDIER_WALK "Models\\Enemies\\Walker\\Sounds\\Soldier\\Walk.wav", + + 60 sound SOUND_SERGEANT_IDLE "Models\\Enemies\\Walker\\Sounds\\Sergeant\\Idle.wav", + 61 sound SOUND_SERGEANT_SIGHT "Models\\Enemies\\Walker\\Sounds\\Sergeant\\Sight.wav", + 63 sound SOUND_SERGEANT_FIRE_ROCKET "Models\\Enemies\\Walker\\Sounds\\Sergeant\\Fire.wav", + 64 sound SOUND_SERGEANT_DEATH "Models\\Enemies\\Walker\\Sounds\\Sergeant\\Death.wav", + 65 sound SOUND_SERGEANT_WALK "Models\\Enemies\\Walker\\Sounds\\Sergeant\\Walk.wav", + + /* + 70 model MODEL_WALKER_HEAD1 "Models\\Enemies\\Walker\\Debris\\Head.mdl", + 71 model MODEL_WALKER_HEAD2 "Models\\Enemies\\Walker\\Debris\\Head2.mdl", + 72 model MODEL_WALKER_LEG "Models\\Enemies\\Walker\\Debris\\Leg.mdl", + */ + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("A Biomech blew %s away"), (const char*)strPlayerName); + return str; + } + + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnmSoldier, "Data\\Messages\\Enemies\\WalkerSmall.txt"); + static DECLARE_CTFILENAME(fnmSergeant, "Data\\Messages\\Enemies\\WalkerBig.txt"); + switch(m_EwcChar) { + default: ASSERT(FALSE); + case WLC_SOLDIER: return fnmSoldier; + case WLC_SERGEANT: return fnmSergeant; + } + } + // overridable function to get range for switching to another player + FLOAT GetThreatDistance(void) + { + return m_fThreatDistance; + } + + BOOL ForcesCannonballToExplode(void) + { + if (m_EwcChar==WLC_SERGEANT) { + return TRUE; + } + return CEnemyBase::ForcesCannonballToExplode(); + } + + void Precache(void) { + CEnemyBase::Precache(); + + PrecacheModel(MODEL_WALKER); + + if (m_EwcChar==WLC_SOLDIER) + { + // sounds + PrecacheSound(SOUND_SOLDIER_IDLE ); + PrecacheSound(SOUND_SOLDIER_SIGHT); + PrecacheSound(SOUND_SOLDIER_DEATH); + PrecacheSound(SOUND_SOLDIER_FIRE_LASER); + PrecacheSound(SOUND_SOLDIER_WALK); + // model's texture + PrecacheTexture(TEXTURE_WALKER_SOLDIER); + // weapon + PrecacheModel(MODEL_LASER); + PrecacheTexture(TEXTURE_LASER); + // projectile + PrecacheClass(CLASS_PROJECTILE, PRT_CYBORG_LASER); + } + else + { + // sounds + PrecacheSound(SOUND_SERGEANT_IDLE); + PrecacheSound(SOUND_SERGEANT_SIGHT); + PrecacheSound(SOUND_SERGEANT_DEATH); + PrecacheSound(SOUND_SERGEANT_FIRE_ROCKET); + PrecacheSound(SOUND_SERGEANT_WALK); + // model's texture + PrecacheTexture(TEXTURE_WALKER_SERGEANT); + // weapon + PrecacheModel(MODEL_ROCKETLAUNCHER); + PrecacheTexture(TEXTURE_ROCKETLAUNCHER); + // projectile + PrecacheClass(CLASS_PROJECTILE, PRT_WALKER_ROCKET); + } + }; + /* Entity info */ + void *GetEntityInfo(void) { + return &eiWalker; + }; + + FLOAT GetCrushHealth(void) + { + if (m_EwcChar==WLC_SERGEANT) { + return 100.0f; + } + return 0.0f; + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // walker can't harm walker + if (!IsOfClass(penInflictor, "Walker") || + ((CWalker*)penInflictor)->m_EwcChar!=m_EwcChar) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // virtual anim functions + void StandingAnim(void) { + DeactivateWalkingSound(); + StartModelAnim(WALKER_ANIM_STAND01, AOF_LOOPING|AOF_NORESTART); + }; + void StandingAnimFight(void) + { + DeactivateWalkingSound(); + StartModelAnim(WALKER_ANIM_IDLEFIGHT, AOF_LOOPING|AOF_NORESTART); + } + void WalkingAnim(void) { + ActivateWalkingSound(); + if (m_EwcChar==WLC_SERGEANT) { + StartModelAnim(WALKER_ANIM_WALKBIG, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(WALKER_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) { + WalkingAnim(); + }; + void RotatingAnim(void) { + WalkingAnim(); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, WALKERSOUND(IDLE), SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, WALKERSOUND(SIGHT), SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, WALKERSOUND(DEATH), SOF_3D); + }; + + // walking sounds + void ActivateWalkingSound(void) + { + if (!m_bWalkSoundPlaying) { + PlaySound(m_soFeet, WALKERSOUND(WALK), SOF_3D|SOF_LOOP); + m_bWalkSoundPlaying = TRUE; + } + } + void DeactivateWalkingSound(void) + { + m_soFeet.Stop(); + m_bWalkSoundPlaying = FALSE; + } + + // fire death rocket + void FireDeathRocket(const FLOAT3D &vPos) { + CPlacement3D plRocket; + plRocket.pl_PositionVector = vPos; + plRocket.pl_OrientationAngle = ANGLE3D(0, -5.0f-FRnd()*10.0f, 0); + plRocket.RelativeToAbsolute(GetPlacement()); + CEntityPointer penProjectile = CreateEntity(plRocket, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_WALKER_ROCKET; + penProjectile->Initialize(eLaunch); + }; + // fire death laser + void FireDeathLaser(const FLOAT3D &vPos) { + CPlacement3D plLaser; + plLaser.pl_PositionVector = vPos; + plLaser.pl_OrientationAngle = ANGLE3D(0, -5.0f-FRnd()*10.0f, 0); + plLaser.RelativeToAbsolute(GetPlacement()); + CEntityPointer penProjectile = CreateEntity(plLaser, CLASS_PROJECTILE); + ELaunchProjectile eLaunch; + eLaunch.penLauncher = this; + eLaunch.prtType = PRT_CYBORG_LASER; + penProjectile->Initialize(eLaunch); + }; + + + + // adjust sound and watcher parameters here if needed + void EnemyPostInit(void) + { + // set sound default parameters + m_soSound.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + m_soFeet.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + m_soFire1.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + m_soFire2.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + m_soFire3.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + m_soFire4.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + }; + +/************************************************************ + * BLOW UP FUNCTIONS * + ************************************************************/ + // spawn body parts +/* void BlowUp(void) + { + // get your size + FLOATaabbox3D box; + GetBoundingBox(box); + FLOAT fEntitySize = box.Size().MaxNorm(); + + FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); + vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); + + vNormalizedDamage *= 0.75f; + FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); + + // spawn debris + Debris_Begin(EIBT_FLESH, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 5.0f, 2.0f); + Debris_Spawn(this, this, MODEL_WALKER_HEAD1, TEXTURE_WALKER_SOLDIER, 0, 0, 0, 0, 0.1250f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_WALKER_HEAD2, TEXTURE_WALKER_SOLDIER, 0, 0, 0, 0, 0.125f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_WALKER_LEG, TEXTURE_WALKER_SOLDIER, 0, 0, 0, 0, 0.125f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + Debris_Spawn(this, this, MODEL_WALKER_LEG, TEXTURE_WALKER_SOLDIER, 0, 0, 0, 0, 0.125f, + FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); + + // hide yourself (must do this after spawning debris) + SwitchToEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + };*/ + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + Fire(EVoid) : CEnemyBase::Fire { + DeactivateWalkingSound(); + // to fire + StartModelAnim(WALKER_ANIM_TOFIRE, 0); + m_fLockOnEnemyTime = GetModelObject()->GetAnimLength(WALKER_ANIM_TOFIRE); + autocall CEnemyBase::LockOnEnemy() EReturn; + + // sergeant 4 rockets + if (m_EwcChar==WLC_SERGEANT) { + StartModelAnim(WALKER_ANIM_FIRERIGHT, AOF_LOOPING); + ShootProjectile(PRT_WALKER_ROCKET, FIRE_RIGHT_ARM*m_fSize, ANGLE3D(0, 0, 0)); + PlaySound(m_soFire1, SOUND_SERGEANT_FIRE_ROCKET, SOF_3D); + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + m_fLockOnEnemyTime = 1.0f; + } else { + m_fLockOnEnemyTime = 0.5f; + } + autocall CEnemyBase::LockOnEnemy() EReturn; + StartModelAnim(WALKER_ANIM_FIRELEFT, AOF_LOOPING); + ShootProjectile(PRT_WALKER_ROCKET, FIRE_LEFT_ARM*m_fSize, ANGLE3D(0, 0, 0)); + PlaySound(m_soFire2, SOUND_SERGEANT_FIRE_ROCKET, SOF_3D); + +// m_fLockOnEnemyTime = 0.25f; +// autocall CEnemyBase::LockOnEnemy() EReturn; + } + if (m_EwcChar==WLC_SOLDIER) { + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + m_iLoopCounter = 4; + } else { + m_iLoopCounter = 8; + } + while(m_iLoopCounter>0) { + if (m_iLoopCounter%2) { + StartModelAnim(WALKER_ANIM_FIRELEFT, AOF_LOOPING); + ShootProjectile(PRT_CYBORG_LASER, FIRE_LEFT_ARM*m_fSize, ANGLE3D(0, 0, 0)); + } else { + StartModelAnim(WALKER_ANIM_FIRERIGHT, AOF_LOOPING); + ShootProjectile(PRT_CYBORG_LASER, FIRE_RIGHT_ARM*m_fSize, ANGLE3D(0, 0, 0)); + } + INDEX iChannel = m_iLoopCounter%4; + if (iChannel==0) { + PlaySound(m_soFire1, SOUND_SOLDIER_FIRE_LASER, SOF_3D); + } else if (iChannel==1) { + PlaySound(m_soFire2, SOUND_SOLDIER_FIRE_LASER, SOF_3D); + } else if (iChannel==2) { + PlaySound(m_soFire3, SOUND_SOLDIER_FIRE_LASER, SOF_3D); + } else if (iChannel==3) { + PlaySound(m_soFire4, SOUND_SOLDIER_FIRE_LASER, SOF_3D); + } + if (m_iLoopCounter>1) { + if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) { + m_fLockOnEnemyTime = 0.4f; + } else { + m_fLockOnEnemyTime = 0.1f; + } + autocall CEnemyBase::LockOnEnemy() EReturn; + } + m_iLoopCounter--; + } + } + StopMoving(); + + MaybeSwitchToAnotherPlayer(); + + // from fire + StartModelAnim(WALKER_ANIM_FROMFIRE, 0); + autowait(GetModelObject()->GetAnimLength(WALKER_ANIM_FROMFIRE)); + + // wait for a while + StandingAnimFight(); + autowait(FRnd()*0.1f+0.1f); + + return EReturn(); + }; + + + +/************************************************************ + * D E A T H * + ************************************************************/ + Death(EVoid) : CEnemyBase::Death { + // stop moving + StopMoving(); + DeathSound(); // death sound + DeactivateWalkingSound(); + + // set physic flags + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags() | ENF_SEETHROUGH); + + // death notify (change collision box) + ChangeCollisionBoxIndexWhenPossible(WALKER_COLLISION_BOX_DEATH); + + // start death anim + StartModelAnim(WALKER_ANIM_DEATH, 0); + autowait(0.9f); + + // one rocket/laser from left or right arm + if (m_EwcChar==WLC_SERGEANT) { + if (IRnd()&1) { + FireDeathRocket(FIRE_DEATH_RIGHT*m_fSize); + } else { + FireDeathRocket(FIRE_DEATH_LEFT*m_fSize); + } + PlaySound(m_soSound, SOUND_SERGEANT_FIRE_ROCKET, SOF_3D); + } + if (m_EwcChar==WLC_SOLDIER) { + if (IRnd()&1) { + FireDeathLaser(FIRE_DEATH_RIGHT*m_fSize); + } else { + FireDeathLaser(FIRE_DEATH_LEFT*m_fSize); + } + PlaySound(m_soFire2, SOUND_SOLDIER_FIRE_LASER, SOF_3D); + } + autowait(0.6f); + + return EEnd(); + }; + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + if (m_EwcChar==WLC_SERGEANT) { + SetHealth(750.0f); + m_fMaxHealth = 750.0f; + } else { + SetHealth(150.0f); + m_fMaxHealth = 150.0f; + } + en_fDensity = 3000.0f; + + m_sptType = SPT_ELECTRICITY_SPARKS; + + // set your appearance + SetModel(MODEL_WALKER); + if (m_EwcChar==WLC_SERGEANT) { + m_fSize = 1.0f; + SetModelMainTexture(TEXTURE_WALKER_SERGEANT); + AddAttachment(WALKER_ATTACHMENT_ROCKETLAUNCHER_LT, MODEL_ROCKETLAUNCHER, TEXTURE_ROCKETLAUNCHER); + AddAttachment(WALKER_ATTACHMENT_ROCKETLAUNCHER_RT, MODEL_ROCKETLAUNCHER, TEXTURE_ROCKETLAUNCHER); + GetModelObject()->StretchModel(FLOAT3D(1,1,1)); + ModelChangeNotify(); + CModelObject *pmoRight = &GetModelObject()->GetAttachmentModel(WALKER_ATTACHMENT_ROCKETLAUNCHER_RT)->amo_moModelObject; + pmoRight->StretchModel(FLOAT3D(-1,1,1)); + m_fBlowUpAmount = 1E10f; + m_iScore = 7500; + m_fThreatDistance = 15; + } else { + m_fSize = 0.5f; + SetModelMainTexture(TEXTURE_WALKER_SOLDIER); + AddAttachment(WALKER_ATTACHMENT_LASER_LT, MODEL_LASER, TEXTURE_LASER); + AddAttachment(WALKER_ATTACHMENT_LASER_RT, MODEL_LASER, TEXTURE_LASER); + GetModelObject()->StretchModel(FLOAT3D(0.5f,0.5f,0.5f)); + ModelChangeNotify(); + CModelObject *pmoRight = &GetModelObject()->GetAttachmentModel(WALKER_ATTACHMENT_LASER_RT)->amo_moModelObject; + pmoRight->StretchModel(FLOAT3D(-0.5f,0.5f,0.5f)); + m_fBlowUpAmount = 1E10f; + //m_fBlowUpAmount = 100.0f; + //m_bRobotBlowup = TRUE; + m_iScore = 2000; + m_fThreatDistance = 5; + } + if (m_fStepHeight==-1) { + m_fStepHeight = 4.0f; + } + + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd()*1.5f + 9.0f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*50.0f + 500.0f); + m_fAttackRunSpeed = m_fWalkSpeed; + m_aAttackRotateSpeed = m_aWalkRotateSpeed/2; + m_fCloseRunSpeed = m_fWalkSpeed; + m_aCloseRotateSpeed = m_aWalkRotateSpeed/2; + m_fWalkSpeed/=2.0f; + // setup attack distances + m_fAttackDistance = 150.0f; + m_fCloseDistance = 0.0f; + m_fStopDistance = 15.0f; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 300.0f; + // damage/explode properties + m_fBodyParts = 8; + m_fDamageWounded = 100000.0f; + + // continue behavior in base class + jump CEnemyBase::MainLoop(); + }; +}; diff --git a/Sources/Entities/WatchPlayers.es b/Sources/Entities/WatchPlayers.es new file mode 100644 index 0000000..19679b9 --- /dev/null +++ b/Sources/Entities/WatchPlayers.es @@ -0,0 +1,161 @@ +702 +%{ +#include "Entities/StdH/StdH.h" +%} + +class CWatchPlayers: CRationalEntity { +name "Watch Players"; +thumbnail "Thumbnails\\WatchPlayers.tbn"; +features "HasName", "IsTargetable"; + +properties: + 1 CEntityPointer m_penOwner "Owner/Target" 'O' COLOR(C_dBROWN|0xFF), // entity which owns it / target + 2 FLOAT m_fWaitTime "Wait time" 'W' = 0.1f, // watch time + 3 RANGE m_fDistance "Watch distance" 'D' = 100.0f, // distance when player is seen + 4 BOOL m_bRangeWatcher "Range watcher" 'R' = TRUE, // range watcher + 5 enum EventEType m_eetEventClose "Close Event type" 'T' = EET_TRIGGER, // type of event to send + 6 enum EventEType m_eetEventFar "Far Event type" 'Y' = EET_ENVIRONMENTSTOP, // type of event to send + 7 CEntityPointer m_penCurrentWatch, + 8 BOOL m_bActive "Active" 'A' = TRUE, + 9 CTString m_strName "Name" 'N' = "", + +components: + 1 model MODEL_WATCHPLAYERS "Models\\Editor\\WatchPlayers.mdl", + 2 texture TEXTURE_WATCHPLAYERS "Models\\Editor\\WatchPlayers.tex" + +functions: +/************************************************************ + * USER FUNCTIONS * + ************************************************************/ + // check if any player is close + BOOL IsAnyPlayerClose(void) { + // far enough to not move at all + FLOAT fClosest = 100000.0f; + FLOAT fDistance; + + m_penCurrentWatch = NULL; + // for all players + for (INDEX iPlayer=0; iPlayerGetFlags()&ENF_ALIVE && !(penPlayer->GetFlags()&ENF_INVISIBLE)) { + fDistance = 100000.0f; + if (m_bRangeWatcher) { + // calculate distance to player from wathcer + fDistance = (penPlayer->GetPlacement().pl_PositionVector- + GetPlacement().pl_PositionVector).Length(); + } else { + if (m_penOwner!=NULL) { + // calculate distance to player from owner + fDistance = (penPlayer->GetPlacement().pl_PositionVector- + m_penOwner->GetPlacement().pl_PositionVector).Length(); + } + } + if (fDistanceGetFlags()&ENF_ALIVE && !(penPlayer->GetFlags()&ENF_INVISIBLE)) { + // calculate distance to player + FLOAT fDistance = + (penPlayer->GetPlacement().pl_PositionVector-m_penOwner->GetPlacement().pl_PositionVector).Length(); + // update if closer + if (fDistanceSendEvent(eWatch); + } + + void CheckIfPlayerVisible(void) + { + // if the owner is blind + if( GetOwner()->m_bBlind) { + // don't even bother checking + return; + } + + // get maximum number of players in game + INDEX ctPlayers = GetMaxPlayers(); + // find first one after current sequence + CEntity *penPlayer = NULL; + m_iPlayerToCheck = (m_iPlayerToCheck+1)%ctPlayers; + INDEX iFirstChecked = m_iPlayerToCheck; + FOREVER { + penPlayer = GetPlayerEntity(m_iPlayerToCheck); + if (penPlayer!=NULL) { + break; + } + m_iPlayerToCheck++; + m_iPlayerToCheck%=ctPlayers; + if (m_iPlayerToCheck==iFirstChecked) { + return; // we get here if there are no players at all + } + } + + // if this one is dead or invisible + if (!(penPlayer->GetFlags()&ENF_ALIVE) || (penPlayer->GetFlags()&ENF_INVISIBLE)) { + // do nothing + return; + } + + // if inside view angle and visible + if (GetOwner()->SeeEntity(penPlayer, Cos(GetOwner()->m_fViewAngle/2.0f))) { + // send event to owner + SendWatchEvent(penPlayer); + } + }; + + // set new watch time + void SetWatchDelays(void) + { + const FLOAT tmMinDelay = 0.1f; // delay at closest distance + const FLOAT tmSeeDelay = 5.0f; // delay at see distance + const FLOAT tmTick = _pTimer->TickQuantum; + FLOAT fSeeDistance = GetOwner()->m_fIgnoreRange; + FLOAT fNearDistance = Min(GetOwner()->m_fStopDistance, GetOwner()->m_fCloseDistance); + + // if closer than near distance + if (m_fClosestPlayer<=fNearDistance) { + // always use minimum delay + m_tmDelay = tmMinDelay; + // if further than near distance + } else { + // interpolate between near and see + m_tmDelay = tmMinDelay+ + (m_fClosestPlayer-fNearDistance)*(tmSeeDelay-tmMinDelay)/(fSeeDistance-fNearDistance); + // round to nearest tick + m_tmDelay = floor(m_tmDelay/tmTick)*tmTick; + } + }; + + // watch + void Watch(void) + { + // remember original distance + FLOAT fOrgDistance = m_fClosestPlayer; + + // find closest player + CEntity *penClosest = FindClosestPlayer(); + + FLOAT fSeeDistance = GetOwner()->m_fIgnoreRange; + FLOAT fStopDistance = Max(fSeeDistance*1.5f, GetOwner()->m_fActivityRange); + + // if players exited enemy's scope + if (fOrgDistance=fStopDistance) { + // stop owner + m_penOwner->SendEvent(EStop()); + // if players entered enemy's scope + } else if (fOrgDistance>=fStopDistance && m_fClosestPlayerSendEvent(EStart()); + } + + // if the closest player is close enough to be seen + if (m_fClosestPlayerm_fSenseRange; + if (penClosest!=NULL && fSenseRange>0 && m_fClosestPlayerm_bBlind) { + // don't even bother checking + return NULL; + } + + CEntity *penClosestPlayer = NULL; + FLOAT fClosestPlayer = + (penCurrentTarget->GetPlacement().pl_PositionVector-m_penOwner->GetPlacement().pl_PositionVector).Length(); + fClosestPlayer = Min(fClosestPlayer, fRange); // this is maximum considered range + + // for all other players + for (INDEX iPlayer=0; iPlayerGetFlags()&ENF_ALIVE) && !(penPlayer->GetFlags()&ENF_INVISIBLE)) { + // calculate distance to player + FLOAT fDistance = + (penPlayer->GetPlacement().pl_PositionVector-m_penOwner->GetPlacement().pl_PositionVector).Length(); + // if closer than current and you can see him + if (fDistanceSeeEntity(penPlayer, Cos(GetOwner()->m_fViewAngle/2.0f))) { + // update + fClosestPlayer = fDistance; + penClosestPlayer = penPlayer; + } + } + } + + return penClosestPlayer; + } + + // this is called directly from enemybase to attack multiple players (for really big enemies) + CEntity *CheckAnotherPlayer(CEntity *penCurrentTarget) + { + // if the owner is blind, or no current target + if( GetOwner()->m_bBlind || penCurrentTarget==NULL) { + // don't even check + return NULL; + } + + // get allowed distance + CEntity *penClosestPlayer = NULL; + FLOAT fCurrentDistance = + (penCurrentTarget->GetPlacement().pl_PositionVector-m_penOwner->GetPlacement().pl_PositionVector).Length(); + FLOAT fRange = fCurrentDistance*1.5f; + + // find a random offset to start searching + INDEX iOffset = GetRandomPlayer(); + + // for all other players + INDEX ctPlayers = GetMaxPlayers(); + for (INDEX iPlayer=0; iPlayerGetFlags()&ENF_ALIVE) && !(penPlayer->GetFlags()&ENF_INVISIBLE)) { + // calculate distance to player + FLOAT fDistance = + (penPlayer->GetPlacement().pl_PositionVector-m_penOwner->GetPlacement().pl_PositionVector).Length(); + // if inside allowed range and visible + if (fDistanceSeeEntity(penPlayer, Cos(GetOwner()->m_fViewAngle/2.0f))) { + // attack that one + return penPlayer; + } + } + } + + return penCurrentTarget; + } + +procedures: + // watching + Active() { + // repeat + while (TRUE) { + // check all players + Watch(); + // wait for given delay + wait(m_tmDelay) { + on (EBegin) : { resume; } + on (ETimer) : { stop; } + // stop looking + on (EStop) : { jump Inactive(); } + // force re-checking if receiving start or teleport + on (EStart) : { stop; } + on (ETeleport) : { stop; } + } + } + }; + + // not watching + Inactive(EVoid) { + wait() { + on (EBegin) : { resume; } + on (EStart) : { jump Active(); } + } + }; + + // dummy mode + Dummy(EVoid) + { + // ignores all events forever + wait() { + on (EBegin) : { resume; } + otherwise() : { resume; }; + }; + } + + Main(EWatcherInit eInit) { + // remember the initial parameters + ASSERT(eInit.penOwner!=NULL); + m_penOwner = eInit.penOwner; + + // init as nothing + InitAsVoid(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // if in flyover game mode + if (GetSP()->sp_gmGameMode == CSessionProperties::GM_FLYOVER) { + // go to dummy mode + jump Dummy(); + // NOTE: must not destroy self, because owner has a pointer + } + + // generate random number of player to check next + // (to provide even distribution of enemies among players) + m_iPlayerToCheck = GetRandomPlayer()-1; + + // start in disabled state + autocall Inactive() EEnd; + + // cease to exist + Destroy(); + + return; + }; +}; \ No newline at end of file diff --git a/Sources/Entities/Water.es b/Sources/Entities/Water.es new file mode 100644 index 0000000..f59c9d0 --- /dev/null +++ b/Sources/Entities/Water.es @@ -0,0 +1,209 @@ +508 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Light"; + +enum WaterSize { + 0 WTS_SMALL "", // small water + 1 WTS_BIG "", // big water + 2 WTS_LARGE "", // large water +}; + + +// input parameter for water +event EWater { + CEntityPointer penLauncher, // entity which launch it + enum WaterSize EwsSize, // water size +}; + + +%{ +#define FLY_TIME 5.0f +%} + +class CWater : CMovableModelEntity { +name "Water"; +thumbnail ""; + +properties: + 1 CEntityPointer m_penLauncher, // entity which launch it + 2 enum WaterSize m_EwsSize = WTS_SMALL, // water size (type) + + // internal -> do not use + 10 FLOAT m_fDamageAmount = 0.0f, // water hit damage + 11 FLOAT m_fIgnoreTime = 0.0f, // time when laucher will be ignored + 12 FLOAT m_fPushAwayFactor = 0.0f, // push away on hit + +{ + CLightSource m_lsLightSource; +} + + +components: + 1 class CLASS_LIGHT "Classes\\Light.ecl", + +// ********* WATER ********* + 10 model MODEL_WATER "Models\\Enemies\\Elementals\\Projectile\\WaterDrop.mdl", + 11 texture TEXTURE_WATER "Models\\Enemies\\Elementals\\WaterManFX.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + + + +functions: + /* Read from stream. */ + void Read_t( CTStream *istr) // throw char * + { + CRationalEntity::Read_t(istr); + SetupLightSource(); + }; + + /* Get static light source information. */ + CLightSource *GetLightSource(void) + { + if (!IsPredictor()) { + return &m_lsLightSource; + } else { + return NULL; + } + }; + + // Setup light source + void SetupLightSource(void) + { + // setup light source + CLightSource lsNew; + lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC; + lsNew.ls_colColor = C_lBLUE; + lsNew.ls_rFallOff = 1.0f; + lsNew.ls_rHotSpot = 0.2f; + lsNew.ls_plftLensFlare = NULL; + lsNew.ls_ubPolygonalMask = 0; + lsNew.ls_paoLightAnimation = NULL; + + m_lsLightSource.ls_penEntity = this; + m_lsLightSource.SetLightSource(lsNew); + }; + + // render particles + void RenderParticles(void) { + }; + + + // water touch his valid target + void WaterTouch(CEntityPointer penHit) { + // direct damage + FLOAT3D vDirection; + AnglesToDirectionVector(GetPlacement().pl_OrientationAngle, vDirection); + InflictDirectDamage(penHit, m_penLauncher, DMT_PROJECTILE, m_fDamageAmount, + GetPlacement().pl_PositionVector, vDirection); + // push target away + FLOAT3D vSpeed; + GetHeadingDirection(0.0f, vSpeed); + vSpeed = vSpeed * m_fPushAwayFactor; + KickEntity(penHit, vSpeed); + }; + + + +/************************************************************ + * P R O C E D U R E S * + ************************************************************/ +procedures: + // --->>> PROJECTILE SLIDE ON BRUSH + WaterFly(EVoid) { + // fly loop + wait(FLY_TIME) { + on (EBegin) : { resume; } + on (EPass epass) : { + BOOL bHit; + // ignore launcher within 1 second + bHit = epass.penOther!=m_penLauncher || _pTimer->CurrentTick()>m_fIgnoreTime; + // ignore water + bHit &= !(IsOfClass(epass.penOther, "Water")); + if (bHit) { + WaterTouch(epass.penOther); + stop; + } + resume; + } + on (ETouch etouch) : { + // clear time limit for launcher + m_fIgnoreTime = 0.0f; + // ignore brushes + BOOL bHit; + bHit = !(etouch.penOther->GetRenderType() & RT_BRUSH); + // ignore another projectile of same type + bHit &= !(IsOfClass(etouch.penOther, "Water")); + if (bHit) { + WaterTouch(etouch.penOther); + stop; + } + // water is moving to slow (stuck somewhere) -> kill it + if (en_vCurrentTranslationAbsolute.Length() < 0.25f*en_vDesiredTranslationRelative.Length()) { + stop; + } + resume; + } + on (EDeath) : { stop; } + on (ETimer) : { stop; } + } + return EEnd(); + }; + + + // --->>> MAIN + Main(EWater ew) { + // remember the initial parameters + ASSERT(ew.penLauncher!=NULL); + m_penLauncher = ew.penLauncher; + m_EwsSize = ew.EwsSize; + + // initialization + InitAsModel(); + SetPhysicsFlags(EPF_ONBLOCK_SLIDE|EPF_PUSHABLE|EPF_MOVABLE); + SetCollisionFlags(ECF_PROJECTILE_MAGIC); + SetComponents(this, *GetModelObject(), MODEL_WATER, TEXTURE_WATER, 0, TEX_SPEC_STRONG, 0); + + // setup + switch(m_EwsSize) { + case WTS_SMALL: + m_fDamageAmount = 10.0f; + m_fPushAwayFactor = 10.0f; + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -30.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + break; + case WTS_BIG: + m_fDamageAmount = 20.0f; + m_fPushAwayFactor = 20.0f; + GetModelObject()->StretchModel(FLOAT3D(4.0f, 4.0f, 4.0f)); + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -50.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + break; + case WTS_LARGE: + m_fDamageAmount = 40.0f; + m_fPushAwayFactor = 40.0f; + GetModelObject()->StretchModel(FLOAT3D(16.0f, 16.0f, 16.0f)); + LaunchAsPropelledProjectile(FLOAT3D(0.0f, 0.0f, -80.0f), (CMovableEntity*)(CEntity*)m_penLauncher); + break; + } + ModelChangeNotify(); + + // setup light source + SetupLightSource(); + + // remember lauching time + m_fIgnoreTime = _pTimer->CurrentTick() + 1.0f; + + // fly + autocall WaterFly() EEnd; + + // cease to exist + Destroy(); + + return; + } +}; diff --git a/Sources/Entities/WeaponItem.es b/Sources/Entities/WeaponItem.es new file mode 100644 index 0000000..08071f3 --- /dev/null +++ b/Sources/Entities/WeaponItem.es @@ -0,0 +1,465 @@ +802 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Items/ItemHolder/ItemHolder.h" +#include "Models/Weapons/Colt/ColtItem.h" +#include "Models/Weapons/SingleShotgun/SingleShotgunItem.h" +#include "Models/Weapons/DoubleShotgun/DoubleShotgunItem.h" +#include "Models/Weapons/TommyGun/TommyGunItem.h" +#include "Models/Weapons/MiniGun/MiniGunItem.h" +#include "Models/Weapons/GrenadeLauncher/GrenadeLauncherItem.h" +#include "Models/Weapons/RocketLauncher/RocketLauncherItem.h" +//#include "Models/Weapons/Pipebomb/StickItem.h" +//#include "Models/Weapons/Flamer/FlamerItem.h" +#include "Models/Weapons/Laser/LaserItem.h" +//#include "Models/Weapons/GhostBuster/GhostBusterItem.h" +//#include "Models/Weapons/GhostBuster/Effect01.h" +#include "Models/Weapons/Cannon/Cannon.h" + +#include "Entities/PlayerWeapons.h" +%} + +uses "Entities/Item"; + +// health type +enum WeaponItemType { + 1 WIT_COLT "Colt", + 2 WIT_SINGLESHOTGUN "Single shotgun", + 3 WIT_DOUBLESHOTGUN "Double shotgun", + 4 WIT_TOMMYGUN "Tommygun", + 5 WIT_MINIGUN "Minigun", + 6 WIT_ROCKETLAUNCHER "Rocket launcher", + 7 WIT_GRENADELAUNCHER "Grenade launcher", + 8 WIT_PIPEBOMB "obsolete", + 9 WIT_FLAMER "obsolete", + 10 WIT_LASER "Laser", + 11 WIT_GHOSTBUSTER "obsolete", + 12 WIT_CANNON "Cannon", +}; + +// event for sending through receive item +event EWeaponItem { + INDEX iWeapon, // weapon collected + INDEX iAmmo, // weapon ammo (used only for leaving weapons, -1 for deafult ammount) + BOOL bDropped, // for dropped weapons (can be picked even if weapons stay) +}; + +%{ +extern void CPlayerWeapons_Precache(ULONG ulAvailable); +%} + + +class CWeaponItem : CItem { +name "Weapon Item"; +thumbnail "Thumbnails\\WeaponItem.tbn"; + +properties: + 1 enum WeaponItemType m_EwitType "Type" 'Y' = WIT_COLT, // weapon + +components: + 0 class CLASS_BASE "Classes\\Item.ecl", + +// ************** COLT ************** + 30 model MODEL_COLT "Models\\Weapons\\Colt\\ColtItem.mdl", + 31 model MODEL_COLTCOCK "Models\\Weapons\\Colt\\ColtCock.mdl", + 32 model MODEL_COLTMAIN "Models\\Weapons\\Colt\\ColtMain.mdl", + 33 model MODEL_COLTBULLETS "Models\\Weapons\\Colt\\ColtBullets.mdl", + 34 texture TEXTURE_COLTMAIN "Models\\Weapons\\Colt\\ColtMain.tex", + 35 texture TEXTURE_COLTCOCK "Models\\Weapons\\Colt\\ColtCock.tex", + 36 texture TEXTURE_COLTBULLETS "Models\\Weapons\\Colt\\ColtBullets.tex", + +// ************** SINGLE SHOTGUN ************ + 40 model MODEL_SINGLESHOTGUN "Models\\Weapons\\SingleShotgun\\SingleShotgunItem.mdl", + 41 model MODEL_SS_SLIDER "Models\\Weapons\\SingleShotgun\\Slider.mdl", + 42 model MODEL_SS_HANDLE "Models\\Weapons\\SingleShotgun\\Handle.mdl", + 43 model MODEL_SS_BARRELS "Models\\Weapons\\SingleShotgun\\Barrels.mdl", + 44 texture TEXTURE_SS_HANDLE "Models\\Weapons\\SingleShotgun\\Handle.tex", + 45 texture TEXTURE_SS_BARRELS "Models\\Weapons\\SingleShotgun\\Barrels.tex", + +// ************** DOUBLE SHOTGUN ************** + 50 model MODEL_DOUBLESHOTGUN "Models\\Weapons\\DoubleShotgun\\DoubleShotgunItem.mdl", + 51 model MODEL_DS_HANDLE "Models\\Weapons\\DoubleShotgun\\Dshotgunhandle.mdl", + 52 model MODEL_DS_BARRELS "Models\\Weapons\\DoubleShotgun\\Dshotgunbarrels.mdl", + 54 model MODEL_DS_SWITCH "Models\\Weapons\\DoubleShotgun\\Switch.mdl", + 56 texture TEXTURE_DS_HANDLE "Models\\Weapons\\DoubleShotgun\\Handle.tex", + 57 texture TEXTURE_DS_BARRELS "Models\\Weapons\\DoubleShotgun\\Barrels.tex", + 58 texture TEXTURE_DS_SWITCH "Models\\Weapons\\DoubleShotgun\\Switch.tex", + +// ************** TOMMYGUN ************** + 70 model MODEL_TOMMYGUN "Models\\Weapons\\TommyGun\\TommyGunItem.mdl", + 71 model MODEL_TG_BODY "Models\\Weapons\\TommyGun\\Body.mdl", + 72 model MODEL_TG_SLIDER "Models\\Weapons\\TommyGun\\Slider.mdl", + 73 texture TEXTURE_TG_BODY "Models\\Weapons\\TommyGun\\Body.tex", + +// ************** MINIGUN ************** + 80 model MODEL_MINIGUN "Models\\Weapons\\MiniGun\\MiniGunItem.mdl", + 81 model MODEL_MG_BARRELS "Models\\Weapons\\MiniGun\\Barrels.mdl", + 82 model MODEL_MG_BODY "Models\\Weapons\\MiniGun\\Body.mdl", + 83 model MODEL_MG_ENGINE "Models\\Weapons\\MiniGun\\Engine.mdl", + 84 texture TEXTURE_MG_BODY "Models\\Weapons\\MiniGun\\Body.tex", + 99 texture TEXTURE_MG_BARRELS "Models\\Weapons\\MiniGun\\Barrels.tex", + +// ************** ROCKET LAUNCHER ************** + 90 model MODEL_ROCKETLAUNCHER "Models\\Weapons\\RocketLauncher\\RocketLauncherItem.mdl", + 91 model MODEL_RL_BODY "Models\\Weapons\\RocketLauncher\\Body.mdl", + 92 texture TEXTURE_RL_BODY "Models\\Weapons\\RocketLauncher\\Body.tex", + 93 model MODEL_RL_ROTATINGPART "Models\\Weapons\\RocketLauncher\\RotatingPart.mdl", + 94 texture TEXTURE_RL_ROTATINGPART "Models\\Weapons\\RocketLauncher\\RotatingPart.tex", + 95 model MODEL_RL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.mdl", + 96 texture TEXTURE_RL_ROCKET "Models\\Weapons\\RocketLauncher\\Projectile\\Rocket.tex", + +// ************** GRENADE LAUNCHER ************** +100 model MODEL_GRENADELAUNCHER "Models\\Weapons\\GrenadeLauncher\\GrenadeLauncherItem.mdl", +101 model MODEL_GL_BODY "Models\\Weapons\\GrenadeLauncher\\Body.mdl", +102 model MODEL_GL_MOVINGPART "Models\\Weapons\\GrenadeLauncher\\MovingPipe.mdl", +103 model MODEL_GL_GRENADE "Models\\Weapons\\GrenadeLauncher\\GrenadeBack.mdl", +104 texture TEXTURE_GL_BODY "Models\\Weapons\\GrenadeLauncher\\Body.tex", +105 texture TEXTURE_GL_MOVINGPART "Models\\Weapons\\GrenadeLauncher\\MovingPipe.tex", + +/* +// ************** PIPEBOMB ************** +110 model MODEL_PIPEBOMB_STICK "Models\\Weapons\\Pipebomb\\StickItem.mdl", +112 model MODEL_PB_BUTTON "Models\\Weapons\\Pipebomb\\Button.mdl", +113 model MODEL_PB_SHIELD "Models\\Weapons\\Pipebomb\\Shield.mdl", +114 model MODEL_PB_STICK "Models\\Weapons\\Pipebomb\\Stick.mdl", +116 texture TEXTURE_PB_STICK "Models\\Weapons\\Pipebomb\\Stick.tex", + +// ************** FLAMER ************** +130 model MODEL_FLAMER "Models\\Weapons\\Flamer\\FlamerItem.mdl", +131 model MODEL_FL_BODY "Models\\Weapons\\Flamer\\Body.mdl", +132 model MODEL_FL_RESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.mdl", +133 model MODEL_FL_FLAME "Models\\Weapons\\Flamer\\Flame.mdl", +134 texture TEXTURE_FL_BODY "Models\\Weapons\\Flamer\\Body.tex", +135 texture TEXTURE_FL_FLAME "Models\\Weapons\\Flamer\\Flame.tex", +136 texture TEXTURE_FL_FUELRESERVOIR "Models\\Weapons\\Flamer\\FuelReservoir.tex", +*/ +// ************** LASER ************** +140 model MODEL_LASER "Models\\Weapons\\Laser\\LaserItem.mdl", +141 model MODEL_LS_BODY "Models\\Weapons\\Laser\\Body.mdl", +142 model MODEL_LS_BARREL "Models\\Weapons\\Laser\\Barrel.mdl", +143 texture TEXTURE_LS_BODY "Models\\Weapons\\Laser\\Body.tex", +144 texture TEXTURE_LS_BARREL "Models\\Weapons\\Laser\\Barrel.tex", +/* +// ************** GHOSTBUSTER ************** +150 model MODEL_GHOSTBUSTER "Models\\Weapons\\GhostBuster\\GhostBusterItem.mdl", +151 model MODEL_GB_BODY "Models\\Weapons\\GhostBuster\\Body.mdl", +152 model MODEL_GB_ROTATOR "Models\\Weapons\\GhostBuster\\Rotator.mdl", +153 model MODEL_GB_EFFECT1 "Models\\Weapons\\GhostBuster\\Effect01.mdl", +154 model MODEL_GB_EFFECT1FLARE "Models\\Weapons\\GhostBuster\\EffectFlare01.mdl", +155 texture TEXTURE_GB_ROTATOR "Models\\Weapons\\GhostBuster\\Rotator.tex", +156 texture TEXTURE_GB_BODY "Models\\Weapons\\GhostBuster\\Body.tex", +157 texture TEXTURE_GB_LIGHTNING "Models\\Weapons\\GhostBuster\\Lightning.tex", +158 texture TEXTURE_GB_FLARE "Models\\Weapons\\GhostBuster\\EffectFlare.tex", +*/ +// ************** CANNON ************** +170 model MODEL_CANNON "Models\\Weapons\\Cannon\\Cannon.mdl", +171 model MODEL_CN_BODY "Models\\Weapons\\Cannon\\Body.mdl", +173 texture TEXTURE_CANNON "Models\\Weapons\\Cannon\\Body.tex", +//174 model MODEL_CN_NUKEBOX "Models\\Weapons\\Cannon\\NukeBox.mdl", +//175 model MODEL_CN_LIGHT "Models\\Weapons\\Cannon\\Light.mdl", + +// ************** FLARE FOR EFFECT ************** +190 texture TEXTURE_FLARE "Models\\Items\\Flares\\Flare.tex", +191 model MODEL_FLARE "Models\\Items\\Flares\\Flare.mdl", + +// ************** REFLECTIONS ************** +200 texture TEX_REFL_BWRIPLES01 "Models\\ReflectionTextures\\BWRiples01.tex", +201 texture TEX_REFL_BWRIPLES02 "Models\\ReflectionTextures\\BWRiples02.tex", +202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex", +203 texture TEX_REFL_LIGHTBLUEMETAL01 "Models\\ReflectionTextures\\LightBlueMetal01.tex", +204 texture TEX_REFL_DARKMETAL "Models\\ReflectionTextures\\DarkMetal.tex", +205 texture TEX_REFL_PURPLE01 "Models\\ReflectionTextures\\Purple01.tex", + +// ************** SPECULAR ************** +210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", +211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", +212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", + +// ************** SOUNDS ************** +213 sound SOUND_PICK "Sounds\\Items\\Weapon.wav", + +functions: + void Precache(void) { + PrecacheSound(SOUND_PICK); + switch (m_EwitType) { + case WIT_COLT: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_COLT )-1)); break; + case WIT_SINGLESHOTGUN: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_SINGLESHOTGUN )-1)); break; + case WIT_DOUBLESHOTGUN: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_DOUBLESHOTGUN )-1)); break; + case WIT_TOMMYGUN: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_TOMMYGUN )-1)); break; + case WIT_MINIGUN: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_MINIGUN )-1)); break; + case WIT_ROCKETLAUNCHER: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_ROCKETLAUNCHER )-1)); break; + case WIT_GRENADELAUNCHER: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_GRENADELAUNCHER)-1)); break; +// case WIT_PIPEBOMB: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_PIPEBOMB )-1)); break; +// case WIT_FLAMER: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_FLAMER )-1)); break; + case WIT_LASER: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_LASER )-1)); break; +// case WIT_GHOSTBUSTER: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_GHOSTBUSTER )-1)); break; + case WIT_CANNON: CPlayerWeapons_Precache(1<<(INDEX(WEAPON_IRONCANNON )-1)); break; + } + } + /* Fill in entity statistics - for AI purposes only */ + BOOL FillEntityStatistics(EntityStats *pes) + { + pes->es_strName = m_strDescription; + pes->es_ctCount = 1; + pes->es_ctAmmount = 1; + pes->es_fValue = 1; + pes->es_iScore = 0;//m_iScore; + return TRUE; + } + + // render particles + void RenderParticles(void) { + // no particles when not existing or in DM modes + if (GetRenderType()!=CEntity::RT_MODEL || GetSP()->sp_gmGameMode>CSessionProperties::GM_COOPERATIVE + || !ShowItemParticles()) + { + return; + } + switch (m_EwitType) { + case WIT_COLT: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_SINGLESHOTGUN: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_DOUBLESHOTGUN: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_TOMMYGUN: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_MINIGUN: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_ROCKETLAUNCHER: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_GRENADELAUNCHER: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_PIPEBOMB: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_FLAMER: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_LASER: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_GHOSTBUSTER: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + case WIT_CANNON: Particles_Atomic(this, 1.5f, 1.5f, PT_STAR07, 12); break; + } + } + + + // set weapon properties depending on weapon type + void SetProperties(void) + { + BOOL bDM = FALSE;//m_bRespawn || m_bDropped; + FLOAT3D vDMStretch = FLOAT3D( 2.0f, 2.0f, 2.0f); + + switch (m_EwitType) { + // *********** COLT *********** + case WIT_COLT: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Colt"); + AddItem(MODEL_COLT, TEXTURE_COLTMAIN, 0, 0, 0); + AddItemAttachment(COLTITEM_ATTACHMENT_BULLETS, MODEL_COLTBULLETS, TEXTURE_COLTBULLETS, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(COLTITEM_ATTACHMENT_COCK, MODEL_COLTCOCK, TEXTURE_COLTCOCK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(COLTITEM_ATTACHMENT_BODY, MODEL_COLTMAIN, TEXTURE_COLTMAIN, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : FLOAT3D(4.5f, 4.5f, 4.5f)); + break; + + // *********** SINGLE SHOTGUN *********** + case WIT_SINGLESHOTGUN: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Single Shotgun"); + AddItem(MODEL_SINGLESHOTGUN, TEXTURE_SS_HANDLE, 0, 0, 0); + AddItemAttachment(SINGLESHOTGUNITEM_ATTACHMENT_BARRELS, MODEL_SS_BARRELS, TEXTURE_SS_BARRELS, TEX_REFL_DARKMETAL, TEX_SPEC_WEAK, 0); + AddItemAttachment(SINGLESHOTGUNITEM_ATTACHMENT_HANDLE, MODEL_SS_HANDLE, TEXTURE_SS_HANDLE, TEX_REFL_DARKMETAL, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(SINGLESHOTGUNITEM_ATTACHMENT_SLIDER, MODEL_SS_SLIDER, TEXTURE_SS_BARRELS, TEX_REFL_DARKMETAL, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(3.5f, 3.5f, 3.5f)) ); + break; + + // *********** DOUBLE SHOTGUN *********** + case WIT_DOUBLESHOTGUN: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Double Shotgun"); + AddItem(MODEL_DOUBLESHOTGUN, TEXTURE_DS_HANDLE, 0, 0, 0); + AddItemAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_BARRELS, MODEL_DS_BARRELS, TEXTURE_DS_BARRELS, TEX_REFL_BWRIPLES01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_HANDLE, MODEL_DS_HANDLE, TEXTURE_DS_HANDLE, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(DOUBLESHOTGUNITEM_ATTACHMENT_SWITCH, MODEL_DS_SWITCH, TEXTURE_DS_SWITCH, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(3.0f, 3.0f, 3.0f))); + break; + + + // *********** TOMMYGUN *********** + case WIT_TOMMYGUN: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Tommygun"); + AddItem(MODEL_TOMMYGUN, TEXTURE_TG_BODY, 0, 0, 0); + AddItemAttachment(TOMMYGUNITEM_ATTACHMENT_BODY, MODEL_TG_BODY, TEXTURE_TG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(TOMMYGUNITEM_ATTACHMENT_SLIDER, MODEL_TG_SLIDER, TEXTURE_TG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(3.0f, 3.0f, 3.0f))); + break; + + // *********** MINIGUN *********** + case WIT_MINIGUN: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Minigun"); + AddItem(MODEL_MINIGUN, TEXTURE_MG_BODY, 0, 0, 0); + AddItemAttachment(MINIGUNITEM_ATTACHMENT_BARRELS, MODEL_MG_BARRELS, TEXTURE_MG_BARRELS, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(MINIGUNITEM_ATTACHMENT_BODY, MODEL_MG_BODY, TEXTURE_MG_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(MINIGUNITEM_ATTACHMENT_ENGINE, MODEL_MG_ENGINE, TEXTURE_MG_BARRELS, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(1.75f, 1.75f, 1.75f))); + break; + + // *********** ROCKET LAUNCHER *********** + case WIT_ROCKETLAUNCHER: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Rocket launcher"); + AddItem(MODEL_ROCKETLAUNCHER, TEXTURE_RL_BODY, 0, 0, 0); + AddItemAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_BODY, MODEL_RL_BODY, TEXTURE_RL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROTATINGPART, MODEL_RL_ROTATINGPART, TEXTURE_RL_ROTATINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET1, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET2, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET3, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(ROCKETLAUNCHERITEM_ATTACHMENT_ROCKET4, MODEL_RL_ROCKET, TEXTURE_RL_ROCKET, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(2.5f, 2.5f, 2.5f))); + break; + + // *********** GRENADE LAUNCHER *********** + case WIT_GRENADELAUNCHER: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Grenade launcher"); + AddItem(MODEL_GRENADELAUNCHER, TEXTURE_GL_BODY, 0, 0, 0); + AddItemAttachment(GRENADELAUNCHERITEM_ATTACHMENT_BODY, MODEL_GL_BODY, TEXTURE_GL_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(GRENADELAUNCHERITEM_ATTACHMENT_MOVING_PART, MODEL_GL_MOVINGPART, TEXTURE_GL_MOVINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(GRENADELAUNCHERITEM_ATTACHMENT_GRENADE, MODEL_GL_GRENADE, TEXTURE_GL_MOVINGPART, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(2.5f, 2.5f, 2.5f))); + break; + +/* + // *********** PIPEBOMB *********** + case WIT_PIPEBOMB: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Pipebomb"); + AddItem(MODEL_PIPEBOMB_STICK, TEXTURE_PB_STICK, 0, 0, 0); + AddItemAttachment(STICKITEM_ATTACHMENT_STICK, MODEL_PB_STICK, + TEXTURE_PB_STICK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(STICKITEM_ATTACHMENT_SHIELD, MODEL_PB_SHIELD, + TEXTURE_PB_STICK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(STICKITEM_ATTACHMENT_BUTTON, MODEL_PB_BUTTON, + TEXTURE_PB_STICK, TEX_REFL_LIGHTBLUEMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(6.0f, 6.0f, 6.0f))); + break; + + // *********** FLAMER *********** + case WIT_FLAMER: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Flamer"); + AddItem(MODEL_FLAMER, TEXTURE_FL_BODY, 0, 0, 0); + AddItemAttachment(FLAMERITEM_ATTACHMENT_BODY, MODEL_FL_BODY, + TEXTURE_FL_BODY, TEX_REFL_BWRIPLES02, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(FLAMERITEM_ATTACHMENT_FUEL, MODEL_FL_RESERVOIR, + TEXTURE_FL_FUELRESERVOIR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(FLAMERITEM_ATTACHMENT_FLAME, MODEL_FL_FLAME, + TEXTURE_FL_FLAME, 0, 0, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(2.5f, 2.5f, 2.5f))); + break; +*/ + // *********** LASER *********** + case WIT_LASER: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("Laser"); + AddItem(MODEL_LASER, TEXTURE_LS_BODY, 0, 0, 0); + AddItemAttachment(LASERITEM_ATTACHMENT_BODY, MODEL_LS_BODY, TEXTURE_LS_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(LASERITEM_ATTACHMENT_LEFTUP, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(LASERITEM_ATTACHMENT_LEFTDOWN, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(LASERITEM_ATTACHMENT_RIGHTUP, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(LASERITEM_ATTACHMENT_RIGHTDOWN, MODEL_LS_BARREL, TEXTURE_LS_BARREL, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(2.5f, 2.5f, 2.5f))); + break; +/* + // *********** GHOSTBUSTER *********** + case WIT_GHOSTBUSTER: + m_fRespawnTime = 10.0f; + m_strDescription.PrintF("GhostBuster"); + AddItem(MODEL_GHOSTBUSTER, TEXTURE_GB_BODY, 0, 0, 0); + AddItemAttachment(GHOSTBUSTERITEM_ATTACHMENT_BODY, MODEL_GB_BODY, TEXTURE_GB_BODY, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(GHOSTBUSTERITEM_ATTACHMENT_ROTATOR, MODEL_GB_ROTATOR, TEXTURE_GB_ROTATOR, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + AddItemAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT01, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddItemAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT02, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddItemAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT03, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + AddItemAttachment(GHOSTBUSTERITEM_ATTACHMENT_EFFECT04, MODEL_GB_EFFECT1, TEXTURE_GB_LIGHTNING, 0, 0, 0); + CModelObject *pmoMain, *pmo; + pmoMain = &(GetModelObject()->GetAttachmentModel(ITEMHOLDER_ATTACHMENT_ITEM)->amo_moModelObject); + pmo = &(pmoMain->GetAttachmentModel(GHOSTBUSTERITEM_ATTACHMENT_EFFECT01)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmo = &(pmoMain->GetAttachmentModel(GHOSTBUSTERITEM_ATTACHMENT_EFFECT02)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmo = &(pmoMain->GetAttachmentModel(GHOSTBUSTERITEM_ATTACHMENT_EFFECT03)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + pmo = &(pmoMain->GetAttachmentModel(GHOSTBUSTERITEM_ATTACHMENT_EFFECT04)->amo_moModelObject); + AddAttachmentToModel(this, *pmo, EFFECT01_ATTACHMENT_FLARE, MODEL_GB_EFFECT1FLARE, TEXTURE_GB_FLARE, 0, 0, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(3.25f, 3.25f, 3.25f))); + break; + */ + + // *********** CANNON *********** + case WIT_CANNON: + m_fRespawnTime = 30.0f; + m_strDescription.PrintF("Cannon"); + AddItem(MODEL_CANNON, TEXTURE_CANNON, 0, 0, 0); + AddItemAttachment(CANNON_ATTACHMENT_BODY, MODEL_CN_BODY, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); +// AddItemAttachment(CANNON_ATTACHMENT_NUKEBOX, MODEL_CN_NUKEBOX, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); +// AddItemAttachment(CANNON_ATTACHMENT_LIGHT, MODEL_CN_LIGHT, TEXTURE_CANNON, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0); + StretchItem( bDM ? vDMStretch : (FLOAT3D(3.0f, 3.0f, 3.0f))); + break; + } + // add flare + AddFlare(MODEL_FLARE, TEXTURE_FLARE, FLOAT3D(0,0.6f,0), FLOAT3D(3,3,0.3f) ); +}; + +procedures: + ItemCollected(EPass epass) : CItem::ItemCollected { + ASSERT(epass.penOther!=NULL); + + // if weapons stays + if (GetSP()->sp_bWeaponsStay && !m_bPickupOnce) { + // if already picked by this player + BOOL bWasPicked = MarkPickedBy(epass.penOther); + if (bWasPicked) { + // don't pick again + return; + } + } + + // send weapon to entity + EWeaponItem eWeapon; + eWeapon.iWeapon = m_EwitType; + eWeapon.iAmmo = -1; // use default ammo amount + eWeapon.bDropped = m_bDropped; + // if weapon is received + if (epass.penOther->ReceiveItem(eWeapon)) { + // play the pickup sound + if(_pNetwork->IsPlayerLocal(epass.penOther)) {IFeel_PlayEffect("PU_Weapon");} + m_soPick.Set3DParameters(50.0f, 1.0f, 1.0f, 1.0f); + PlaySound(m_soPick, SOUND_PICK, SOF_3D); + m_fPickSoundLen = GetSoundLength(SOUND_PICK); + if (!GetSP()->sp_bWeaponsStay || m_bDropped || m_bPickupOnce) { + jump CItem::ItemReceived(); + } + } + return; + }; + + Main() + { + if (m_EwitType==WIT_PIPEBOMB|| + m_EwitType==WIT_FLAMER|| + m_EwitType==WIT_GHOSTBUSTER) { + m_EwitType=WIT_LASER; + } + + Initialize(); // initialize base class + StartModelAnim(ITEMHOLDER_ANIM_BIGOSCILATION, AOF_LOOPING|AOF_NORESTART); + ForceCollisionBoxIndexChange(ITEMHOLDER_COLLISION_BOX_BIG); + SetProperties(); // set properties + + if (!m_bDropped) { + jump CItem::ItemLoop(); + } else if (TRUE) { + wait() { + on (EBegin) : { + SpawnReminder(this, m_fRespawnTime, 0); + call CItem::ItemLoop(); + } + on (EReminder) : { + SendEvent(EEnd()); + resume; + } + } + } + }; +}; diff --git a/Sources/Entities/Werebull.es b/Sources/Entities/Werebull.es new file mode 100644 index 0000000..8b0efc8 --- /dev/null +++ b/Sources/Entities/Werebull.es @@ -0,0 +1,318 @@ +307 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/WereBull/WereBull.h" +%} + +uses "Entities/EnemyBase"; +uses "Entities/EnemyRunInto"; + +enum BullChar { + 0 BUC_SUMMER "Summer", + 1 BUC_WINTER "Winter", +}; + +%{ +// info structure +static EntityInfo eiWerebull = { + EIBT_FLESH, 500.0f, + 0.0f, 3.0f, 0.0f, // source (eyes) + 0.0f, 1.5f, 0.0f, // target (body) +}; + +#define HIT_DISTANCE 5.0f +%} + + +class CWerebull : CEnemyRunInto { +name "Werebull"; +thumbnail "Thumbnails\\Werebull.tbn"; + +properties: + 1 BOOL m_bRunAttack = FALSE, // run attack (attack local) + 2 BOOL m_bHornHit = FALSE, // close attack local + 3 CEntityPointer m_penLastTouched, // last touched + 4 CSoundObject m_soFeet, // for running sound + 5 BOOL m_bRunSoundPlaying = FALSE, +// 6 enum BullChar m_bcChar "Character" 'C' = BUC_SUMMER, // character + +components: + 0 class CLASS_BASE "Classes\\EnemyRunInto.ecl", + 1 model MODEL_WEREBULL "Models\\Enemies\\Werebull\\Werebull.mdl", + 2 texture TEXTURE_WEREBULL_SUMMER "Models\\Enemies\\Werebull\\Werebull.tex", +// 3 texture TEXTURE_WEREBULL_WINTER "Models\\Enemies\\Werebull\\Werebull2.tex", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Werebull\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Werebull\\Sounds\\Sight.wav", + 53 sound SOUND_KICKHORN "Models\\Enemies\\Werebull\\Sounds\\KickHorn.wav", + 54 sound SOUND_IMPACT "Models\\Enemies\\Werebull\\Sounds\\Impact.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Werebull\\Sounds\\Death.wav", + 56 sound SOUND_RUN "Models\\Enemies\\Werebull\\Sounds\\Run.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + str.PrintF(TRANS("Sirian werebull sent %s flying"), (const char*)strPlayerName); + return str; + } + + void Precache(void) { + CEnemyBase::Precache(); + PrecacheSound(SOUND_IDLE ); + PrecacheSound(SOUND_SIGHT ); + PrecacheSound(SOUND_KICKHORN); + PrecacheSound(SOUND_IMPACT ); + PrecacheSound(SOUND_DEATH ); + PrecacheSound(SOUND_RUN ); + }; + + /* Entity info */ + void *GetEntityInfo(void) { + return &eiWerebull; + }; + + FLOAT GetCrushHealth(void) + { + return 60.0f; + } + + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Bull.txt"); + return fnm; + }; + + // render particles + void RenderParticles(void) + { + Particles_RunningDust(this); + CEnemyBase::RenderParticles(); + } + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // werebull can't harm werebull + if (!IsOfClass(penInflictor, "Werebull")) { + CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + void AdjustDifficulty(void) + { + // bull must not change its speed at different difficulties + } + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + if (en_vCurrentTranslationAbsolute.Length()>5.0f) { + iAnim = WEREBULL_ANIM_DEATHRUN; + } else { + iAnim = WEREBULL_ANIM_DEATH; + } + StartModelAnim(iAnim, 0); + DeactivateRunningSound(); + return iAnim; + }; + + void DeathNotify() { + ChangeCollisionBoxIndexWhenPossible(WEREBULL_COLLISION_BOX_DEATH); + SetCollisionFlags(ECF_MODEL); + }; + + // virtual anim functions + void StandingAnim(void) { + StartModelAnim(WEREBULL_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART); + DeactivateRunningSound(); + }; + void WalkingAnim(void) { + StartModelAnim(WEREBULL_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); + DeactivateRunningSound(); + }; + void RunningAnim(void) { + StartModelAnim(WEREBULL_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + ActivateRunningSound(); + }; + void RotatingAnim(void) { + StartModelAnim(WEREBULL_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); + //DeactivateRunningSound(); + ActivateRunningSound(); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + + // running sounds + void ActivateRunningSound(void) + { + if (!m_bRunSoundPlaying) { + PlaySound(m_soFeet, SOUND_RUN, SOF_3D|SOF_LOOP); + m_bRunSoundPlaying = TRUE; + } + } + void DeactivateRunningSound(void) + { + m_soFeet.Stop(); + m_bRunSoundPlaying = FALSE; + } + + +/************************************************************ + * ATTACK FUNCTIONS * + ************************************************************/ + // touched another live entity + void LiveEntityTouched(ETouch etouch) { + if (m_penLastTouched!=etouch.penOther || _pTimer->CurrentTick()>=m_fLastTouchedTime+0.25f) { + // hit angle + FLOAT3D vDirection = en_vCurrentTranslationAbsolute; + vDirection.Normalize(); + ANGLE aHitAngle = FLOAT3D(etouch.plCollision)%vDirection; + // only hit target in front of you + if (aHitAngle < 0.0f) { + // increase mass - only if not another bull + if (!IsOfSameClass(this, etouch.penOther)) { + IncreaseKickedMass(etouch.penOther); + } + PlaySound(m_soSound, SOUND_IMPACT, SOF_3D); + // store last touched + m_penLastTouched = etouch.penOther; + m_fLastTouchedTime = _pTimer->CurrentTick(); + // damage + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(etouch.penOther, this, DMT_CLOSERANGE, -aHitAngle*40.0f, + FLOAT3D(0, 0, 0), vDirection); + // kick touched entity + FLOAT3D vSpeed = -FLOAT3D(etouch.plCollision); + vSpeed = vSpeed*10.0f; + const FLOATmatrix3D &m = GetRotationMatrix(); + FLOAT3D vSpeedRel = vSpeed*!m; + if (vSpeedRel(1)<-0.1f) { + vSpeedRel(1)-=15.0f; + } else { + vSpeedRel(1)+=15.0f; + } + vSpeedRel(2)=15.0f; + + vSpeed = vSpeedRel*m; + KickEntity(etouch.penOther, vSpeed); + } + } + }; + + // touched entity with higher mass + BOOL HigherMass(void) { + return (m_fMassKicked > 500.0f); + }; + + // adjust sound and watcher parameters here if needed + void EnemyPostInit(void) + { + // set sound default parameters + m_soFeet.Set3DParameters(500.0f, 50.0f, 1.0f, 1.0f); + m_bRunSoundPlaying = FALSE; + m_soSound.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f); + }; + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + // hit enemy + Hit(EVoid) : CEnemyBase::Hit { + if (CalcDist(m_penEnemy) < HIT_DISTANCE) { + // attack with horns + StartModelAnim(WEREBULL_ANIM_ATTACKHORNS, 0); + DeactivateRunningSound(); + m_bHornHit = FALSE; + autowait(0.4f); + PlaySound(m_soSound, SOUND_KICKHORN, SOF_3D); + if (CalcDist(m_penEnemy) < HIT_DISTANCE) { m_bHornHit = TRUE; } + autowait(0.1f); + if (CalcDist(m_penEnemy) < HIT_DISTANCE) { m_bHornHit = TRUE; } + autowait(0.1f); + if (CalcDist(m_penEnemy) < HIT_DISTANCE) { m_bHornHit = TRUE; } + if (m_bHornHit) { + FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; + vDirection.Normalize(); + InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 20.0f, FLOAT3D(0, 0, 0), vDirection); + FLOAT3D vSpeed; + GetPitchDirection(AngleDeg(90.0f), vSpeed); + vSpeed = vSpeed * 10.0f; + KickEntity(m_penEnemy, vSpeed); + } + } + + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.5f; + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(250.0f); + m_fMaxHealth = 250.0f; + en_fDensity = 2000.0f; + + // set your appearance + SetModel(MODEL_WEREBULL); +// if (m_bcChar==BUC_SUMMER) { + SetModelMainTexture(TEXTURE_WEREBULL_SUMMER); +// } else { +// SetModelMainTexture(TEXTURE_WEREBULL_WINTER); +// } + StandingAnim(); + // setup moving speed + m_fWalkSpeed = FRnd() + 2.5f; + m_aWalkRotateSpeed = AngleDeg(FRnd()*25.0f + 45.0f); + m_fAttackRunSpeed = FRnd()*5.0f + 22.5f; + m_fAttackRotateRunInto = AngleDeg(FRnd()*60 + 100.0f); + m_aAttackRotateSpeed = m_fAttackRotateRunInto; + m_fCloseRunSpeed = FRnd()*5.0f + 15.0f; + m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 500.0f); + // setup attack distances + m_fAttackDistance = 100.0f; + m_fCloseDistance = 7.0f; + m_fStopDistance = 0.0f; + m_fAttackFireTime = 0.05f; + m_fCloseFireTime = 1.0f; + m_fIgnoreRange = 250.0f; + // damage/explode properties + m_fBlowUpAmount = 1E10f; + m_fBodyParts = 12; + m_fDamageWounded = 100000.0f; + m_iScore = 2000; + if (m_fStepHeight==-1) { + m_fStepHeight = 4.0f; + } + + Particles_RunningDust_Prepare(this); + + // continue behavior in base class + jump CEnemyRunInto::MainLoop(); + }; +}; diff --git a/Sources/Entities/Woman.es b/Sources/Entities/Woman.es new file mode 100644 index 0000000..d10ffaa --- /dev/null +++ b/Sources/Entities/Woman.es @@ -0,0 +1,341 @@ +320 +%{ +#include "Entities/StdH/StdH.h" +#include "Models/Enemies/Woman/Woman.h" +%} + +uses "Entities/EnemyFly"; + +%{ +// info structure +static EntityInfo eiWomanStand = { + EIBT_FLESH, 100.0f, + 0.0f, 1.55f, 0.0f, + 0.0f, 1.0f, 0.0f, +}; +static EntityInfo eiWomanFly = { + EIBT_FLESH, 80.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; + +#define FIRE_AIR FLOAT3D(0.0f, 0.25f, -0.65f) +#define FIRE_GROUND FLOAT3D(0.0f, 1.3f, -0.5f) +%} + + +class CWoman : CEnemyFly { +name "Woman"; +thumbnail "Thumbnails\\Woman.tbn"; + +properties: +components: + 0 class CLASS_BASE "Classes\\EnemyFly.ecl", + 1 model MODEL_WOMAN "Models\\Enemies\\Woman\\Woman.mdl", + 2 texture TEXTURE_WOMAN "Models\\Enemies\\Woman\\Woman.tex", + 3 class CLASS_PROJECTILE "Classes\\Projectile.ecl", + +// ************** SOUNDS ************** + 50 sound SOUND_IDLE "Models\\Enemies\\Woman\\Sounds\\Idle.wav", + 51 sound SOUND_SIGHT "Models\\Enemies\\Woman\\Sounds\\Sight.wav", + 52 sound SOUND_WOUND "Models\\Enemies\\Woman\\Sounds\\Wound.wav", + 53 sound SOUND_FIRE "Models\\Enemies\\Woman\\Sounds\\Fire.wav", + 54 sound SOUND_KICK "Models\\Enemies\\Woman\\Sounds\\Kick.wav", + 55 sound SOUND_DEATH "Models\\Enemies\\Woman\\Sounds\\Death.wav", + +functions: + // describe how this enemy killed player + virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) + { + CTString str; + if (eDeath.eLastDamage.dmtType==DMT_CLOSERANGE) { + str.PrintF(TRANS("%s was beaten by a Scythian Harpy"), (const char*)strPlayerName); + } else { + str.PrintF(TRANS("A Scythian Harpy got %s spellbound"), (const char*)strPlayerName); + } + return str; + } + virtual const CTFileName &GetComputerMessageName(void) const { + static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Woman.txt"); + return fnm; + } + void Precache(void) { + CEnemyBase::Precache(); + PrecacheSound(SOUND_IDLE ); + PrecacheSound(SOUND_SIGHT); + PrecacheSound(SOUND_WOUND); + PrecacheSound(SOUND_FIRE ); + PrecacheSound(SOUND_KICK ); + PrecacheSound(SOUND_DEATH); + PrecacheClass(CLASS_PROJECTILE, PRT_WOMAN_FIRE); + }; + + /* Entity info */ + void *GetEntityInfo(void) { + if (m_bInAir) { + return &eiWomanFly; + } else { + return &eiWomanStand; + } + }; + + /* Receive damage */ + void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, + FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) + { + // woman can't harm woman + if (!IsOfClass(penInflictor, "Woman")) { + CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); + } + }; + + + // damage anim + INDEX AnimForDamage(FLOAT fDamage) { + INDEX iAnim; + if (m_bInAir) { + iAnim = WOMAN_ANIM_AIRWOUND02; + } else { + iAnim = WOMAN_ANIM_GROUNDWOUND04; + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + // death + INDEX AnimForDeath(void) { + INDEX iAnim; + if (m_bInAir) { + iAnim = WOMAN_ANIM_AIRDEATH; + } else { + iAnim = WOMAN_ANIM_GROUNDDEATH01; + } + StartModelAnim(iAnim, 0); + return iAnim; + }; + + void DeathNotify(void) { + ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_DEATH); + en_fDensity = 500.0f; + }; + + // virtual anim functions + void StandingAnim(void) { + if (m_bInAir) { + StartModelAnim(WOMAN_ANIM_AIRSTAND, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(WOMAN_ANIM_GROUNDSTAND, AOF_LOOPING|AOF_NORESTART); + } + }; + void WalkingAnim(void) { + if (m_bInAir) { + StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(WOMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); + } + }; + void RunningAnim(void) { + if (m_bInAir) { + StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(WOMAN_ANIM_GROUNDRUN, AOF_LOOPING|AOF_NORESTART); + } + }; + void RotatingAnim(void) { + if (m_bInAir) { + StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART); + } else { + StartModelAnim(WOMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); + } + }; + FLOAT AirToGroundAnim(void) { + StartModelAnim(WOMAN_ANIM_AIRTOGROUND, 0); + return(GetModelObject()->GetAnimLength(WOMAN_ANIM_AIRTOGROUND)); + }; + FLOAT GroundToAirAnim(void) { + StartModelAnim(WOMAN_ANIM_GROUNDTOAIR, 0); + return(GetModelObject()->GetAnimLength(WOMAN_ANIM_GROUNDTOAIR)); + }; + void ChangeCollisionToAir() { + ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_AIR); + }; + void ChangeCollisionToGround() { + ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_GROUND); + }; + + // virtual sound functions + void IdleSound(void) { + PlaySound(m_soSound, SOUND_IDLE, SOF_3D); + }; + void SightSound(void) { + PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); + }; + void WoundSound(void) { + PlaySound(m_soSound, SOUND_WOUND, SOF_3D); + }; + void DeathSound(void) { + PlaySound(m_soSound, SOUND_DEATH, SOF_3D); + }; + + +procedures: +/************************************************************ + * A T T A C K E N E M Y * + ************************************************************/ + FlyFire(EVoid) : CEnemyFly::FlyFire { + // fire projectile + StartModelAnim(WOMAN_ANIM_AIRATTACK02, 0); + autowait(0.6f); + ShootProjectile(PRT_WOMAN_FIRE, FIRE_AIR, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.6f); + StandingAnim(); + autowait(FRnd()/2 + _pTimer->TickQuantum); + + return EReturn(); + }; + + FlyHit(EVoid) : CEnemyFly::FlyHit { + // if enemy near + if (CalcDist(m_penEnemy) <= 5.0f) { + // if enemy is not in water + CMovableEntity *pen = (CMovableEntity *)&*m_penEnemy; + CContentType &ctDn = pen->en_pwoWorld->wo_actContentTypes[pen->en_iDnContent]; + BOOL bEnemySwimming = !(ctDn.ct_ulFlags&CTF_BREATHABLE_LUNGS); + if (bEnemySwimming) { + jump FlyFire(); + } else { + jump FlyOnEnemy(); + } + } + + // run to enemy + m_fShootTime = _pTimer->CurrentTick() + 0.25f; + return EReturn(); + }; + + FlyOnEnemy(EVoid) { + StartModelAnim(WOMAN_ANIM_AIRATTACK01, 0); + + // jump + FLOAT3D vDir = PlayerDestinationPos(); + vDir = (vDir - GetPlacement().pl_PositionVector).Normalize(); + vDir *= !GetRotationMatrix(); + vDir *= m_fFlyCloseRunSpeed*1.9f; + SetDesiredTranslation(vDir); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + + // animation - IGNORE DAMAGE WOUND - + SpawnReminder(this, 0.9f, 0); + m_iChargeHitAnimation = WOMAN_ANIM_AIRATTACK01; + m_fChargeHitDamage = 20.0f; + m_fChargeHitAngle = 0.0f; + m_fChargeHitSpeed = 10.0f; + autocall CEnemyBase::ChargeHitEnemy() EReturn; + + StandingAnim(); + autowait(0.3f); + return EReturn(); + } + + GroundFire(EVoid) : CEnemyFly::GroundFire { + // fire projectile + StartModelAnim(WOMAN_ANIM_GROUNDATTACK02, 0); + autowait(0.3f); + ShootProjectile(PRT_WOMAN_FIRE, FIRE_GROUND, ANGLE3D(0, 0, 0)); + PlaySound(m_soSound, SOUND_FIRE, SOF_3D); + autowait(0.3f); + StandingAnim(); + autowait(FRnd()/2 + _pTimer->TickQuantum); + + return EReturn(); + }; + + GroundHit(EVoid) : CEnemyFly::GroundHit { + StartModelAnim(WOMAN_ANIM_GROUNDATTACK01, 0); + + // jump + FLOAT3D vDir = (m_penEnemy->GetPlacement().pl_PositionVector - + GetPlacement().pl_PositionVector).Normalize(); + vDir *= !GetRotationMatrix(); + vDir *= m_fCloseRunSpeed*1.75f; + vDir(2) = 2.5f; + SetDesiredTranslation(vDir); + PlaySound(m_soSound, SOUND_KICK, SOF_3D); + + // animation - IGNORE DAMAGE WOUND - + SpawnReminder(this, 0.9f, 0); + m_iChargeHitAnimation = WOMAN_ANIM_GROUNDATTACK01; + m_fChargeHitDamage = 20.0f; + m_fChargeHitAngle = 0.0f; + m_fChargeHitSpeed = 10.0f; + autocall CEnemyBase::ChargeHitEnemy() EReturn; + + StandingAnim(); + autowait(0.3f); + return EReturn(); + }; + + + +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + // declare yourself as a model + InitAsModel(); + SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); + SetCollisionFlags(ECF_MODEL); + SetFlags(GetFlags()|ENF_ALIVE); + SetHealth(100.0f); + m_fMaxHealth = 100.0f; + en_tmMaxHoldBreath = 5.0f; + en_fDensity = 2000.0f; + + m_sptType = SPT_FEATHER; + + // set your appearance + SetModel(MODEL_WOMAN); + SetModelMainTexture(TEXTURE_WOMAN); + // setup moving speed + m_fWalkSpeed = FRnd() + 1.5f; + m_aWalkRotateSpeed = FRnd()*10.0f + 25.0f; + m_fAttackRunSpeed = FRnd()*2.0f + 9.0f; + m_aAttackRotateSpeed = FRnd()*50 + 245.0f; + m_fCloseRunSpeed = FRnd()*2.0f + 4.0f; + m_aCloseRotateSpeed = FRnd()*50 + 245.0f; + // setup attack distances + m_fAttackDistance = 50.0f; + m_fCloseDistance = 5.0f; + m_fStopDistance = 0.0f; + m_fAttackFireTime = 3.0f; + m_fCloseFireTime = 2.0f; + m_fIgnoreRange = 200.0f; + // fly moving properties + m_fFlyWalkSpeed = FRnd()/2 + 1.0f; + m_aFlyWalkRotateSpeed = FRnd()*10.0f + 25.0f; + m_fFlyAttackRunSpeed = FRnd()*2.0f + 10.0f; + m_aFlyAttackRotateSpeed = FRnd()*25 + 150.0f; + m_fFlyCloseRunSpeed = FRnd()*2.0f + 10.0f; + m_aFlyCloseRotateSpeed = FRnd()*50 + 500.0f; + m_fGroundToAirSpeed = m_fFlyCloseRunSpeed; + m_fAirToGroundSpeed = m_fFlyCloseRunSpeed; + m_fAirToGroundMin = 0.1f; + m_fAirToGroundMax = 0.1f; + // attack properties - CAN BE SET + m_fFlyAttackDistance = 50.0f; + m_fFlyCloseDistance = 12.5f; + m_fFlyStopDistance = 0.0f; + m_fFlyAttackFireTime = 3.0f; + m_fFlyCloseFireTime = 2.0f; + m_fFlyIgnoreRange = 200.0f; + // damage/explode properties + m_fBlowUpAmount = 100.0f; + m_fBodyParts = 4; + m_fDamageWounded = 20.0f; + m_iScore = 1000; + + // continue behavior in base class + jump CEnemyFly::MainLoop(); + }; +}; diff --git a/Sources/Entities/WorldBase.es b/Sources/Entities/WorldBase.es new file mode 100644 index 0000000..b7abc26 --- /dev/null +++ b/Sources/Entities/WorldBase.es @@ -0,0 +1,1247 @@ +100 +%{ +#include "Entities/StdH/StdH.h" +#include "Entities/BackgroundViewer.h" +#include "Entities/WorldSettingsController.h" + +#ifdef PLATFORM_UNIX +#define EAX_ENVIRONMENT_LIVINGROOM 0 +#define EAX_ENVIRONMENT_STONEROOM 0 +#define EAX_ENVIRONMENT_AUDITORIUM 0 +#define EAX_ENVIRONMENT_HALLWAY 0 +#define EAX_ENVIRONMENT_ARENA 0 +#define EAX_ENVIRONMENT_STONECORRIDOR 0 +#define EAX_ENVIRONMENT_QUARRY 0 +#define EAX_ENVIRONMENT_MOUNTAINS 0 +#define EAX_ENVIRONMENT_PLAIN 0 +#define EAX_ENVIRONMENT_CAVE 0 +#define EAX_ENVIRONMENT_SEWERPIPE 0 +#define EAX_ENVIRONMENT_UNDERWATER 0 +#endif + +%} + +uses "Entities/FogMarker"; +uses "Entities/HazeMarker"; +uses "Entities/MirrorMarker"; +uses "Entities/GradientMarker"; + +// clasification bits +enum ClasificationBits { + 16 CB_00 "Bit 16", + 17 CB_01 "Bit 17", + 18 CB_02 "Bit 18", + 19 CB_03 "Bit 19", + 20 CB_04 "Bit 20", + 21 CB_05 "Bit 21", + 22 CB_06 "Bit 22", + 23 CB_07 "Bit 23", + 24 CB_08 "Bit 24", + 25 CB_09 "Bit 25", + 26 CB_10 "Bit 26", + 27 CB_11 "Bit 27", + 28 CB_12 "Bit 28", + 29 CB_13 "Bit 29", + 30 CB_14 "Bit 30", + 31 CB_15 "Bit 31", +}; + +// visibility bits +enum VisibilityBits { + 0 VB_00 "Bit 00", + 1 VB_01 "Bit 01", + 2 VB_02 "Bit 02", + 3 VB_03 "Bit 03", + 4 VB_04 "Bit 04", + 5 VB_05 "Bit 05", + 6 VB_06 "Bit 06", + 7 VB_07 "Bit 07", + 8 VB_08 "Bit 08", + 9 VB_09 "Bit 09", + 10 VB_10 "Bit 10", + 11 VB_11 "Bit 11", + 12 VB_12 "Bit 12", + 13 VB_13 "Bit 13", + 14 VB_14 "Bit 14", + 15 VB_15 "Bit 15", +}; + +%{ + +inline void Clear(EntityStats &es) {es.es_strName.Clear();}; +static CDynamicArray _aes; +static CAnimObject _aoLightningColor; + +EntityStats *FindStats(const CTString &strName) +{ + {FOREACHINDYNAMICARRAY(_aes, EntityStats, ites) { + EntityStats &es = *ites; + if (es.es_strName==strName) { + return &es; + } + }} + return NULL; +} + +static void MakeWorldStatistics(void) +{ + // get the world pointer + CWorld *pwo = (CWorld *)_pShell->GetINDEX("pwoCurrentWorld"); + // if there is no current world + if (pwo==NULL) { + CPrintF("No current world.\n"); + return; + } + + // for each entity in the world + {FOREACHINDYNAMICCONTAINER(pwo->wo_cenEntities, CEntity, iten) { + // get its stats + EntityStats esCurrent; + BOOL bHasStats = iten->FillEntityStatistics(&esCurrent); + // if no stats + if (!bHasStats) { + // skip it + continue; + } + + // find existing stats with same name + EntityStats *pesOld = FindStats(esCurrent.es_strName); + // if such stats exists + if (pesOld!=NULL) { + // update the existing stats + pesOld->es_ctCount += esCurrent.es_ctCount; + pesOld->es_ctAmmount += esCurrent.es_ctAmmount*esCurrent.es_ctCount; + pesOld->es_fValue += esCurrent.es_fValue*esCurrent.es_ctCount; + pesOld->es_iScore += esCurrent.es_iScore*esCurrent.es_ctCount; + // if this a new name + } else { + // create new stats + EntityStats &esNew = *_aes.New(); + esNew.es_strName = esCurrent.es_strName; + esNew.es_ctCount = esCurrent.es_ctCount; + esNew.es_ctAmmount = esCurrent.es_ctAmmount*esCurrent.es_ctCount; + esNew.es_fValue = esCurrent.es_fValue*esCurrent.es_ctCount; + esNew.es_iScore = esCurrent.es_iScore*esCurrent.es_ctCount; + } + }} + + // dump all stats + try { + CTFileStream strm; + CTFileName fnm = CTString("Temp\\Statistics.txt"); + strm.Create_t(fnm); + CTString strLine; + strLine.PrintF("%-40s: %8s %8s %10s %10s", + "name", "count", "ammount", "health", "score"); + strm.PutLine_t(strLine); + {FOREACHINDYNAMICARRAY(_aes, EntityStats, ites) { + EntityStats &es = *ites; + CTString strLine; + strLine.PrintF("%-40s: %8d %8d %10g %10d", + (const char*)es.es_strName, es.es_ctCount, es.es_ctAmmount, es.es_fValue, es.es_iScore); + strm.PutLine_t(strLine); + }} + CPrintF("Dumped to '%s'\n", (const char*)CTString(fnm)); + } catch (char *strError) { + CPrintF("Error: %s\n", (const char*)strError); + } + + _aes.Clear(); +} + +static void ReoptimizeAllBrushes(void) +{ + // get the world pointer + CWorld *pwo = (CWorld *)_pShell->GetINDEX("pwoCurrentWorld"); + // if there is no current world + if (pwo==NULL) { + CPrintF("No current world.\n"); + return; + } + + // for each brush in the world + FOREACHINDYNAMICARRAY(pwo->wo_baBrushes.ba_abrBrushes, CBrush3D, itbr) { + CBrush3D &br=*itbr; + // for each mip in the brush + FOREACHINLIST(CBrushMip, bm_lnInBrush, itbr->br_lhBrushMips, itbm) { + // reoptimize it + itbm->Reoptimize(); + } + } + CPrintF("All brushes reoptimized.\n"); +} + +void SetPyramidPlateActivateAlpha(CWorld *pwo, INDEX iBlending, + TIME tmActivated, TIME tmDeactivated, BOOL bPulsate) +{ + TIME tmNow = _pTimer->CurrentTick(); + TIME tmStop = 2.0f; + FLOAT fRatio; + + // get alpha + if( tmNow>tmDeactivated) + { + // if plate is deactivated + if( tmNow>tmDeactivated+tmStop) + { + fRatio = 0; + } + // if fading out + else + { + fRatio = CalculateRatio(tmNow, tmDeactivated, tmDeactivated+tmStop, 0.0f, 1.0f); + } + } + else if( tmNow>tmActivated) + { + // if full visible + if( tmNow>tmActivated+tmStop) + { + fRatio = 1; + } + else + { + // fade in + fRatio = CalculateRatio(tmNow, tmActivated, tmActivated+tmStop, 1.0f, 0.0f); + } + } + // not yet activated + else + { + fRatio = 0; + } + FLOAT fSinFactor = 1.0f; + if( bPulsate) + { + fSinFactor = Sin((tmNow-tmActivated) * 720.0f)*0.5f+0.5f; + } + + UBYTE ub = UBYTE( fRatio*fSinFactor*255.0f); + // apply blend or add + if( pwo->wo_atbTextureBlendings[iBlending].tb_ubBlendingType == STXF_BLEND_ALPHA) + { + pwo->wo_atbTextureBlendings[iBlending].tb_colMultiply = C_WHITE|ub; + } + else if( pwo->wo_atbTextureBlendings[iBlending].tb_ubBlendingType == STXF_BLEND_ADD) + { + pwo->wo_atbTextureBlendings[iBlending].tb_colMultiply = RGBAToColor(ub,ub,ub,255); + } +} + +void SetPyramidMorphRoomAlpha(CWorld *pwo, INDEX iBlending, TIME tmActivated) +{ + TIME tmNow = _pTimer->CurrentTick(); + TIME tmDelta = tmNow-tmActivated; + FLOAT fRatio; + FLOAT tmAppear=10.0f; + + if( tmNow<=tmActivated) { return;} + + // get alpha + if( tmNow>=tmActivated+tmAppear) + { + fRatio = 1; + } + else + { + fRatio = CalculateRatio(tmNow, tmActivated, tmActivated+tmAppear, 1.0f, 0.0f); + } + + FLOAT fSinFactor = Sin(-90+tmDelta*90*(1.0f+tmDelta/tmAppear*4))*0.5f+0.5f; + //FLOAT fSinFactor = Sin(-90+90*tmDelta)*0.5f+0.5f; + //UBYTE ub = fSinFactor*255.0f; + UBYTE ub = UBYTE((fRatio+(1.0f-fRatio)*fSinFactor)*255.0f); + + // apply blend or add + if( pwo->wo_atbTextureBlendings[iBlending].tb_ubBlendingType == STXF_BLEND_ALPHA) + { + pwo->wo_atbTextureBlendings[iBlending].tb_colMultiply = C_WHITE|ub; + } + else if( pwo->wo_atbTextureBlendings[iBlending].tb_ubBlendingType == STXF_BLEND_ADD) + { + pwo->wo_atbTextureBlendings[iBlending].tb_colMultiply = RGBAToColor(ub,ub,ub,255); + } +} + +void CWorldBase_OnWorldInit(CWorld *pwo) +{ + pwo->wo_attTextureTransformations[0].tt_strName = "None"; + pwo->wo_attTextureTransformations[1].tt_strName = "R Extremly Slow"; + pwo->wo_attTextureTransformations[2].tt_strName = "R Very Slow"; + pwo->wo_attTextureTransformations[3].tt_strName = "R Slow"; + pwo->wo_attTextureTransformations[4].tt_strName = "R Medium"; + pwo->wo_attTextureTransformations[5].tt_strName = "R Fast"; + pwo->wo_attTextureTransformations[6].tt_strName = "R Very Fast"; + pwo->wo_attTextureTransformations[7].tt_strName = "R Extremly Fast"; + + pwo->wo_attTextureTransformations[8].tt_strName = "Dummy 1"; + pwo->wo_attTextureTransformations[9].tt_strName = "Dummy 2"; + pwo->wo_attTextureTransformations[10].tt_strName = "Dummy 3"; + + pwo->wo_attTextureTransformations[11].tt_strName = "Water movement extremly slow"; + pwo->wo_attTextureTransformations[12].tt_strName = "Water movement very slow"; + pwo->wo_attTextureTransformations[13].tt_strName = "Water movement slow"; + pwo->wo_attTextureTransformations[14].tt_strName = "Water movement normal"; + pwo->wo_attTextureTransformations[15].tt_strName = "Water movement fast"; + + pwo->wo_attTextureTransformations[16].tt_strName = "Stormy sky appearing"; + + pwo->wo_attTextureTransformations[17].tt_strName = "Rotation Left 1"; + pwo->wo_attTextureTransformations[18].tt_strName = "Rotation Left 2"; + pwo->wo_attTextureTransformations[19].tt_strName = "Rotation Left 3"; + pwo->wo_attTextureTransformations[20].tt_strName = "Rotation Left 4"; + pwo->wo_attTextureTransformations[21].tt_strName = "Rotation Left 5"; + pwo->wo_attTextureTransformations[22].tt_strName = "Rotation Left 6"; + pwo->wo_attTextureTransformations[23].tt_strName = "Rotation Left 7"; + pwo->wo_attTextureTransformations[24].tt_strName = "Rotation Left 8"; + pwo->wo_attTextureTransformations[25].tt_strName = "Rotation Left 9"; + pwo->wo_attTextureTransformations[26].tt_strName = "Rotation Left 10"; + + pwo->wo_attTextureTransformations[27].tt_strName = "Rotation Right 1"; + pwo->wo_attTextureTransformations[28].tt_strName = "Rotation Right 2"; + pwo->wo_attTextureTransformations[29].tt_strName = "Rotation Right 3"; + pwo->wo_attTextureTransformations[30].tt_strName = "Rotation Right 4"; + pwo->wo_attTextureTransformations[31].tt_strName = "Rotation Right 5"; + pwo->wo_attTextureTransformations[32].tt_strName = "Rotation Right 6"; + pwo->wo_attTextureTransformations[33].tt_strName = "Rotation Right 7"; + pwo->wo_attTextureTransformations[34].tt_strName = "Rotation Right 8"; + pwo->wo_attTextureTransformations[35].tt_strName = "Rotation Right 9"; + pwo->wo_attTextureTransformations[36].tt_strName = "Rotation Right 10"; + + pwo->wo_attTextureTransformations[37].tt_strName = "D Extremly Slow"; + pwo->wo_attTextureTransformations[38].tt_strName = "D Very Slow"; + pwo->wo_attTextureTransformations[39].tt_strName = "D Slow"; + pwo->wo_attTextureTransformations[40].tt_strName = "D Medium"; + pwo->wo_attTextureTransformations[41].tt_strName = "D Fast"; + pwo->wo_attTextureTransformations[42].tt_strName = "D Very Fast"; + pwo->wo_attTextureTransformations[43].tt_strName = "D Extremly Fast"; + pwo->wo_attTextureTransformations[44].tt_strName = "D Super Fast"; + pwo->wo_attTextureTransformations[45].tt_strName = "D Abnormaly Fast"; + +// static + pwo->wo_atbTextureBlendings[0].tb_strName = "Opaque"; + pwo->wo_atbTextureBlendings[0].tb_ubBlendingType = STXF_BLEND_OPAQUE; + + pwo->wo_atbTextureBlendings[1].tb_strName = "Shade"; + pwo->wo_atbTextureBlendings[1].tb_ubBlendingType = STXF_BLEND_SHADE; + + pwo->wo_atbTextureBlendings[2].tb_strName = "Blend"; + pwo->wo_atbTextureBlendings[2].tb_ubBlendingType = STXF_BLEND_ALPHA; + + pwo->wo_atbTextureBlendings[3].tb_strName = "Add"; + pwo->wo_atbTextureBlendings[3].tb_ubBlendingType = STXF_BLEND_ADD; +// pulsating + pwo->wo_atbTextureBlendings[4].tb_strName = "Shade pulsating"; + pwo->wo_atbTextureBlendings[4].tb_ubBlendingType = STXF_BLEND_SHADE; + pwo->wo_atbTextureBlendings[4].tb_colMultiply = 0x808080FF; + + pwo->wo_atbTextureBlendings[5].tb_strName = "Blend pulsating full"; + pwo->wo_atbTextureBlendings[5].tb_ubBlendingType = STXF_BLEND_ALPHA; + pwo->wo_atbTextureBlendings[5].tb_colMultiply = C_WHITE|0x80; + + pwo->wo_atbTextureBlendings[6].tb_strName = "Add pulsating"; + pwo->wo_atbTextureBlendings[6].tb_ubBlendingType = STXF_BLEND_ADD; + pwo->wo_atbTextureBlendings[6].tb_colMultiply = 0x808080FF; + + pwo->wo_atbTextureBlendings[7].tb_strName = "Blend pulsating half"; + pwo->wo_atbTextureBlendings[7].tb_ubBlendingType = STXF_BLEND_ALPHA; + pwo->wo_atbTextureBlendings[7].tb_colMultiply = C_WHITE|0xC0; + + pwo->wo_atbTextureBlendings[8].tb_strName = "Stormy sky blend"; + pwo->wo_atbTextureBlendings[8].tb_ubBlendingType = STXF_BLEND_ALPHA; + pwo->wo_atbTextureBlendings[8].tb_colMultiply = C_WHITE|0x00; + + pwo->wo_atbTextureBlendings[9].tb_strName = "Stormy sky shade"; + pwo->wo_atbTextureBlendings[9].tb_ubBlendingType = STXF_BLEND_SHADE; + pwo->wo_atbTextureBlendings[9].tb_colMultiply = C_WHITE|0xFF; + + pwo->wo_atbTextureBlendings[10].tb_strName = "Pyramid plate appearing"; + pwo->wo_atbTextureBlendings[10].tb_ubBlendingType = STXF_BLEND_ALPHA; + pwo->wo_atbTextureBlendings[10].tb_colMultiply = C_WHITE|0x00; + + pwo->wo_atbTextureBlendings[11].tb_strName = "Activated plate 1"; + pwo->wo_atbTextureBlendings[11].tb_ubBlendingType = STXF_BLEND_ADD; + pwo->wo_atbTextureBlendings[11].tb_colMultiply = C_BLACK|CT_OPAQUE; + + pwo->wo_atbTextureBlendings[12].tb_strName = "Activated plate 2"; + pwo->wo_atbTextureBlendings[12].tb_ubBlendingType = STXF_BLEND_ADD; + pwo->wo_atbTextureBlendings[12].tb_colMultiply = C_BLACK|CT_OPAQUE; + + pwo->wo_atbTextureBlendings[13].tb_strName = "Activated plate 3"; + pwo->wo_atbTextureBlendings[13].tb_ubBlendingType = STXF_BLEND_ADD; + pwo->wo_atbTextureBlendings[13].tb_colMultiply = C_BLACK|CT_OPAQUE; + + pwo->wo_atbTextureBlendings[14].tb_strName = "Activated plate 4"; + pwo->wo_atbTextureBlendings[14].tb_ubBlendingType = STXF_BLEND_ADD; + pwo->wo_atbTextureBlendings[14].tb_colMultiply = C_BLACK|CT_OPAQUE; + + pwo->wo_atbTextureBlendings[15].tb_strName = "Activate pyramid morph room"; + pwo->wo_atbTextureBlendings[15].tb_ubBlendingType = STXF_BLEND_ALPHA; + pwo->wo_atbTextureBlendings[15].tb_colMultiply = C_WHITE|0x00; + + pwo->wo_aitIlluminationTypes[0].it_strName = "None"; + pwo->wo_aitIlluminationTypes[1].it_strName = "Vitraj 1"; + pwo->wo_aitIlluminationTypes[2].it_strName = "Vitraj 2"; + pwo->wo_aitIlluminationTypes[3].it_strName = "Vitraj 3"; + pwo->wo_aitIlluminationTypes[4].it_strName = "Lava 1"; + pwo->wo_aitIlluminationTypes[5].it_strName = "Lava 2"; + pwo->wo_aitIlluminationTypes[6].it_strName = "Lava 3"; + pwo->wo_aitIlluminationTypes[7].it_strName = "Misc 1"; + pwo->wo_aitIlluminationTypes[8].it_strName = "Misc 2"; + pwo->wo_aitIlluminationTypes[9].it_strName = "Misc 3"; + + // surfaces + + pwo->wo_astSurfaceTypes[0].st_strName = "Standard"; + pwo->wo_astSurfaceTypes[0].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[0].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[0].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[0].st_fClimbSlopeCos = Cos(45.0f); + + pwo->wo_astSurfaceTypes[1].st_strName = "Ice"; + pwo->wo_astSurfaceTypes[1].st_fFriction = 0.045f; + pwo->wo_astSurfaceTypes[1].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[1].st_fJumpSlopeCos = Cos(5.0f); + pwo->wo_astSurfaceTypes[1].st_fClimbSlopeCos = Cos(5.0f); + + pwo->wo_astSurfaceTypes[2].st_strName = "Standard - no step"; + pwo->wo_astSurfaceTypes[2].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[2].st_fStairsHeight = -0.2f; + pwo->wo_astSurfaceTypes[2].st_fJumpSlopeCos = Cos(10.0f); + pwo->wo_astSurfaceTypes[2].st_fClimbSlopeCos = Cos(10.0f); + + pwo->wo_astSurfaceTypes[3].st_strName = "Standard - high stairs"; + pwo->wo_astSurfaceTypes[3].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[3].st_fStairsHeight = 2.0f; + pwo->wo_astSurfaceTypes[3].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[3].st_fClimbSlopeCos = Cos(45.0f); + + pwo->wo_astSurfaceTypes[4].st_strName = "Ice climbable slope"; + pwo->wo_astSurfaceTypes[4].st_fFriction = 0.05f; + pwo->wo_astSurfaceTypes[4].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[4].st_fJumpSlopeCos = Cos(15.0f); + pwo->wo_astSurfaceTypes[4].st_fClimbSlopeCos = Cos(15.0f); + + pwo->wo_astSurfaceTypes[5].st_strName = "Ice sliding slope"; + pwo->wo_astSurfaceTypes[5].st_fFriction = 0.001f; + pwo->wo_astSurfaceTypes[5].st_fStairsHeight = 0.0f; + pwo->wo_astSurfaceTypes[5].st_fJumpSlopeCos = Cos(5.0f); + pwo->wo_astSurfaceTypes[5].st_fClimbSlopeCos = Cos(5.0f); + + pwo->wo_astSurfaceTypes[6].st_strName = "Ice less sliding"; + pwo->wo_astSurfaceTypes[6].st_fFriction = 0.06f; + pwo->wo_astSurfaceTypes[6].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[6].st_fJumpSlopeCos = Cos(5.0f); + pwo->wo_astSurfaceTypes[6].st_fClimbSlopeCos = Cos(5.0f); + + pwo->wo_astSurfaceTypes[7].st_strName = "Roller coaster"; + pwo->wo_astSurfaceTypes[7].st_fFriction = 0.1f; + pwo->wo_astSurfaceTypes[7].st_fStairsHeight = 0.0f; + pwo->wo_astSurfaceTypes[7].st_fJumpSlopeCos = Cos(5.0f); + pwo->wo_astSurfaceTypes[7].st_fClimbSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[7].st_ulFlags = STF_SLIDEDOWNSLOPE; + + pwo->wo_astSurfaceTypes[8].st_strName = "Lava"; + pwo->wo_astSurfaceTypes[8].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[8].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[8].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[8].st_fClimbSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[8].st_iWalkDamageType = DMT_BURNING; + pwo->wo_astSurfaceTypes[8].st_fWalkDamageAmount = 2.0f; + pwo->wo_astSurfaceTypes[8].st_tmWalkDamageFrequency = 0.5f; + + ASSERT(9==SURFACE_SAND); + pwo->wo_astSurfaceTypes[9].st_strName = "Sand"; + pwo->wo_astSurfaceTypes[9].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[9].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[9].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[9].st_fClimbSlopeCos = Cos(45.0f); + + pwo->wo_astSurfaceTypes[10].st_strName = "Clibamble Slope"; + pwo->wo_astSurfaceTypes[10].st_fFriction = 2.0f; + pwo->wo_astSurfaceTypes[10].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[10].st_fJumpSlopeCos = Cos(60.0f); + pwo->wo_astSurfaceTypes[10].st_fClimbSlopeCos = Cos(60.0f); + + pwo->wo_astSurfaceTypes[11].st_strName = "Standard - no impact"; + pwo->wo_astSurfaceTypes[11].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[11].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[11].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[11].st_fClimbSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[11].st_ulFlags = STF_NOIMPACT; + + ASSERT(12==SURFACE_WATER); + pwo->wo_astSurfaceTypes[12].st_strName = "Water"; + pwo->wo_astSurfaceTypes[12].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[12].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[12].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[12].st_fClimbSlopeCos = Cos(45.0f); + + ASSERT(13==SURFACE_RED_SAND); + pwo->wo_astSurfaceTypes[13].st_strName = "Red sand"; + pwo->wo_astSurfaceTypes[13].st_fFriction = 1.0f; + pwo->wo_astSurfaceTypes[13].st_fStairsHeight = 1.0f; + pwo->wo_astSurfaceTypes[13].st_fJumpSlopeCos = Cos(45.0f); + pwo->wo_astSurfaceTypes[13].st_fClimbSlopeCos = Cos(45.0f); + + // contents + pwo->wo_actContentTypes[0].ct_strName = "Air"; + pwo->wo_actContentTypes[0].ct_fDensity = 0.0f; + pwo->wo_actContentTypes[0].ct_fFluidFriction = 0.0f; + pwo->wo_actContentTypes[0].ct_fControlMultiplier = 1.0f; + pwo->wo_actContentTypes[0].ct_fSpeedMultiplier = 1.0f; + pwo->wo_actContentTypes[0].ct_fDrowningDamageAmount = 10.0f; + pwo->wo_actContentTypes[0].ct_tmDrowningDamageDelay = 1.0f; + pwo->wo_actContentTypes[0].ct_ulFlags = CTF_FLYABLE|CTF_BREATHABLE_LUNGS; + + pwo->wo_actContentTypes[1].ct_strName = "Water"; + pwo->wo_actContentTypes[1].ct_fDensity = 1000.0f; + pwo->wo_actContentTypes[1].ct_fFluidFriction = 0.0f; + pwo->wo_actContentTypes[1].ct_fControlMultiplier = 2.0f; + pwo->wo_actContentTypes[1].ct_fSpeedMultiplier = 0.75f; + pwo->wo_actContentTypes[1].ct_fDrowningDamageAmount = 10.0f; + pwo->wo_actContentTypes[1].ct_tmDrowningDamageDelay = 1.0f; + pwo->wo_actContentTypes[1].ct_ulFlags = CTF_BREATHABLE_GILLS|CTF_SWIMABLE|CTF_FADESPINNING; + + pwo->wo_actContentTypes[2].ct_strName = "Lava"; + pwo->wo_actContentTypes[2].ct_fDensity = 800.0f; + pwo->wo_actContentTypes[2].ct_fFluidFriction = 1.0f; + pwo->wo_actContentTypes[2].ct_fControlMultiplier = 2.0f; + pwo->wo_actContentTypes[2].ct_fSpeedMultiplier = 0.5f; + pwo->wo_actContentTypes[2].ct_fDrowningDamageAmount = 0.0f; + pwo->wo_actContentTypes[2].ct_tmDrowningDamageDelay = 1.0f; + pwo->wo_actContentTypes[2].ct_iSwimDamageType = DMT_BURNING; + pwo->wo_actContentTypes[2].ct_fSwimDamageAmount = 50.0f; + pwo->wo_actContentTypes[2].ct_tmSwimDamageFrequency = 0.25f; + pwo->wo_actContentTypes[2].ct_ulFlags = CTF_FADESPINNING; + + pwo->wo_actContentTypes[3].ct_strName = "Cold Water"; + pwo->wo_actContentTypes[3].ct_fDensity = 1000.0f; + pwo->wo_actContentTypes[3].ct_fFluidFriction = 0.0f; + pwo->wo_actContentTypes[3].ct_fControlMultiplier = 2.0f; + pwo->wo_actContentTypes[3].ct_fSpeedMultiplier = 0.75f; + pwo->wo_actContentTypes[3].ct_fDrowningDamageAmount = 10.0f; + pwo->wo_actContentTypes[3].ct_tmDrowningDamageDelay = 1.0f; + pwo->wo_actContentTypes[3].ct_iSwimDamageType = DMT_FREEZING; + pwo->wo_actContentTypes[3].ct_fSwimDamageAmount = 1.0f; + pwo->wo_actContentTypes[3].ct_tmSwimDamageDelay = 5.0f; + pwo->wo_actContentTypes[3].ct_tmSwimDamageFrequency = 1.0f; + pwo->wo_actContentTypes[3].ct_ulFlags = CTF_BREATHABLE_GILLS|CTF_SWIMABLE|CTF_FADESPINNING; + + pwo->wo_actContentTypes[4].ct_strName = "Spikes"; + pwo->wo_actContentTypes[4].ct_fDensity = 500.0f; + pwo->wo_actContentTypes[4].ct_fFluidFriction = 0.5f; + pwo->wo_actContentTypes[4].ct_fControlMultiplier = 1.0f; + pwo->wo_actContentTypes[4].ct_fSpeedMultiplier = 0.75f; + pwo->wo_actContentTypes[4].ct_iKillDamageType = DMT_SPIKESTAB; + pwo->wo_actContentTypes[4].ct_fKillImmersion = 0.5f; + pwo->wo_actContentTypes[4].ct_ulFlags = CTF_BREATHABLE_LUNGS|CTF_FADESPINNING; + + pwo->wo_actContentTypes[5].ct_strName = "Desert heat"; + pwo->wo_actContentTypes[5].ct_fDensity = 0.0f; + pwo->wo_actContentTypes[5].ct_fFluidFriction = 0.0f; + pwo->wo_actContentTypes[5].ct_fControlMultiplier = 1.0f; + pwo->wo_actContentTypes[5].ct_fSpeedMultiplier = 1.0f; + pwo->wo_actContentTypes[5].ct_iSwimDamageType = DMT_HEAT; + pwo->wo_actContentTypes[5].ct_fSwimDamageAmount = 10.0f; + pwo->wo_actContentTypes[5].ct_tmSwimDamageDelay = 10.0f; + pwo->wo_actContentTypes[5].ct_tmSwimDamageFrequency = 2.0f; + pwo->wo_actContentTypes[5].ct_ulFlags = CTF_FLYABLE|CTF_BREATHABLE_LUNGS; + + // environments + pwo->wo_aetEnvironmentTypes[ 0].et_strName = "Normal"; + pwo->wo_aetEnvironmentTypes[ 0].et_iType = 1; + pwo->wo_aetEnvironmentTypes[ 0].et_fSize = 1.4f; + + pwo->wo_aetEnvironmentTypes[ 1].et_strName = "Generic"; + pwo->wo_aetEnvironmentTypes[ 1].et_iType = 0; + pwo->wo_aetEnvironmentTypes[ 1].et_fSize = 7.5f; + + pwo->wo_aetEnvironmentTypes[ 2].et_strName = "Small room"; + pwo->wo_aetEnvironmentTypes[ 2].et_iType = EAX_ENVIRONMENT_LIVINGROOM; + pwo->wo_aetEnvironmentTypes[ 2].et_fSize = 2.5f; + + pwo->wo_aetEnvironmentTypes[ 3].et_strName = "Medium room"; + pwo->wo_aetEnvironmentTypes[ 3].et_iType = EAX_ENVIRONMENT_STONEROOM; + pwo->wo_aetEnvironmentTypes[ 3].et_fSize = 11.6f; + + pwo->wo_aetEnvironmentTypes[ 4].et_strName = "Big room"; + pwo->wo_aetEnvironmentTypes[ 4].et_iType = EAX_ENVIRONMENT_AUDITORIUM; + pwo->wo_aetEnvironmentTypes[ 4].et_fSize = 21.6f; + + pwo->wo_aetEnvironmentTypes[ 5].et_strName = "Corridor"; + pwo->wo_aetEnvironmentTypes[ 5].et_iType = EAX_ENVIRONMENT_HALLWAY; + pwo->wo_aetEnvironmentTypes[ 5].et_fSize = 1.8f; + + pwo->wo_aetEnvironmentTypes[ 6].et_strName = "Arena"; + pwo->wo_aetEnvironmentTypes[ 6].et_iType = EAX_ENVIRONMENT_ARENA; + pwo->wo_aetEnvironmentTypes[ 6].et_fSize = 36.2f; + + pwo->wo_aetEnvironmentTypes[ 7].et_strName = "Long corridor"; + pwo->wo_aetEnvironmentTypes[ 7].et_iType = EAX_ENVIRONMENT_STONECORRIDOR; + pwo->wo_aetEnvironmentTypes[ 7].et_fSize = 13.5f; + + pwo->wo_aetEnvironmentTypes[ 8].et_strName = "Small canyon"; + pwo->wo_aetEnvironmentTypes[ 8].et_iType = EAX_ENVIRONMENT_QUARRY; + pwo->wo_aetEnvironmentTypes[ 8].et_fSize = 17.5f; + + pwo->wo_aetEnvironmentTypes[ 9].et_strName = "Big canyon"; + pwo->wo_aetEnvironmentTypes[ 9].et_iType = EAX_ENVIRONMENT_MOUNTAINS; + pwo->wo_aetEnvironmentTypes[ 9].et_fSize = 100.0f; + + pwo->wo_aetEnvironmentTypes[10].et_strName = "Open space"; + pwo->wo_aetEnvironmentTypes[10].et_iType = EAX_ENVIRONMENT_PLAIN; + pwo->wo_aetEnvironmentTypes[10].et_fSize = 42.5f; + + pwo->wo_aetEnvironmentTypes[11].et_strName = "Cave"; + pwo->wo_aetEnvironmentTypes[11].et_iType = EAX_ENVIRONMENT_CAVE; + pwo->wo_aetEnvironmentTypes[11].et_fSize = 14.6f; + + pwo->wo_aetEnvironmentTypes[12].et_strName = "Sewers"; + pwo->wo_aetEnvironmentTypes[12].et_iType = EAX_ENVIRONMENT_SEWERPIPE; + pwo->wo_aetEnvironmentTypes[12].et_fSize = 1.7f; + + pwo->wo_aetEnvironmentTypes[13].et_strName = "Underwater"; + pwo->wo_aetEnvironmentTypes[13].et_iType = EAX_ENVIRONMENT_UNDERWATER; + pwo->wo_aetEnvironmentTypes[13].et_fSize = 1.8f; + + // declare console variables + _pShell->DeclareSymbol("user void MakeWorldStatistics(void);", (void*) &MakeWorldStatistics); + _pShell->DeclareSymbol("user void ReoptimizeAllBrushes(void);", (void*) &ReoptimizeAllBrushes); +} + +void CWorldBase_OnWorldRender(CWorld *pwo) +{ + // get current tick + TIME tmNow = _pTimer->GetLerpedCurrentTick(); + // wrap time to prevent texture coordinates to get unprecise + tmNow = fmod(tmNow, 600.0); // (wrap every 10 minutes) + +// transformations + // right + pwo->wo_attTextureTransformations[1].tt_mdTransformation.md_fUOffset= 128/1024.0f*tmNow; + pwo->wo_attTextureTransformations[2].tt_mdTransformation.md_fUOffset= 256/1024.0f*tmNow; + pwo->wo_attTextureTransformations[3].tt_mdTransformation.md_fUOffset= 512/1024.0f*tmNow; + pwo->wo_attTextureTransformations[4].tt_mdTransformation.md_fUOffset=1024/1024.0f*tmNow; + pwo->wo_attTextureTransformations[5].tt_mdTransformation.md_fUOffset=2048/1024.0f*tmNow; + pwo->wo_attTextureTransformations[6].tt_mdTransformation.md_fUOffset=4096/1024.0f*tmNow; + pwo->wo_attTextureTransformations[7].tt_mdTransformation.md_fUOffset=8192/1024.0f*tmNow; + + // down + pwo->wo_attTextureTransformations[37].tt_mdTransformation.md_fVOffset= 128/1024.0f*tmNow; + pwo->wo_attTextureTransformations[38].tt_mdTransformation.md_fVOffset= 256/1024.0f*tmNow; + pwo->wo_attTextureTransformations[39].tt_mdTransformation.md_fVOffset= 512/1024.0f*tmNow; + pwo->wo_attTextureTransformations[40].tt_mdTransformation.md_fVOffset=1024/1024.0f*tmNow; + pwo->wo_attTextureTransformations[41].tt_mdTransformation.md_fVOffset=2048/1024.0f*tmNow; + pwo->wo_attTextureTransformations[42].tt_mdTransformation.md_fVOffset=4096/1024.0f*tmNow; + pwo->wo_attTextureTransformations[43].tt_mdTransformation.md_fVOffset=8192/1024.0f*tmNow; + pwo->wo_attTextureTransformations[44].tt_mdTransformation.md_fVOffset=8192*2/1024.0f*tmNow; + pwo->wo_attTextureTransformations[45].tt_mdTransformation.md_fVOffset=8192*4/1024.0f*tmNow; + + CMappingDefinitionUI mdui; + mdui.mdui_fUStretch = 1.0f; + mdui.mdui_fVStretch = 1.0f; + mdui.mdui_fUOffset = 0.0f; + mdui.mdui_fVOffset = 0.0f; + // rotations left + mdui.mdui_aURotation = 8192*1/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*1/1024.0f*tmNow; + pwo->wo_attTextureTransformations[17].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*2/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*2/1024.0f*tmNow; + pwo->wo_attTextureTransformations[18].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*4/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*4/1024.0f*tmNow; + pwo->wo_attTextureTransformations[19].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*8/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*8/1024.0f*tmNow; + pwo->wo_attTextureTransformations[20].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*16/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*16/1024.0f*tmNow; + pwo->wo_attTextureTransformations[21].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*32/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*32/1024.0f*tmNow; + pwo->wo_attTextureTransformations[22].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*64/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*64/1024.0f*tmNow; + pwo->wo_attTextureTransformations[23].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*128/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*128/1024.0f*tmNow; + pwo->wo_attTextureTransformations[24].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = 8192*256/1024.0f*tmNow; + mdui.mdui_aVRotation = 8192*256/1024.0f*tmNow; + pwo->wo_attTextureTransformations[25].tt_mdTransformation.FromUI(mdui); + // rotations right + mdui.mdui_aURotation = -8192*1/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*1/1024.0f*tmNow; + pwo->wo_attTextureTransformations[27].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*2/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*2/1024.0f*tmNow; + pwo->wo_attTextureTransformations[28].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*4/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*4/1024.0f*tmNow; + pwo->wo_attTextureTransformations[29].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*8/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*8/1024.0f*tmNow; + pwo->wo_attTextureTransformations[30].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*16/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*16/1024.0f*tmNow; + pwo->wo_attTextureTransformations[31].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*32/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*32/1024.0f*tmNow; + pwo->wo_attTextureTransformations[32].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*64/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*64/1024.0f*tmNow; + pwo->wo_attTextureTransformations[33].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*128/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*128/1024.0f*tmNow; + pwo->wo_attTextureTransformations[34].tt_mdTransformation.FromUI(mdui); + mdui.mdui_aURotation = -8192*256/1024.0f*tmNow; + mdui.mdui_aVRotation = -8192*256/1024.0f*tmNow; + pwo->wo_attTextureTransformations[35].tt_mdTransformation.FromUI(mdui); +// blendings + FLOAT f = Abs(Sin(tmNow*AngleDeg(180.0f))); + pwo->wo_atbTextureBlendings[4].tb_colMultiply = RGBAToColor(f*255, f*255, f*255, 255); + pwo->wo_atbTextureBlendings[5].tb_colMultiply = C_WHITE|UBYTE(255*f); + pwo->wo_atbTextureBlendings[6].tb_colMultiply = RGBAToColor(f*255, f*255, f*255, 255); + pwo->wo_atbTextureBlendings[7].tb_colMultiply = C_WHITE|UBYTE(255*Lerp(0.5f, 1.0f, f)); + + pwo->wo_attTextureTransformations[11].tt_mdTransformation.md_fUOffset=Sin( tmNow*22)/30; + pwo->wo_attTextureTransformations[11].tt_mdTransformation.md_fVOffset=Cos( tmNow*26)/35; + + pwo->wo_attTextureTransformations[12].tt_mdTransformation.md_fUOffset=Sin( tmNow*32)/10; + pwo->wo_attTextureTransformations[12].tt_mdTransformation.md_fVOffset=Cos( tmNow*22)/15; + + pwo->wo_attTextureTransformations[13].tt_mdTransformation.md_fUOffset=Sin( tmNow*15)/7; + pwo->wo_attTextureTransformations[13].tt_mdTransformation.md_fVOffset=Cos( tmNow*25)/8; + + pwo->wo_attTextureTransformations[14].tt_mdTransformation.md_fUOffset=Sin( tmNow*32)/3; + pwo->wo_attTextureTransformations[14].tt_mdTransformation.md_fVOffset=Cos( tmNow*22)/3; + + pwo->wo_attTextureTransformations[15].tt_mdTransformation.md_fUOffset=Sin( tmNow*15); + pwo->wo_attTextureTransformations[15].tt_mdTransformation.md_fVOffset=Cos( tmNow*25); + + // ----------- Obtain world settings controller + CWorldSettingsController *pwsc = NULL; + // obtain bcg viewer + CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) pwo->GetBackgroundViewer(); + if( penBcgViewer != NULL) + { + // obtain world settings controller + pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; + } + + // ***** Storm effects + // if world settings controller is valid + if( pwsc != NULL) + { + FLOAT fStormFactor = pwsc->GetStormFactor(); + // set alpha value + UBYTE ubA = UBYTE(255.0f*fStormFactor); + pwo->wo_atbTextureBlendings[8].tb_colMultiply = C_WHITE|ubA; + + // set world polygon shading multiplier + UBYTE ubShd = UBYTE(64+191*(1.0f-fStormFactor)); + COLOR colShade = RGBToColor(ubShd,ubShd,ubShd)|CT_OPAQUE; + + // apply lightning FX + if( pwsc->m_tmLightningStart != -1) + { + FLOAT tmLightningLife = tmNow-pwsc->m_tmLightningStart; + _aoLightningColor.ao_tmAnimStart = pwsc->m_tmLightningStart; + COLOR colLightning = _aoLightningColor.GetFrame(); + // calculate lightning power factor + UBYTE ub = UBYTE( pwsc->m_fLightningPower*255); + COLOR colFactor = RGBToColor( ub, ub, ub) | CT_OPAQUE; + colLightning = MulColors( colLightning, colFactor); + colShade = AddColors( colShade, colLightning); + } + pwo->wo_atbTextureBlendings[9].tb_colMultiply = colShade; + } + + // ***** Pyramid blending effects + // if world settings controller is valid + if( pwsc != NULL) + { + // set alpha values for switch-controlled pyramid plate activating + SetPyramidPlateActivateAlpha(pwo, 10, pwsc->m_tmPyramidPlatesStart, 1e6, FALSE); + SetPyramidPlateActivateAlpha(pwo, 11, pwsc->m_tmActivatedPlate1, pwsc->m_tmDeactivatedPlate1, TRUE); + SetPyramidPlateActivateAlpha(pwo, 12, pwsc->m_tmActivatedPlate2, pwsc->m_tmDeactivatedPlate2, TRUE); + SetPyramidPlateActivateAlpha(pwo, 13, pwsc->m_tmActivatedPlate3, pwsc->m_tmDeactivatedPlate3, TRUE); + SetPyramidPlateActivateAlpha(pwo, 14, pwsc->m_tmActivatedPlate4, pwsc->m_tmDeactivatedPlate4, TRUE); + // pyramid morph room + SetPyramidMorphRoomAlpha(pwo, 15, pwsc->m_tmPyramidMorphRoomActivated); + } +}; + +void CWorldBase_OnInitClass(void) +{ + // init particle effects + InitParticles(); + try + { + // setup simple model shadow texture + _toSimpleModelShadow.SetData_t( CTFILENAME("Textures\\Effects\\Shadow\\SimpleModelShadow.tex")); + _aoLightningColor.SetData_t( CTFILENAME("Animations\\Lightning.ani")); + // we will use first animation in .ani file for lightning + _aoLightningColor.PlayAnim(0, AOF_NORESTART); + } + catch(char *strError) + { + FatalError(TRANS("Cannot load shadow texture: \n%s"), strError); + } +} + +void CWorldBase_OnEndClass(void) +{ + // close particle effects + CloseParticles(); +} + +class CFixedForce { +public: + CTString ff_strName; + class CForceStrength ff_fsGravity; + class CForceStrength ff_fsField; + + inline CFixedForce(CTString strName, + FLOAT3D vDirection, + FLOAT fAcceleration, + FLOAT fVelocity) + { + ff_strName = strName; + ff_fsGravity.fs_vDirection =vDirection; + ff_fsGravity.fs_fAcceleration =fAcceleration; + ff_fsGravity.fs_fVelocity =fVelocity; + } + +}; + +static CFixedForce affFixedForces[] = +{ + CFixedForce ("Normal D", FLOAT3D( 0,-1, 0), 30, 70), + CFixedForce ("Normal U", FLOAT3D( 0,+1, 0), 30, 70), + CFixedForce ("Normal N", FLOAT3D( 0, 0,-1), 30, 70), + CFixedForce ("Normal S", FLOAT3D( 0, 0,+1), 30, 70), + CFixedForce ("Normal E", FLOAT3D(-1, 0, 0), 30, 70), + CFixedForce ("Normal W", FLOAT3D(+1, 0, 0), 30, 70), + CFixedForce ("ZeroG", FLOAT3D(+1, 0, 0), 0, 0), + CFixedForce ("Unused", FLOAT3D(+1, 0, 0), 0, 0), + CFixedForce ("Unused", FLOAT3D(+1, 0, 0), 0, 0), + CFixedForce ("Unused", FLOAT3D(+1, 0, 0), 0, 0), +}; +static INDEX ctFixedForces = ARRAYCOUNT(affFixedForces); +extern void GetDefaultForce(INDEX iForce, const FLOAT3D &vPoint, + CForceStrength &fsGravity, CForceStrength &fsField) +{ + if (iForce=ulFirst) && (slPropertyOffset<=ulLast) ) { + return (IsDerivedFromClass(penTarget, strClass)); + } + + // if gravity marker + ulFirst = offsetof(CWorldBase, m_penGravity0); + ulLast = offsetof(CWorldBase, m_penGravity9); + if( (slPropertyOffset>=ulFirst) && (slPropertyOffset<=ulLast) ) { + return + IsDerivedFromClass(penTarget, "Gravity Marker")|| + IsDerivedFromClass(penTarget, "Gravity Router"); + } + + // if mirror marker + ulFirst = offsetof(CWorldBase, m_penMirror0); + ulLast = offsetof(CWorldBase, m_penMirror4); + strClass = "Mirror Marker"; + if( (slPropertyOffset>=ulFirst) && (slPropertyOffset<=ulLast) ) { + return (IsDerivedFromClass(penTarget, strClass)); + } + + // if fog marker + ulFirst = offsetof(CWorldBase, m_penFog0); + ulLast = offsetof(CWorldBase, m_penFog4); + strClass = "Fog Marker"; + if( (slPropertyOffset>=ulFirst) && (slPropertyOffset<=ulLast) ) { + return (IsDerivedFromClass(penTarget, strClass)); + } + + // if haze marker + ulFirst = offsetof(CWorldBase, m_penHaze0); + ulLast = offsetof(CWorldBase, m_penHaze4); + strClass = "Haze Marker"; + if( (slPropertyOffset>=ulFirst) && (slPropertyOffset<=ulLast) ) { + return (IsDerivedFromClass(penTarget, strClass)); + } + + return CEntity::IsTargetValid(slPropertyOffset, penTarget); + } + + /* Get force type name, return empty string if not used. */ + const CTString &GetForceName(INDEX iForce) + { + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + INDEX ctGravityMarkers = &m_penGravity9-&m_penGravity0+1; + + if (iForceGetForceName(0); + } else { + return strMarkerUnused; + } + + } + return strDummyName; + } + } + /* Get force in given point. */ + void GetForce(INDEX iForce, const FLOAT3D &vPoint, + CForceStrength &fsGravity, CForceStrength &fsField) + { + INDEX ctGravityMarkers = &m_penGravity9-&m_penGravity0+1; + if (iForceGetForce(0, vPoint, fsGravity, fsField); + return; + } + } + fsGravity.fs_fAcceleration = 30; + fsGravity.fs_fVelocity = 70; + fsGravity.fs_vDirection = FLOAT3D(1,0,0); + } + fsField.fs_fAcceleration = 0; + fsField.fs_fVelocity = 0; + } + + /* Get entity that controls the force, used for change notification checking. */ + CEntity *GetForceController(INDEX iForce) + { + INDEX ctGravityMarkers = &m_penGravity9-&m_penGravity0+1; + if (iForceGetForceController(0); + } + } + } + return NULL; + } + + /* Get fog type name, return empty string if not used. */ + const CTString &GetFogName(INDEX iFog) + { + INDEX ctFogMarkers = &m_penFog4-&m_penFog0+1; + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + if (iFogGetFogName(); + } else { + return strMarkerUnused; + } + } + return strDummyName; + } + /* Get fog, return FALSE for none. */ + BOOL GetFog(INDEX iFog, class CFogParameters &fpFog) + { + INDEX ctFogMarkers = &m_penFog4-&m_penFog0+1; + if (iFogGetFog(fpFog); + return TRUE; + } + } + return FALSE; + } + + /* Get haze type name, return empty string if not used. */ + const CTString &GetHazeName(INDEX iHaze) + { + INDEX ctHazeMarkers = &m_penHaze4-&m_penHaze0+1; + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + if (iHazeGetHazeName(); + } else { + return strMarkerUnused; + } + } + return strDummyName; + } + + /* Get haze, return FALSE for none. */ + BOOL GetHaze(INDEX iHaze, class CHazeParameters &hpHaze, FLOAT3D &vViewDir) + { + INDEX ctHazeMarkers = &m_penHaze4-&m_penHaze0+1; + if (iHazeGetHaze(hpHaze, vViewDir); + return TRUE; + } + } + return FALSE; + } + + /* Get mirror type name, return empty string if not used. */ + const CTString &GetMirrorName(INDEX iMirror) + { + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + if (iMirror==0) { + return strDummyName; + } + + switch (iMirror) { + case 1: { static const CTString str("std mirror 1"); return str; }; break; + case 2: { static const CTString str("std mirror 2"); return str; }; break; + case 3: { static const CTString str("std mirror 3"); return str; }; break; + case 4: { static const CTString str("std mirror 4"); return str; }; break; + case 5: { static const CTString str("std mirror 5"); return str; }; break; + case 6: { static const CTString str("std mirror 6"); return str; }; break; + case 7: { static const CTString str("std mirror 7"); return str; }; break; + case 8: { static const CTString str("std mirror 8"); return str; }; break; + default: { + iMirror-=9; + INDEX ctMirrorMarkers = &m_penMirror4-&m_penMirror0+1; + if (iMirrorGetMirrorName(); + } else { + return strMarkerUnused; + } + } + } + } + return strDummyName; + } + + /* Get mirror, return FALSE for none. */ + BOOL GetMirror(INDEX iMirror, class CMirrorParameters &mpMirror) + { + if (iMirror==0) { + return FALSE; + } + if (iMirror>=1 && iMirror<=8) { + mpMirror.mp_ulFlags = 0; + return TRUE; + } + iMirror-=9; + INDEX ctMirrorMarkers = &m_penMirror4-&m_penMirror0+1; + if (iMirrorGetMirror(mpMirror); + return TRUE; + } + } + return FALSE; + } + + /* Get gradient type name, return empty string if not used. */ + const CTString &GetGradientName(INDEX iGradient) + { + INDEX ctGradientMarkers = &m_penGradient19-&m_penGradient0+1; + static const CTString strDummyName(""); + static const CTString strMarkerUnused("Marker not set"); + if (iGradientGetGradientName(); + } else { + return strMarkerUnused; + } + } + return strDummyName; + } + /* Uncache shadows for given gradient */ + void UncacheShadowsForGradient(class CGradientMarker *penDiscard) + { + INDEX ctGradientMarkers = &m_penGradient19-&m_penGradient0+1; + for( INDEX iGradient=0; iGradient0) ){ + CGradientMarker *pgm = (CGradientMarker *)&*(&m_penGradient0)[iGradient-1]; + if (pgm != NULL) { + return pgm->GetGradient(0, fpGradient); + } + } + return FALSE; + } + + /* Handle an event, return false if the event is not handled. */ + BOOL HandleEvent(const CEntityEvent &ee) + { + // when someone in range is destroyed + if (ee.ee_slEvent==EVENTCODE_EFirstWorldBase) { + SetFlags(GetFlags()|ENF_ZONING); + m_bZoning = TRUE; + SetFlags(GetFlags()|ENF_ANCHORED); + m_bAnchored = TRUE; + return TRUE; + } + return FALSE; + } + +procedures: + Main(EVoid evoid) + { + // declare yourself as a brush + InitAsBrush(); + SetPhysicsFlags(EPF_BRUSH_FIXED); + SetCollisionFlags(ECF_BRUSH); + + // set zoning + if( m_bZoning) { + m_strDescription = "zoning"; + SetFlags(GetFlags()|ENF_ZONING); + } else { + m_strDescription = "non zoning"; + SetFlags(GetFlags()&~ENF_ZONING); + } + + // set background + if( m_bBackground) { + m_strDescription += " background"; + SetFlags(GetFlags()|ENF_BACKGROUND); + } else { + SetFlags(GetFlags()&~ENF_BACKGROUND); + } + + // set anchor for SEd + if( m_bAnchored) { + m_strDescription += " anchored"; + SetFlags(GetFlags()|ENF_ANCHORED); + } else { + SetFlags(GetFlags()&~ENF_ANCHORED); + } + + return; + } +}; diff --git a/Sources/Entities/WorldLink.es b/Sources/Entities/WorldLink.es new file mode 100644 index 0000000..f01f0f7 --- /dev/null +++ b/Sources/Entities/WorldLink.es @@ -0,0 +1,64 @@ +214 +%{ +#include "Entities/StdH/StdH.h" +%} + +uses "Entities/Marker"; + +// world link +enum WorldLinkType { + 1 WLT_FIXED "Fixed", // fixed link + 2 WLT_RELATIVE "Relative", // relative link +}; + +class CWorldLink : CMarker { +name "World link"; +thumbnail "Thumbnails\\WorldLink.tbn"; +features "IsImportant"; + +properties: + 1 CTString m_strGroup "Group" 'G' = "", + 2 CTFileNameNoDep m_strWorld "World" 'W' = "", + 3 BOOL m_bStoreWorld "Store world" 'S' = FALSE, + 4 enum WorldLinkType m_EwltType "Type" 'Y' = WLT_RELATIVE, + +components: + 1 model MODEL_WORLDLINK "Models\\Editor\\WorldLink.mdl", + 2 texture TEXTURE_WORLDLINK "Models\\Editor\\WorldLink.tex" + + +functions: +/************************************************************ + * START EVENT * + ************************************************************/ + BOOL HandleEvent(const CEntityEvent &ee) { + if (ee.ee_slEvent == EVENTCODE_ETrigger) { + ETrigger &eTrigger = (ETrigger &)ee; + _SwcWorldChange.strGroup = m_strGroup; // group name + _SwcWorldChange.plLink = GetPlacement(); // link placement + _SwcWorldChange.iType = (INDEX)m_EwltType; // type + _pNetwork->ChangeLevel(m_strWorld, m_bStoreWorld, 0); + return TRUE; + } + return FALSE; + }; + +procedures: +/************************************************************ + * M A I N * + ************************************************************/ + Main(EVoid) { + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // set appearance + SetModel(MODEL_WORLDLINK); + SetModelMainTexture(TEXTURE_WORLDLINK); + + // set name + m_strName.PrintF("World link - %s", (const char*)m_strGroup); + + return; + } +}; diff --git a/Sources/Entities/WorldSettingsController.es b/Sources/Entities/WorldSettingsController.es new file mode 100644 index 0000000..437ffc0 --- /dev/null +++ b/Sources/Entities/WorldSettingsController.es @@ -0,0 +1,124 @@ +605 +%{ +#include "Entities/StdH/StdH.h" +%} + +class CWorldSettingsController: CEntity { +name "WorldSettingsController"; +thumbnail "Thumbnails\\WorldSettingsController.tbn"; +features "IsTargetable", "HasName", "IsImportant"; + +properties: + 1 FLOAT m_tmStormStart = -1.0f, // storm start time + 2 CTString m_strName "Name" 'N' = "World settings controller", // class name + 3 FLOAT m_tmLightningStart = -1.0f, // lightning start time + 4 FLOAT m_fLightningPower = 1.0f, // lightning power + 5 FLOAT m_tmStormEnd = -1.0f, // storm end time + 6 FLOAT m_tmPyramidPlatesStart = 1e6, // time when pyramid plates blend started + 7 FLOAT m_tmActivatedPlate1 = 1e6, // time when plate 1 has been activated + 8 FLOAT m_tmDeactivatedPlate1 = 1e6, // time when plate 1 has been deactivated + 9 FLOAT m_tmActivatedPlate2 = 1e6, // time when plate 2 has been activated + 10 FLOAT m_tmDeactivatedPlate2 = 1e6, // time when plate 2 has been deactivated + 11 FLOAT m_tmActivatedPlate3 = 1e6, // time when plate 3 has been activated + 12 FLOAT m_tmDeactivatedPlate3 = 1e6, // time when plate 3 has been deactivated + 13 FLOAT m_tmActivatedPlate4 = 1e6, // time when plate 4 has been activated + 14 FLOAT m_tmDeactivatedPlate4 = 1e6, // time when plate 4 has been deactivated + 15 FLOAT m_tmPyramidMorphRoomActivated = 1e6, // time when pyramid morph room has been activated + + 20 FLOAT m_tmShakeStarted = -1.0f, // time when shaking started + 21 FLOAT3D m_vShakePos = FLOAT3D(0,0,0), // shake position + 22 FLOAT m_fShakeFalloff = 100.0f, // fall off with distance + 23 FLOAT m_fShakeFade = 1.0f, // fall off with time + 24 FLOAT m_fShakeIntensityY = 1.0f, // shake strength + 25 FLOAT m_tmShakeFrequencyY = 1.0f, // shake strength + 26 FLOAT m_fShakeIntensityB = 1.0f, // shake strength + 27 FLOAT m_tmShakeFrequencyB = 1.0f, // shake strength + 31 FLOAT m_fShakeIntensityZ = 1.0f, // shake strength + 32 FLOAT m_tmShakeFrequencyZ = 1.0f, // shake strength + + 28 CTFileName m_fnHeightMap "Height map" 'R' = CTString(""), + 29 CModelObject m_moHeightMapHolder, + 30 FLOATaabbox3D m_boxHeightMap "Height map box" 'B' = FLOATaabbox3D(FLOAT3D(0,0,0), FLOAT3D(1,1,1)), + + 41 FLOAT m_tmGlaringStarted = -1.0f, // glaring start time + 42 FLOAT m_tmGlaringEnded = -1.0f, // glaring end time + 43 FLOAT m_fGlaringFadeInRatio = 0.1f, // glaring fade in ratio + 44 FLOAT m_fGlaringFadeOutRatio = 0.1f, // glaring fade out ratio + +components: + 1 model MODEL_WORLD_SETTINGS_CONTROLLER "Models\\Editor\\WorldSettingsController.mdl", + 2 texture TEXTURE_WORLD_SETTINGS_CONTROLLER "Models\\Editor\\WorldSettingsController.tex" + +functions: + void Precache(void) + { + CTextureData *ptdHeightMap = (CTextureData *) m_moHeightMapHolder.mo_toTexture.GetData(); + if( ptdHeightMap!=NULL) + { + ptdHeightMap->Force(TEX_STATIC); + } + } + + FLOAT GetStormFactor(void) + { + FLOAT fStormFactor = 0.0f; + FLOAT fStormAppearLen = 10.0f; + TIME tmNow = _pTimer->GetLerpedCurrentTick(); + // if we have storm + if( tmNow>m_tmStormStart && tmNowm_tmStormStart+fStormAppearLen && tmNowm_tmStormEnd) + { + fStormFactor = 1.0f-(tmNow-m_tmStormEnd)/fStormAppearLen; + } + // storm is turning on + else + { + fStormFactor = (tmNow-m_tmStormStart)/fStormAppearLen; + } + } + return fStormFactor; + } + + void GetHeightMapData(CTextureData *&ptdHeightMap, FLOATaabbox3D &boxHeightMap) + { + ptdHeightMap = (CTextureData *) m_moHeightMapHolder.mo_toTexture.GetData(); + boxHeightMap = m_boxHeightMap; + } + +procedures: + Main(EVoid) + { + // set appearance + InitAsEditorModel(); + SetPhysicsFlags(EPF_MODEL_IMMATERIAL); + SetCollisionFlags(ECF_IMMATERIAL); + + // try to obtain height map + if( m_fnHeightMap != CTString("")) + { + try + { + m_moHeightMapHolder.mo_toTexture.SetData_t(m_fnHeightMap); + } catch (char *strError) { + WarningMessage(strError); + } + } + + // set appearance + SetModel(MODEL_WORLD_SETTINGS_CONTROLLER); + SetModelMainTexture(TEXTURE_WORLD_SETTINGS_CONTROLLER); + + m_tmStormStart = 1e5-1.0f; + m_tmStormEnd = 1e5; + + // do nothing + return; + } +}; diff --git a/Sources/SeriousSam/SeriousSam.cpp b/Sources/SeriousSam/SeriousSam.cpp index 7963471..abf8d9c 100644 --- a/Sources/SeriousSam/SeriousSam.cpp +++ b/Sources/SeriousSam/SeriousSam.cpp @@ -123,7 +123,7 @@ CTextureObject *_ptoLogoCT = NULL; CTextureObject *_ptoLogoODI = NULL; CTextureObject *_ptoLogoEAX = NULL; -#if 0 // First Encounter (not working for now) +#ifdef FIRST_ENCOUNTER // First Encounter CTString sam_strVersion = "1.10"; CTString sam_strModName = TRANS("- O P E N S O U R C E -"); #if _SE_DEMO From bd0b38ba00f728c730201fc5a6ada8e36d8d5245 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 8 Apr 2016 07:51:13 +0200 Subject: [PATCH 03/10] It compile now --- Sources/Entities/Common/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Entities/Common/Common.cpp b/Sources/Entities/Common/Common.cpp index 18ffff3..0b4bb61 100644 --- a/Sources/Entities/Common/Common.cpp +++ b/Sources/Entities/Common/Common.cpp @@ -2,7 +2,7 @@ #include "Entities/Reminder.h" //#include "Entities/Flame.h" #include "Entities/Debris.h" -#include "Game/PlayerSettings.h" +#include "GameMP/PlayerSettings.h" #include "Models/Player/SeriousSam/Player.h" #include "Models/Player/SeriousSam/Body.h" #include "Models/Player/SeriousSam/Head.h" From a1b399177acd9bf50e0db7579ae78b360a5a4bb0 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 8 Apr 2016 07:51:50 +0200 Subject: [PATCH 04/10] Added Entities generated files to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3b998ef..42aaebd 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,8 @@ Sources/EntitiesMP/*.cpp !Sources/EntitiesMP/StdH/* Sources/Engine/Classes/*.h Sources/Engine/Classes/*.cpp +Sources/Entities/*.h +Sources/Entities/*.cpp # Other generated files: Sources/Engine/Ska/smcScan.cpp From e1fd158fd6f4caab7914d0ac3424519b41c1bc0c Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 8 Apr 2016 08:18:46 +0200 Subject: [PATCH 05/10] TFE now start a game --- Sources/GameMP/CompModels.cpp | 7 ++++++- Sources/GameMP/StdAfx.h | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) mode change 100644 => 100755 Sources/GameMP/StdAfx.h diff --git a/Sources/GameMP/CompModels.cpp b/Sources/GameMP/CompModels.cpp index b828575..c938615 100755 --- a/Sources/GameMP/CompModels.cpp +++ b/Sources/GameMP/CompModels.cpp @@ -20,7 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #undef DECL_DLL #endif #define DECL_DLL +#ifdef FIRST_ENCOUNTER +#include "Entities/Common/Particles.h" +#else #include "EntitiesMP/Common/Particles.h" +#endif #include "Models/Enemies/Headman/headman.h" #include "Models/Enemies/Eyeman/Eyeman.h" @@ -1007,6 +1011,7 @@ void RenderMessageModel(CDrawPort *pdp, const CTString &strModel) _moModel.RenderModel(rm); // render particles +#ifndef FIRST_ENCOUNTER if (_iParticleType!=PARTICLES_NONE) { Particle_PrepareSystem(pdp, apr); Particle_PrepareEntity( 1, 0, 0, NULL); @@ -1020,7 +1025,7 @@ void RenderMessageModel(CDrawPort *pdp, const CTString &strModel) } Particle_EndSystem(); } - +#endif EndModelRenderingView(); } Stereo_SetBuffer(STEREO_BOTH); diff --git a/Sources/GameMP/StdAfx.h b/Sources/GameMP/StdAfx.h old mode 100644 new mode 100755 index 22ada9b..160489d --- a/Sources/GameMP/StdAfx.h +++ b/Sources/GameMP/StdAfx.h @@ -26,8 +26,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #define DECL_DLL #endif +#ifdef FIRST_ENCOUNTER +#include +#include +#include +#include +#else #include #include #include #include +#endif #undef DECL_DLL From df746ab6d198c87abc960f4420a5473545e10421 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 8 Apr 2016 13:40:56 +0200 Subject: [PATCH 06/10] A few TFE changes --- Sources/GameMP/CompModels.cpp | 4 ++++ Sources/GameMP/Game.cpp | 6 ++++++ 2 files changed, 10 insertions(+) mode change 100644 => 100755 Sources/GameMP/Game.cpp diff --git a/Sources/GameMP/CompModels.cpp b/Sources/GameMP/CompModels.cpp index c938615..7f3f655 100755 --- a/Sources/GameMP/CompModels.cpp +++ b/Sources/GameMP/CompModels.cpp @@ -118,7 +118,11 @@ extern void SetupCompModel_t(const CTString &strName) _colLight = C_GRAY; _colAmbient = C_vdGRAY; _iParticleType = PARTICLES_NONE; +#ifdef FIRST_ENCOUNTER + _moFloor.SetData_t(CTFILENAME("Models\\Computer\\Floor.mdl")); +#else _moFloor.SetData_t(CTFILENAME("ModelsMP\\Computer\\Floor.mdl")); +#endif _moFloor.mo_toTexture.SetData_t(CTFILENAME("Models\\Computer\\Floor.tex")); pmo->mo_colBlendColor = 0xFFFFFFFF; if (strName=="Rocketman") { diff --git a/Sources/GameMP/Game.cpp b/Sources/GameMP/Game.cpp old mode 100644 new mode 100755 index 008c367..f630c37 --- a/Sources/GameMP/Game.cpp +++ b/Sources/GameMP/Game.cpp @@ -2823,8 +2823,14 @@ void CGame::LCDInit(void) { try { _toBcgClouds.SetData_t(CTFILENAME("Textures\\General\\Background6.tex")); +#ifdef FIRST_ENCOUNTER + _toPointer.SetData_t(CTFILENAME("Textures\\General\\Pointer.tex")); + _toBcgGrid.SetData_t(CTFILENAME("Textures\\General\\Grid16x16-dot.tex")); +#else _toPointer.SetData_t(CTFILENAME("TexturesMP\\General\\Pointer.tex")); _toBcgGrid.SetData_t(CTFILENAME("TexturesMP\\General\\grid.tex")); +#endif + // thoses are not in original TFE datas and must be added externaly (with SE1_10.gro or a minimal versio of it) _toBackdrop.SetData_t(CTFILENAME("TexturesMP\\General\\MenuBack.tex")); _toSamU.SetData_t(CTFILENAME("TexturesMP\\General\\SamU.tex")); _toSamD.SetData_t(CTFILENAME("TexturesMP\\General\\SamD.tex")); From 87a67eccf53c8a86315f8dc84011b6910aecdd8e Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Sat, 9 Apr 2016 13:20:13 +0200 Subject: [PATCH 07/10] Fixed Portable C versio of ShadowMap Layer Mixer --- Sources/Engine/Light/LayerMixer.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) mode change 100644 => 100755 Sources/Engine/Light/LayerMixer.cpp diff --git a/Sources/Engine/Light/LayerMixer.cpp b/Sources/Engine/Light/LayerMixer.cpp old mode 100644 new mode 100755 index 66762a2..ef84ebb --- a/Sources/Engine/Light/LayerMixer.cpp +++ b/Sources/Engine/Light/LayerMixer.cpp @@ -57,7 +57,6 @@ extern INDEX shd_iDithering; extern const UBYTE *pubClipByte; extern UBYTE aubSqrt[ SQRTTABLESIZE]; extern UWORD auw1oSqrt[SQRTTABLESIZE]; -extern UWORD auw1oSqrt[SQRTTABLESIZE]; // static FLOAT3D _v00; // internal class for layer mixing @@ -464,9 +463,9 @@ skipPixel: SLONG slL = (slL2Point>>SHIFTX)&(SQRTTABLESIZE-1); // and is just for degenerate cases SLONG slIntensity = _slLightMax; slL = aubSqrt[slL]; - if( slL>_slHotSpot) slIntensity = ((255-slL)*_slLightStep)>>8; + if( slL>_slHotSpot) slIntensity = ((255-slL)*_slLightStep); // add the intensity to the pixel - AddToCluster( pubLayer, slIntensity/255.0f); + AddToCluster( pubLayer, (slIntensity>>8)/255.0f); } // go to the next pixel pubLayer+=4; @@ -682,9 +681,9 @@ skipPixel: SLONG slL = (slL2Point>>SHIFTX)&(SQRTTABLESIZE-1); // and is just for degenerate cases SLONG slIntensity = _slLightMax; slL = aubSqrt[slL]; - if( slL>_slHotSpot) slIntensity = ((255-slL)*_slLightStep)>>8; + if( slL>_slHotSpot) slIntensity = ((255-slL)*_slLightStep); // add the intensity to the pixel - AddToCluster( pubLayer, slIntensity/255.0f); + AddToCluster( pubLayer, (slIntensity>>8)/255.0f); } // go to the next pixel pubLayer+=4; @@ -899,9 +898,10 @@ skipPixel: SLONG sl1oL = (slL2Point>>SHIFTX)&(SQRTTABLESIZE-1); // and is just for degenerate cases sl1oL = auw1oSqrt[sl1oL]; SLONG slIntensity = _slLightMax; - if( sl1oL>16; + if( sl1oL<256) slIntensity = 0; + else if( sl1oL>16*/; // add the intensity to the pixel - AddToCluster( pubLayer, slIntensity/255.0f); + AddToCluster( pubLayer, (slIntensity>>8)/255.0f); } // advance to next pixel pubLayer+=4; @@ -1119,9 +1119,10 @@ skipPixel: SLONG sl1oL = (slL2Point>>SHIFTX)&(SQRTTABLESIZE-1); // and is just for degenerate cases sl1oL = auw1oSqrt[sl1oL]; SLONG slIntensity = _slLightMax; - if( sl1oL>16; + if( sl1oL<256) slIntensity = 0; + else if( sl1oL>16*/; // add the intensity to the pixel - AddToCluster( pubLayer, slIntensity/255.0f); + AddToCluster( pubLayer, (slIntensity>>8)/255.0f); } // advance to next pixel pubLayer+=4; From 98ebac941a0d2c9ecb158244b9b3ad603ac7baab Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Sat, 9 Apr 2016 14:15:33 +0200 Subject: [PATCH 08/10] Change CTString.Match to treat backslashes as slash (fixes Netrisca categories for new messages) --- Sources/Engine/Base/CTString.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) mode change 100644 => 100755 Sources/Engine/Base/CTString.cpp diff --git a/Sources/Engine/Base/CTString.cpp b/Sources/Engine/Base/CTString.cpp old mode 100644 new mode 100755 index 467bcfb..2caeeab --- a/Sources/Engine/Base/CTString.cpp +++ b/Sources/Engine/Base/CTString.cpp @@ -638,8 +638,10 @@ BOOL CTString::Matches(const char *strOther) const } else { q = 0; } - - if ((tolower(*m) != tolower(*n)) && ((*m != '?') || q)) { + + // also, '\\' in mask should match '/' in name, for unix compatibility + if (((tolower(*m) != tolower(*n)) && ((*m!='\\') && (*n!='/'))) + && ((*m != '?') || q)) { if (!wild) { return FALSE; } From cb039e972fd76d4265305830c9859a1644fed66f Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Sat, 9 Apr 2016 23:57:58 +0200 Subject: [PATCH 09/10] Remove some Float Divide to use Integer and Shift in C Portable helper function on LayerMixer --- Sources/Engine/Light/LayerMixer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/Engine/Light/LayerMixer.cpp b/Sources/Engine/Light/LayerMixer.cpp index ef84ebb..6f1d5ad 100755 --- a/Sources/Engine/Light/LayerMixer.cpp +++ b/Sources/Engine/Light/LayerMixer.cpp @@ -122,7 +122,7 @@ public: // add the intensity to the pixel inline void AddToCluster( UBYTE *pub); inline void AddAmbientToCluster( UBYTE *pub); - inline void AddToCluster( UBYTE *pub, FLOAT fIntensity); + inline void AddToCluster( UBYTE *pub, SLONG slIntensity); // additional functions __forceinline void CopyShadowLayer(void); @@ -160,11 +160,11 @@ inline void CLayerMixer::AddAmbientToCluster( UBYTE *pub) IncrementByteWithClip(pub[1], ((UBYTE*)&lm_colAmbient)[2]); IncrementByteWithClip(pub[2], ((UBYTE*)&lm_colAmbient)[1]); } -inline void CLayerMixer::AddToCluster( UBYTE *pub, FLOAT fIntensity) +inline void CLayerMixer::AddToCluster( UBYTE *pub, SLONG slIntensity) { - IncrementByteWithClip(pub[0], (long) (((UBYTE*)&lm_colLight)[3] *fIntensity)); - IncrementByteWithClip(pub[1], (long) (((UBYTE*)&lm_colLight)[2] *fIntensity)); - IncrementByteWithClip(pub[2], (long) (((UBYTE*)&lm_colLight)[1] *fIntensity)); + IncrementByteWithClip(pub[0], (long) (((UBYTE*)&lm_colLight)[3] *slIntensity)>>16); + IncrementByteWithClip(pub[1], (long) (((UBYTE*)&lm_colLight)[2] *slIntensity)>>16); + IncrementByteWithClip(pub[2], (long) (((UBYTE*)&lm_colLight)[1] *slIntensity)>>16); } @@ -465,7 +465,7 @@ skipPixel: slL = aubSqrt[slL]; if( slL>_slHotSpot) slIntensity = ((255-slL)*_slLightStep); // add the intensity to the pixel - AddToCluster( pubLayer, (slIntensity>>8)/255.0f); + AddToCluster( pubLayer, slIntensity); } // go to the next pixel pubLayer+=4; @@ -683,7 +683,7 @@ skipPixel: slL = aubSqrt[slL]; if( slL>_slHotSpot) slIntensity = ((255-slL)*_slLightStep); // add the intensity to the pixel - AddToCluster( pubLayer, (slIntensity>>8)/255.0f); + AddToCluster( pubLayer, slIntensity); } // go to the next pixel pubLayer+=4; @@ -901,7 +901,7 @@ skipPixel: if( sl1oL<256) slIntensity = 0; else if( sl1oL>16*/; // add the intensity to the pixel - AddToCluster( pubLayer, (slIntensity>>8)/255.0f); + AddToCluster( pubLayer, slIntensity); } // advance to next pixel pubLayer+=4; @@ -1122,7 +1122,7 @@ skipPixel: if( sl1oL<256) slIntensity = 0; else if( sl1oL>16*/; // add the intensity to the pixel - AddToCluster( pubLayer, (slIntensity>>8)/255.0f); + AddToCluster( pubLayer, slIntensity); } // advance to next pixel pubLayer+=4; From dfe262b61922cd10d5586808a3661745f4c7f249 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Mon, 11 Apr 2016 08:32:38 +0200 Subject: [PATCH 10/10] Don't pump SDL Event in GetInput, or they will be missing in SeriousSam.cpp:SubMain(...) --- Sources/Engine/Base/SDL/SDLInput.cpp | 3 +++ 1 file changed, 3 insertions(+) mode change 100644 => 100755 Sources/Engine/Base/SDL/SDLInput.cpp diff --git a/Sources/Engine/Base/SDL/SDLInput.cpp b/Sources/Engine/Base/SDL/SDLInput.cpp old mode 100644 new mode 100755 index 07f985d..af1b72b --- a/Sources/Engine/Base/SDL/SDLInput.cpp +++ b/Sources/Engine/Base/SDL/SDLInput.cpp @@ -759,8 +759,11 @@ void CInput::GetInput(BOOL bPreScan) return; } +#if 0 + // should not be usefull SDL_Event event; while (SE_SDL_InputEventPoll(&event)) { /* do nothing... */ } +#endif // if not pre-scanning if (!bPreScan) {