diff --git a/src/Entities/EntityEffects.h b/src/Entities/EntityEffects.h index 137eb6480..e6b5bdd5d 100644 --- a/src/Entities/EntityEffects.h +++ b/src/Entities/EntityEffects.h @@ -47,6 +47,10 @@ public: /** Returns the distance modifier for affecting potency */ double GetDistanceModifier() { return m_DistanceModifier; } + void SetIntensity(short a_Intensity) { m_Intensity = a_Intensity; } + void SetUser(cPawn *a_User) { m_User = a_User; } + void SetDistanceModifier(double a_DistanceModifier) { m_DistanceModifier = a_DistanceModifier; } + /** * An empty entity effect */ diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp index 5cf270006..5cd493a06 100644 --- a/src/Entities/Pawn.cpp +++ b/src/Entities/Pawn.cpp @@ -69,7 +69,8 @@ void cPawn::AddEntityEffect(cEntityEffect::eType a_EffectType, cEntityEffect a_E } m_EntityEffects[a_EffectType] = a_Effect; - m_World->BroadcastEntityEffect(*this, a_EffectType, a_Effect.GetIntensity(), a_Effect.m_Ticks); + m_World->BroadcastEntityEffect(*this, a_EffectType, a_Effect.GetIntensity(), + a_Effect.m_Ticks * a_Effect.GetDistanceModifier()); } @@ -114,7 +115,7 @@ void cPawn::HandleEntityEffects(cEntityEffect::eType a_EffectType, cEntityEffect case cEntityEffect::efInstantHealth: { // Base heal = 6, doubles for every increase in intensity - Heal(6 * std::pow(2, a_Effect.GetIntensity())); + Heal(6 * std::pow(2, a_Effect.GetIntensity()) * a_Effect.GetDistanceModifier()); // TODO: Harms undead return; @@ -123,7 +124,7 @@ void cPawn::HandleEntityEffects(cEntityEffect::eType a_EffectType, cEntityEffect { // Base damage = 6, doubles for every increase in intensity int damage = 6 * std::pow(2, a_Effect.GetIntensity()); - TakeDamage(dtPotionOfHarming, a_Effect.GetUser(), damage, 0); + TakeDamage(dtPotionOfHarming, a_Effect.GetUser(), damage * a_Effect.GetDistanceModifier(), 0); // TODO: Heals undead return; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index ee3890f23..664f929f6 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -18,7 +18,6 @@ #include "ThrownEnderPearlEntity.h" #include "ExpBottleEntity.h" #include "ThrownSnowballEntity.h" -#include "SplashPotionEntity.h" #include "FireChargeEntity.h" #include "FireworkEntity.h" #include "GhastFireballEntity.h" @@ -252,7 +251,6 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkSplashPotion: return new cSplashPotionEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkFirework: { diff --git a/src/Entities/SplashPotionEntity.cpp b/src/Entities/SplashPotionEntity.cpp index c6be2baf7..5dcea2385 100644 --- a/src/Entities/SplashPotionEntity.cpp +++ b/src/Entities/SplashPotionEntity.cpp @@ -1,14 +1,17 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "SplashPotionEntity.h" -#include "../World.h" +#include "Player.h" -cSplashPotionEntity::cSplashPotionEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : -super(pkSplashPotion, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +cSplashPotionEntity::cSplashPotionEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed, cEntityEffect::eType a_EntityEffectType, cEntityEffect a_EntityEffect, int a_PotionName) : + super(pkSplashPotion, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_EntityEffectType(a_EntityEffectType), + m_EntityEffect(a_EntityEffect), + m_PotionName(a_PotionName) { SetSpeed(a_Speed); } @@ -19,7 +22,7 @@ super(pkSplashPotion, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) void cSplashPotionEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - // TODO: Apply potion effect to entities nearby + Splash(a_HitPos); Destroy(); } @@ -30,8 +33,51 @@ void cSplashPotionEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1); - - // TODO: Apply potion effect to entity and others nearby - + Splash(a_HitPos); Destroy(true); } + + + + + +void cSplashPotionEntity::Splash(const Vector3d & a_HitPos) +{ + cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect); + m_World->ForEachPlayer(Callback); + // TODO: Should be for each pawn + + m_World->BroadcastSoundParticleEffect(2002, a_HitPos.x, a_HitPos.y, a_HitPos.z, m_PotionName); +} + + + + + +cSplashPotionEntity::cSplashPotionCallback::cSplashPotionCallback(const Vector3d & a_HitPos, cEntityEffect::eType &a_EntityEffectType, cEntityEffect &a_EntityEffect): + m_HitPos(a_HitPos), + m_EntityEffectType(a_EntityEffectType), + m_EntityEffect(a_EntityEffect) +{ + +} + + + + + +bool cSplashPotionEntity::cSplashPotionCallback::Item(cPlayer * a_Player) +{ + double distance_splash = (a_Player->GetPosition() - m_HitPos).Length(); + if (distance_splash < 20) + { + // y = -0.25x + 1, where x is the distance from the player. Approximation for potion splash. + // TODO: better equation + double reduction = -0.25 * distance_splash + 1.0; + if (reduction < 0) reduction = 0; + + m_EntityEffect.SetDistanceModifier(reduction); + a_Player->AddEntityEffect(m_EntityEffectType, m_EntityEffect); + } + return false; +} diff --git a/src/Entities/SplashPotionEntity.h b/src/Entities/SplashPotionEntity.h index d82a7bfcd..b64b668a5 100644 --- a/src/Entities/SplashPotionEntity.h +++ b/src/Entities/SplashPotionEntity.h @@ -5,7 +5,8 @@ #pragma once #include "ProjectileEntity.h" - +#include "EntityEffects.h" +#include "../World.h" @@ -13,7 +14,7 @@ // tolua_begin class cSplashPotionEntity : -public cProjectileEntity + public cProjectileEntity { typedef cProjectileEntity super; @@ -23,7 +24,7 @@ public: CLASS_PROTODEF(cSplashPotionEntity); - cSplashPotionEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + cSplashPotionEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed, cEntityEffect::eType a_EntityEffectType, cEntityEffect a_EntityEffect, int a_PotionName); protected: @@ -31,4 +32,27 @@ protected: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + /** Splashes the potion, fires its particle effects and sounds + * @param a_HitPos The position where the potion will splash + */ + void Splash(const Vector3d & a_HitPos); + + cEntityEffect::eType m_EntityEffectType; + cEntityEffect m_EntityEffect; + int m_PotionName; + + class cSplashPotionCallback : + public cPlayerListCallback + { + public: + cSplashPotionCallback(const Vector3d & a_HitPos, cEntityEffect::eType &a_EntityEffectType, cEntityEffect &a_EntityEffect); + + virtual bool Item(cPlayer * a_Player) override; + + private: + const Vector3d &m_HitPos; + cEntityEffect::eType &m_EntityEffectType; + cEntityEffect &m_EntityEffect; + }; + } ; // tolua_export diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h index e34b251aa..528268cfe 100644 --- a/src/Items/ItemPotion.h +++ b/src/Items/ItemPotion.h @@ -2,12 +2,18 @@ #pragma once #include "../Entities/EntityEffects.h" +#include "../Entities/SplashPotionEntity.h" class cItemPotionHandler: -public cItemHandler + public cItemHandler { typedef cItemHandler super; + int GetPotionName(short a_ItemDamage) + { + return a_ItemDamage & 63; + } + cEntityEffect::eType GetEntityEffectType(short a_ItemDamage) { // Potion effect bits are different from entity effect values @@ -118,6 +124,34 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override { + Vector3d Speed = a_Player->GetLookVector() * 10; + + short potion_damage = a_Item.m_ItemDamage; + cProjectileEntity * Projectile = new cSplashPotionEntity(a_Player, + (double)a_BlockX, + (double)a_BlockY, + (double)a_BlockZ, + &Speed, + GetEntityEffectType(potion_damage), + cEntityEffect(GetEntityEffectDuration(potion_damage), + GetEntityEffectIntensity(potion_damage), + a_Player), + GetPotionName(potion_damage)); + if (Projectile == NULL) + { + return false; + } + if (!Projectile->Initialize(*a_World)) + { + delete Projectile; + return false; + } + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + // Called when potion is a splash potion return true; }