From 847884b6a803650903b871054adcde19921af8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Havl=C3=AD=C4=8Dek?= <80639037+havel06@users.noreply.github.com> Date: Wed, 25 Jan 2023 21:50:08 +0100 Subject: TNT minecarts exploding when riding over activator rails (#5469) * TNT Minecarts exploding via activator rails * Fuse animation * Add TNT minecart explosion source to APIDesc --- Server/Plugins/APIDump/APIDesc.lua | 4 ++++ src/Bindings/PluginLua.cpp | 4 ++++ src/Defines.h | 1 + src/Entities/Minecart.cpp | 48 ++++++++++++++++++++++++++++++++++++-- src/Entities/Minecart.h | 9 ++++--- src/World.cpp | 1 + 6 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index f920a8f5b..a5f967915 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -17949,6 +17949,10 @@ end { Notes = "A TNT explosion. The SourceData param is the {{cTNTEntity|TNT entity}} object.", }, + esTNTMinecart = + { + Notes = "A TNT minecart explosion. The SourceData param is the {{cMinecartWithTNT|Minecart with TNT entity}} object.", + }, esWitherBirth = { Notes = "An explosion at a wither's birth. The SourceData param is the {{cMonster|wither entity}} object.", diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 69a8626c1..caa02acf9 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -4,6 +4,8 @@ // Implements the cPluginLua class representing a plugin written in Lua #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "Defines.h" +#include "Entities/Minecart.h" #ifdef __APPLE__ #define LUA_USE_MACOSX @@ -431,6 +433,7 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can case esOther: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break; case esPlugin: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break; case esPrimedTNT: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break; + case esTNTMinecart: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break; case esWitherBirth: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break; case esWitherSkull: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break; case esMax: @@ -471,6 +474,7 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & case esOther: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esPlugin: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esPrimedTNT: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esTNTMinecart: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esWitherBirth: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esWitherSkull: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esMax: diff --git a/src/Defines.h b/src/Defines.h index bbe5d3d3d..ab0a639c4 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -314,6 +314,7 @@ enum eExplosionSource esOther, esPlugin, esPrimedTNT, + esTNTMinecart, esWitherBirth, esWitherSkull, esMax, diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 50be91e4e..d8dbc10c1 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -6,6 +6,8 @@ // Indiana Jones! #include "Globals.h" +#include "ChunkDef.h" +#include "Defines.h" #include "Minecart.h" #include "../BlockInfo.h" #include "../ClientHandle.h" @@ -223,7 +225,7 @@ void cMinecart::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) switch (InsideType) { case E_BLOCK_RAIL: HandleRailPhysics(InsideMeta, a_Dt); break; - case E_BLOCK_ACTIVATOR_RAIL: break; + case E_BLOCK_ACTIVATOR_RAIL: HandleActivatorRailPhysics(InsideMeta, a_Dt); break; case E_BLOCK_POWERED_RAIL: HandlePoweredRailPhysics(InsideMeta); break; case E_BLOCK_DETECTOR_RAIL: { @@ -678,6 +680,7 @@ void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::mi void cMinecart::HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt) { HandleRailPhysics(a_RailMeta & 0x07, a_Dt); + // TODO - shake minecart, throw entities out } @@ -1516,7 +1519,22 @@ cMinecartWithTNT::cMinecartWithTNT(Vector3d a_Pos): { } -// TODO: Make it activate when passing over activator rail + + + + +void cMinecartWithTNT::HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt) +{ + Super::HandleActivatorRailPhysics(a_RailMeta, a_Dt); + + if ((a_RailMeta & 0x08) && !m_isTNTFused) + { + m_isTNTFused = true; + m_TNTFuseTicksLeft = 80; + m_World->BroadcastSoundEffect("entity.tnt.primed", GetPosition(), 1.0f, 1.0f); + m_World->BroadcastEntityAnimation(*this, EntityAnimation::MinecartTNTIgnites); + } +} @@ -1531,6 +1549,32 @@ void cMinecartWithTNT::GetDrops(cItems & a_Drops, cEntity * a_Killer) +void cMinecartWithTNT::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +{ + Super::Tick(a_Dt, a_Chunk); + if (!IsTicking()) + { + return; + } + + if (m_isTNTFused) + { + if (m_TNTFuseTicksLeft > 0) + { + --m_TNTFuseTicksLeft; + } + else + { + Destroy(); + m_World->DoExplosionAt(4.0, GetPosX(), GetPosY() + GetHeight() / 2, GetPosZ(), true, esTNTMinecart, this); + } + } +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cMinecartWithHopper: diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index 0d62d98f1..0e6336330 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -72,8 +72,8 @@ protected: */ void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt); - /** Handles activator rails - placeholder for future implementation */ - void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt); + /** Handles activator rails */ + virtual void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt); /** Snaps a mincecart to a rail's axis, resetting its speed For curved rails, it changes the cart's direction as well as snapping it to axis */ @@ -89,7 +89,6 @@ protected: /** Tests if this mincecart's bounding box is intersecting another entity's bounding box (collision) and pushes mincecart away if necessary */ bool TestEntityCollision(NIBBLETYPE a_RailMeta); - } ; @@ -222,10 +221,14 @@ public: CLASS_PROTODEF(cMinecartWithTNT) cMinecartWithTNT(Vector3d a_Pos); + void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; private: + int m_TNTFuseTicksLeft; + bool m_isTNTFused = false; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; + void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt) override; } ; diff --git a/src/World.cpp b/src/World.cpp index 1af7650e6..133458a8c 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1395,6 +1395,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo case eExplosionSource::esGhastFireball: case eExplosionSource::esMonster: case eExplosionSource::esPrimedTNT: + case eExplosionSource::esTNTMinecart: case eExplosionSource::esWitherBirth: case eExplosionSource::esWitherSkull: { -- cgit v1.2.3