From d0c6805725fc6a4fe049c1ceb929f998032e72d3 Mon Sep 17 00:00:00 2001 From: Matei Date: Thu, 24 Jul 2008 05:50:45 +0000 Subject: [PATCH] Fixed bug that was causing population to go negative. It was due to a unit being killed by multiple enemies in the same frame, which led to multiple calls of the death event handler. The fix is twofold: First, kill() only calls the event handler the first time the unit is killed. Second, damage() (in JS), which apart from killing things also loots them, makes sure that the unit is not already being destroyed. This latter fix is to ensure that we don't get a huge amount of loot by simply attacking a low-HP unit with many soldiers simultaneously, so they kill it in the same frame. This was SVN commit r6276. --- binaries/data/mods/official/scripts/entity_functions.js | 3 +++ source/simulation/Entity.cpp | 5 ++++- source/simulation/Entity.h | 5 +++++ source/simulation/EntityScriptInterface.cpp | 4 +--- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/binaries/data/mods/official/scripts/entity_functions.js b/binaries/data/mods/official/scripts/entity_functions.js index 2b0d943cec..84694694cd 100644 --- a/binaries/data/mods/official/scripts/entity_functions.js +++ b/binaries/data/mods/official/scripts/entity_functions.js @@ -862,6 +862,9 @@ function damage( dmg, inflictor ) var arm = this.traits.armour; if( !arm ) return; // corpses have no armour, everything else should + // Unit has already been destroyed this frame, don't loot for everything hitting it + if( this.isDestroyed() ) return; + // Use traits.health.max = 0 to signify immortal things like settlements if( this.traits.health.max == 0 ) return; diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 92a2573b30..f2dbf4d68d 100644 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -247,6 +247,10 @@ void CEntity::Kill(bool keepActor) { return; // We were already killed this frame } + entf_set(ENTF_DESTROYED); + + CEventDeath evt; + DispatchEvent( &evt ); g_FormationManager.RemoveUnit(this); @@ -279,7 +283,6 @@ void CEntity::Kill(bool keepActor) g_Selection.RemoveAll( me ); - entf_set(ENTF_DESTROYED); g_EntityManager.m_refd[me.m_handle] = false; // refd must be made false when DESTROYED is set g_EntityManager.SetDeath(true); // remember that a unit died this frame diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index eb06a6556c..18011cf962 100644 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -468,6 +468,11 @@ public: return( m_orderQueue.empty() ); } + bool IsDestroyed( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) + { + return( entf_get(ENTF_DESTROYED) ); + } + bool HasClass( JSContext* cx, uintN argc, jsval* argv ) { debug_assert( argc >= 1 ); diff --git a/source/simulation/EntityScriptInterface.cpp b/source/simulation/EntityScriptInterface.cpp index 4bdb6ead7c..fc0284c460 100644 --- a/source/simulation/EntityScriptInterface.cpp +++ b/source/simulation/EntityScriptInterface.cpp @@ -57,6 +57,7 @@ void CEntity::ScriptingInit() AddMethod( "terminateOrder", 1 ); AddMethod( "kill", 0 ); AddMethod( "isIdle", 0 ); + AddMethod( "isDestroyed", 0 ); AddMethod( "hasClass", 1 ); AddMethod( "getSpawnPoint", 1 ); AddMethod( "addAura", 3 ); @@ -364,9 +365,6 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, CEntityOrder::EOrde bool CEntity::Kill( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { - CEventDeath evt; - DispatchEvent( &evt ); - Kill(true); return( true );