Ghast fireball reflections (besides arrows)

This commit is contained in:
Ethan Jones 2021-09-15 12:17:57 -06:00
parent 11ca2cf4c0
commit a3f1af6f78
8 changed files with 109 additions and 27 deletions

View File

@ -249,21 +249,21 @@ void cEntity::TakeDamage(cEntity & a_Attacker)
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount)
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount, const eExplosionSource a_ExplosionSource)
{
float FinalDamage = static_cast<float>(a_RawDamage);
float ArmorCover = GetArmorCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
ApplyArmorDamage(static_cast<int>(ArmorCover));
cEntity::TakeDamage(a_DamageType, a_Attacker, a_RawDamage, FinalDamage, a_KnockbackAmount);
cEntity::TakeDamage(a_DamageType, a_Attacker, a_RawDamage, FinalDamage, a_KnockbackAmount, a_ExplosionSource);
}
void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount)
void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount, const eExplosionSource a_ExplosionSource)
{
m_World->DoWithEntityByID(a_AttackerID, [=](cEntity & a_Attacker)
{
@ -277,7 +277,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_Ra
Attacker = nullptr;
}
TakeDamage(a_DamageType, Attacker, a_RawDamage, a_KnockbackAmount);
TakeDamage(a_DamageType, Attacker, a_RawDamage, a_KnockbackAmount, a_ExplosionSource);
return true;
}
);
@ -287,11 +287,13 @@ void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_Ra
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, float a_FinalDamage, double a_KnockbackAmount)
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, float a_FinalDamage, double a_KnockbackAmount, const eExplosionSource a_ExplosionSource)
{
TakeDamageInfo TDI;
TDI.DamageType = a_DamageType;
if ((a_Attacker != nullptr) && a_Attacker->IsPawn())
TDI.ExplosionSource = a_ExplosionSource;
if (a_Attacker != nullptr)
{
TDI.Attacker = a_Attacker;
}

View File

@ -58,11 +58,12 @@ class cMonster;
// tolua_begin
struct TakeDamageInfo
{
eDamageType DamageType; // Where does the damage come from? Being hit / on fire / contact with cactus / ...
cEntity * Attacker; // The attacking entity; valid only for dtAttack
int RawDamage; // What damage would the receiver get without any armor. Usually: attacker mob type + weapons
float FinalDamage; // What actual damage will be received. Usually: m_RawDamage minus armor
Vector3d Knockback; // The amount and direction of knockback received from the damage
eDamageType DamageType; // Where does the damage come from? Being hit / on fire / contact with cactus / ...
cEntity * Attacker; // The attacking entity; valid only for dtAttack
int RawDamage; // What damage would the receiver get without any armor. Usually: attacker mob type + weapons
float FinalDamage; // What actual damage will be received. Usually: m_RawDamage minus armor
Vector3d Knockback; // The amount and direction of knockback received from the damage
eExplosionSource ExplosionSource; // The explosion source; valid only for dtExplosion
// TODO: Effects - list of effects that the hit is causing. Unknown representation yet
} ;
// tolua_end
@ -263,13 +264,13 @@ public:
void TakeDamage(cEntity & a_Attacker);
/** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount);
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount, const eExplosionSource a_ExplosionSource = esOther);
/** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */
void TakeDamage(eDamageType a_DamageType, UInt32 a_Attacker, int a_RawDamage, double a_KnockbackAmount);
void TakeDamage(eDamageType a_DamageType, UInt32 a_Attacker, int a_RawDamage, double a_KnockbackAmount, const eExplosionSource a_ExplosionSource = esOther);
/** Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage() */
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, float a_FinalDamage, double a_KnockbackAmount);
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, float a_FinalDamage, double a_KnockbackAmount, const eExplosionSource a_ExplosionSource = esOther);
float GetGravity(void) const { return m_Gravity; }

View File

@ -1,7 +1,6 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "GhastFireballEntity.h"
#include "../World.h"
@ -13,6 +12,32 @@ cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, Vector3d a_Pos,
SetSpeed(a_Speed);
SetGravity(0);
SetAirDrag(0);
m_Shooter = a_Creator;
}
void cGhastFireballEntity::ReflectFromAttack(cEntity * a_AttackingEnt)
{
Vector3d Motion = NotchReflect(*a_AttackingEnt);
SetSpeed(Motion * 20);
}
Vector3d cGhastFireballEntity::NotchReflect(cEntity & a_AttackingEnt)
{
float f1 = cos(-a_AttackingEnt.GetYaw() * 0.017453292F - 3.1415927F);
float f2 = sin(-a_AttackingEnt.GetYaw() * 0.017453292F - 3.1415927F);
float f3 = -cos(-a_AttackingEnt.GetPitch() * 0.017453292F);
float f4 = sin(-a_AttackingEnt.GetPitch() * 0.017453292F);
return Vector3d((double) (f2 * f3), (double) f4, (double) (f1 * f3));
}
@ -43,3 +68,24 @@ void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, Vector3d a_HitPos)
Destroy();
Explode(a_HitPos.Floor());
}
bool cGhastFireballEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (this->IsInvisible())
{
return false;
}
if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn())
{
ReflectFromAttack(a_TDI.Attacker);
m_Shooter = a_TDI.Attacker;
return true;
}
return false;
}

View File

@ -30,15 +30,25 @@ public: // tolua_export
cGhastFireballEntity(cEntity * a_Creator, Vector3d a_Pos, Vector3d a_Speed);
cEntity * GetShooter(void) { return m_Shooter; };
protected:
void Explode(Vector3i a_Block);
void ReflectFromAttack(cEntity * a_AttackingEnt);
Vector3d NotchReflect(cEntity & a_AttackingEnt);
// cProjectileEntity overrides:
virtual void OnHitSolidBlock(Vector3d a_HitPos, eBlockFace a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, Vector3d a_HitPos) override;
// TODO: Deflecting the fireballs by arrow- or sword- hits
// cEntity overrides:
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
private:
cEntity * m_Shooter;
} ; // tolua_export

View File

@ -64,6 +64,28 @@ bool cGhast::DoTakeDamage(TakeDamageInfo & a_TDI)
return false;
}
if ((a_TDI.Attacker != nullptr) && (a_TDI.DamageType == dtExplosion) && (a_TDI.ExplosionSource == esGhastFireball))
{
a_TDI.FinalDamage = 1000.0F;
cGhastFireballEntity * GhastFireball = static_cast<cGhastFireballEntity *>(a_TDI.Attacker);
if (GhastFireball != nullptr)
{
cEntity * Shooter = GhastFireball->GetShooter();
if ((Shooter != nullptr) && Shooter->IsPlayer())
{
cPlayer * Player = static_cast<cPlayer *>(Shooter);
if (Player != nullptr)
{
Player->AwardAchievement(CustomStatistic::AchGhast); // Return to Sender!
}
}
}
}
return Super::DoTakeDamage(a_TDI);
}

View File

@ -2,7 +2,6 @@
#include "Globals.h"
#include "BlockInfo.h"
#include "Explodinator.h"
#include "Blocks/BlockHandler.h"
#include "Blocks/ChunkInterface.h"
#include "Chunk.h"
#include "ClientHandle.h"
@ -202,12 +201,12 @@ namespace Explodinator
}
/** Applies distance-based damage and knockback to all entities within the explosion's effect range. */
static void DamageEntities(const cChunk & a_Chunk, const Vector3f a_Position, const int a_Power)
static void DamageEntities(cEntity * a_ExplodingEntity, const cChunk & a_Chunk, const Vector3f a_Position, const int a_Power, const eExplosionSource a_ExplosionSource = esOther)
{
const auto Radius = a_Power * 2;
const auto SquareRadius = Radius * Radius;
a_Chunk.GetWorld()->ForEachEntityInBox({ a_Position, Radius * 2.f }, [&a_Chunk, a_Position, a_Power, Radius, SquareRadius](cEntity & Entity)
a_Chunk.GetWorld()->ForEachEntityInBox({ a_Position, Radius * 2.f }, [a_ExplodingEntity, &a_Chunk, a_Position, a_Power, a_ExplosionSource, Radius, SquareRadius](cEntity & Entity)
{
// Percentage of rays unobstructed.
const auto Exposure = CalculateEntityExposure(a_Chunk, Entity, a_Position, SquareRadius);
@ -218,7 +217,7 @@ namespace Explodinator
if (!Entity.IsTNT() && !Entity.IsFallingBlock())
{
const auto Damage = (Impact * Impact + Impact) * 7 * a_Power + 1;
Entity.TakeDamage(dtExplosion, nullptr, FloorC(Damage), 0);
Entity.TakeDamage(dtExplosion, a_ExplodingEntity, FloorC(Damage), 0, a_ExplosionSource);
}
// Impact reduced by armour, expensive call so only apply to Pawns:
@ -430,12 +429,12 @@ namespace Explodinator
}
}
void Kaboom(cWorld & a_World, const Vector3f a_Position, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
void Kaboom(cWorld & a_World, const Vector3f a_Position, const int a_Power, const bool a_Fiery, cEntity * a_ExplodingEntity, const eExplosionSource a_ExplosionSource)
{
a_World.DoWithChunkAt(a_Position.Floor(), [a_Position, a_Power, a_Fiery, a_ExplodingEntity](cChunk & a_Chunk)
a_World.DoWithChunkAt(a_Position.Floor(), [a_Position, a_Power, a_Fiery, a_ExplodingEntity, a_ExplosionSource](cChunk & a_Chunk)
{
LagTheClient(a_Chunk, a_Position, a_Power);
DamageEntities(a_Chunk, a_Position, a_Power);
DamageEntities(a_ExplodingEntity, a_Chunk, a_Position, a_Power, a_ExplosionSource);
DamageBlocks(a_Chunk, AbsoluteToRelative(a_Position, a_Chunk.GetPos()), a_Power, a_Fiery, a_ExplodingEntity);
return false;

View File

@ -1,6 +1,8 @@
#pragma once
#include "Blocks/BlockHandler.h"
@ -17,5 +19,5 @@ namespace Explodinator
For maximum efficiency, Position should be in the centre of the entity or block that exploded.
The entity pointer is used to trigger OnBreak for the destroyed blocks.
Kaboom indeed, you drunken wretch. */
void Kaboom(cWorld & World, Vector3f Position, int Power, bool Fiery, const cEntity * a_ExplodingEntity);
void Kaboom(cWorld & World, Vector3f Position, int Power, bool Fiery, cEntity * a_ExplodingEntity, const eExplosionSource = esOther);
}

View File

@ -1370,7 +1370,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
{
// TODO: CanCauseFire gets reset to false for some reason, (plugin has ability to change it, might be related)
const cEntity * Entity;
cEntity * Entity;
switch (a_Source)
{
case eExplosionSource::esEnderCrystal:
@ -1380,7 +1380,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
case eExplosionSource::esWitherBirth:
case eExplosionSource::esWitherSkull:
{
Entity = static_cast<const cEntity *>(a_SourceData);
Entity = static_cast<cEntity *>(a_SourceData);
break;
}
default:
@ -1389,7 +1389,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
}
}
Explodinator::Kaboom(*this, Vector3d(a_BlockX, a_BlockY, a_BlockZ), FloorC(a_ExplosionSize), a_CanCauseFire, Entity);
Explodinator::Kaboom(*this, Vector3d(a_BlockX, a_BlockY, a_BlockZ), FloorC(a_ExplosionSize), a_CanCauseFire, Entity, a_Source);
cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData);
}
}