Detecting killer unit

AW Arcaeca

Deus Vult
Joined
Mar 10, 2013
Messages
3,019
Location
Operation Padlock ground zero
A while ago I posted a thread asking whether or not it's possible to make a unit ability revolving around that unit killing an enemy unit. The problem therein is that GameEvents.UnitKilledInCombat only passes the parameters of the killer player, killee player, and killee unit - no killer unit. 'cuz logic, I guess. :rolleyes: And the answer I got was that it's possible with one part of whoward's extensive DLL mod collection.

Now anyone who knows much about my modding habits should know of my distaste for DLL mods, for two reasons, although I don't feel like typing out what they are right now. So basically here's what I'm asking:

How does one detect when a unit kills an enemy unit, without using DLL if possible?

And if DLL is required, can anyone enlighten me on which DLL mod I should be using?
I looked through Machiavelli's mod snippets and there does not seem to be any such event hook I can use. And unfortunately there don't seem to be any lua functions that can directly return the value of either the killed unit or the killer unit. So I'm a bit stuck. :( I'm hoping someone else might be able to shed some light on this conundrum!

TIA,
AW
 
Short of a DLL mod there isn't much that can be done with combat. The existing events (like UnitKilledInCombat) tend to be tied to animation and/or have weird, subtle behaviors that make them not useful for detecting game-play factors.

A method that may be able to "fake" detecting when a unit is killed is giving every unit a capture class that is unique (unitclass_warrior_captured, unitclass_rifleman_captured, etc) and then detect when that unit is created (via the unit created event snippet) to figure out when a unit dies. However, unit capturing is intended for civilian units and may not behave as assumed for military units. It also probably wouldn't work for units that die to ranged attacks.
 
GameEvents.UnitKilledInCombat only passes the parameters of the killer player, killee player, and killee unit

(Not that it helps you, but) The last parameter is killee unit type, and not the id of the killed unit (which no longer exists as an object - it's dead - so you couldn't do anything with its ID anyway)

You'll need to enable both EVENTS_RED_COMBAT and EVENTS_RED_COMBAT_ENDED and then hook the CombatEnded event

Code:
function OnCombatEnded(iAttackingPlayer, iAttackingUnit, iAttackerDamage, iAttackerFinalDamage, iAttackerMaxHP,
                       iDefendingPlayer, iDefendingUnit, iDefenderDamage, iDefenderFinalDamage, iDefenderMaxHP,
                       iInterceptingPlayer, iInterceptingUnit, iInterceptorDamage,
                       iPlotX, iPlotY)
end
GameEvents.CombatEnded.Add(OnCombatEnded)
 
However, unit capturing is intended for civilian units and may not behave as assumed for military units. It also probably wouldn't work for units that die to ranged attacks.
If I understand you correctly, that shouldn't be a problem. This is intended as the trigger for a unit ability for a melee naval unit.
whoward69's VMC has Gedemon's R.E.D. Combat GameEvents for initiating combat and when it ends.
VMC? :crazyeye: Dunno what that is; perhaps you could explicate? Ii've heard a lot about R.E.D but honestly don't know what it does or how it works. Is R.E.D combat a separate mod from this?
(Not that it helps you, but) The last parameter is killee unit type, and not the id of the killed unit (which no longer exists as an object - it's dead - so you couldn't do anything with its ID anyway)
Derp. That never crossed my mind. :cringe: So basically GameEvents.UnitKilledInCombat is even more useless than I had previously thought?
You'll need to enable both EVENTS_RED_COMBAT and EVENTS_RED_COMBAT_ENDED and then hook the CombatEnded event

Code:
function OnCombatEnded(iAttackingPlayer, iAttackingUnit, iAttackerDamage, iAttackerFinalDamage, iAttackerMaxHP,
                       iDefendingPlayer, iDefendingUnit, iDefenderDamage, iDefenderFinalDamage, iDefenderMaxHP,
                       iInterceptingPlayer, iInterceptingUnit, iInterceptorDamage,
                       iPlotX, iPlotY)
end
GameEvents.CombatEnded.Add(OnCombatEnded)
Thank you! :D And this CombatEnded event is the one bane_ was talking about, the one requiring DLL modding? I'll dig into the RED coding and see if I can find what code to reuse...
 
Alright, so I got VMC, which files do I extract for the RED events? Or do I not copy and paste them into my mod and just set a dependency on VMC? Does the user have to manually enable the RED events themselves? I'm very confused... :crazyeye:
 
VMC is a Mod. You treat it like so, there is no difference in 'extraction'.
What you need to do is to add this to YOUR mod:

Code:
<GameData>
	<CustomModOptions>
		<Update>
			<Where Name="EVENTS_RED_TURN"/>
			<Set Value="1"/>
		</Update>

	[B]	<Update>
			<Where Name="EVENTS_RED_COMBAT"/>
			<Set Value="1"/>
		</Update>[/B]

		<Update>
			<Where Name="EVENTS_RED_COMBAT_MISSION"/>
			<Set Value="1"/>
		</Update>

		<Update>
			<Where Name="EVENTS_RED_COMBAT_ABORT"/>
			<Set Value="1"/>
		</Update>

		<Update>
			<Where Name="EVENTS_RED_COMBAT_RESULT"/>
			<Set Value="1"/>
		</Update>

		[B]<Update>
			<Where Name="EVENTS_RED_COMBAT_ENDED"/>
			<Set Value="1"/>
		</Update>[/B]
	</CustomModOptions>
</GameData>

Those in bold are the really important ones; the first activates the code from R.E.D. and the second activates the GameEvents whoward described above.
I let the others here just so you know there are other options too! :)

Also, add a dependency to the DLL mod, yes.
 
A thousand more kudos upon your head!
I don't remember if there are already kudos on your head, but take them anyway
So now, which parameter will return whether or not the defending unit was killed? Would I add in a line like "if (iDefendingUnit:IsDead()) then", or do I check iAttackerFinalDamage, or... I don't know...

And am I right in saying that you don't have to use all the parameters of an event hook so long as you put them in the right order? 'cuz frankly I'm not going to need to worry about interception damage or even what plot the combat happened on for what I'm planning.
 
So now, which parameter will return whether or not the defending unit was killed? Would I add in a line like "if (iDefendingUnit:IsDead()) then", or do I check iAttackerFinalDamage, or... I don't know...
i = integer / iDefendingUnit (in this case) = Unit's ID
You use the 'p' (I guess it is pointer, or floater, something like that) that refers to the object to call methods. So you must get the player (pPlayer = Players[iDefendingPlayer]) then get the unit (pUnit = pPlayer:GetUnitByID(iDefendingUnit)) so you can start messing with it.
I had a few problems understanding how they work, to be honest, and even tried to milk some more in depth explanation of the concept of how it works without success.
What I use to check if the unit will die is this:

Code:
local defenderHealth = defenderMaxHP - defenderFinalDamage
if defenderHealth <= 0 then

I had some problems with my code at the beginning, and after I put the following code, it all disappeared:

Code:
if pAttPlayer then -- In case the combat was aborted...

If this was really necessary or not, I don't know (read lack of concept knowledge from above), but it is in Gedemon's code, so it is safe.


And am I right in saying that you don't have to use all the parameters of an event hook so long as you put them in the right order? 'cuz frankly I'm not going to need to worry about interception damage or even what plot the combat happened on for what I'm planning.
Yes yes. :lol:
Don't worry, they just need to be in order; as a side note, you may treat those you're not using as 'left 0' (I don't know if there is a word in English to describe the 'useless' zero at the left of a number, like '06' for a 'six'); in this case though, it is the stuff at the right that is ignorable, so, if you're not going to use, say, "iInterceptingPlayer, iInterceptingUnit, iInterceptorDamage, iPlotX, iPlotY", you can leave them out; but if you're using iPlotX, you must put the Intercepting stuff, but can leave iPlotY out.


#Reference#
iAttackingPlayer, iAttackingUnit, iAttackerDamage, iAttackerFinalDamage, iAttackerMaxHP, iDefendingPlayer, iDefendingUnit, iDefenderDamage, iDefenderFinalDamage, iDefenderMaxHP, iInterceptingPlayer, iInterceptingUnit, iInterceptorDamage, iPlotX, iPlotY
 
Can I just ignore all the parameters I don't need, even if they're included, like so?
Code:
GameEvents.CombatEnded.Add(
function(iAttackingPlayer, iAttackingUnit, iAttackerDamage, iAttackerFinalDamage, iAttackerMaxHP, iDefendingPlayer, iDefendingUnit, iDefenderDamage, iDefenderFinalDamage, iDefenderMaxHP)
	local iPlayer = Players[iAttackingPlayer]
	local iUnit = Units[iAttackingUnit]
	local mUnitHealth = iDefenderMaxHP - iDefenderFinalDamage
	if mUnitHealth <= 0 and (iUnit:GetUnitType() == GameInfoTypes.UNIT_NEW_UNIT) then
	
		-- do stuff
	end
end)
 
Yes yes. :lol: (deja vu hahaha)
Also, it is not wrong, just confusing, but iPlayer should refer to the Player ID, what you are getting, though, is an object.

I don't believe there is an Units[] table; even because if there was, multiple Civs can share the same Unit ID, hence why we use the Player method to get the specific unit by it's ID.
 
I don't believe there is an Units[] table; even because if there was, multiple Civs can share the same Unit ID, hence why we use the Player method to get the specific unit by it's ID.
I think I might know what you're talking about... what's the function called again? Something like "for iUnit in iPlayer:GetUnitByID() do" or something like that?
 
If you don't want all the parameters, the "accepted Lua way" is to use _ for those before the ones you want and omit any after the ones you want, so, for example

Code:
function OnCombatEnded(iAttackingPlayer, iAttackingUnit, _, iAttackerFinalDamage, _,
                       iDefendingPlayer, iDefendingUnit, _, iDefenderFinalDamage, _,
                       _, _, _,
                       iPlotX, iPlotY)
end
GameEvents.CombatEnded.Add(OnCombatEnded)

or

Code:
function OnCombatEnded(iAttackingPlayer, iAttackingUnit, _, _, _, iDefendingPlayer, iDefendingUnit, )
end
GameEvents.CombatEnded.Add(OnCombatEnded)
 
Back
Top Bottom