EndCombatSim doesn't seem to work, need help!

bamflux

Chieftain
Joined
Jul 7, 2013
Messages
57
Hey guys,

The code below should spawn a unit when an enemy is killed by a specific unit (The Ghoul)

My initial "Now Loading" prints in the log, but nothing else. The function doesn't seem to be calling.

Code:
--- ScourgeRacial
-- Author: Michael
-- DateCreated: 8/5/2013 11:16:42 AM
--------------------------------------------------------------

print("Now loading Scourge Racial ability script");

local uGHOUL = GameInfoTypes.UNIT_GHOUL

GameEvents.EndCombatSim.Add(

	function(attackingPlayer, attackingUnit, defendingUnit)
		local pPlayer = Players[attackingPlayer];
		local attackUnit = attackingUnit;
		local defendUnit = defendingUnit;
		print("Function Starts");
		--Checking that attacking player is scourge
		if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_SCOURGE and (attackUnit:GetUnitType() == uGHOUL) and (defendUnit:IsDead())) then
		print("Attacker is Scourge + Ghoul");
			--Spawn new unit on loser.
			local iRand = math.random(1, 100)
			if (iRand <33 ) then -- GHOUL
				local pNewUnit = attackPlayer:InitUnit(GameInfoTypes.UNIT_GHOUL, defendUnit:GetX(), defendUnit:GetY());
				Players[Game.GetActivePlayer()]:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, "A Ghoul arises from your foe!", "Victory");
				print("Function Complete");
			end
		end
	end

)

Hope you can help!

Edit:

Anyone looking at this thread to do something similar, here is the final working code:

Code:
--- ScourgeRacial
-- Author: Sigmaflux
-- DateCreated: 8/5/2013 11:16:42 AM
--------------------------------------------------------------

print("Now loading Scourge Racial ability script");

local uGHOUL = GameInfoTypes.UNIT_GHOUL

Events.EndCombatSim.Add(

 function(attackingPlayer, attackingUnit, attackingUnitDamage, attackingUnitFinalDamage, attackingUnitMaxHitPoints, defendingPlayer, defendingUnit, defendingUnitDamage, defendingUnitFinalDamage, defendingUnitMaxHitPoints)
  --local pAttackingPlayer = Players[attackingPlayer];
 -- local pDefendingPlayer = Players[defendingPlayer];
  --local attackUnit = pAttackingPlayer:GetUnitByID(attackingUnit);
  --local defendUnit = pDefendingPlayer:GetUnitByID(defendingUnit);

 --Retrieve attacking and defending players from the player list using IDs
    local pAttackingPlayer = Players[attackingPlayer];
    local pDefendingPlayer = Players[defendingPlayer];
 --If either player is not in the game, end.
    if (not pAttackingPlayer or not pDefendingPlayer) then
         return
    end
 print("Both Players Alive");

  --Retrieve both units from the unit lists for each player. 
  local attackUnit = pAttackingPlayer:GetUnitByID(attackingUnit);
  local defendUnit = pDefendingPlayer:GetUnitByID(defendingUnit);
  --If the attackingUnit does not exist, don't bother.
  if (not attackUnit) then
       return
  end

  print("Function Starts");
  --Checking that attacking player is scourge
  if (pAttackingPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_SCOURGE and (attackUnit:GetUnitType() == uGHOUL) and (not defendUnit)) then
  print("Attacker is Scourge, Ghoul, and enemy is dead.");
   --Spawn new unit on loser.
   local iRand = math.random(1, 100)
   if (iRand <100 ) then -- GHOUL
   print("Trying to spawn ghoul, please work! defendUnit:GetX()!");
    local pNewUnit = pAttackingPlayer:InitUnit(GameInfoTypes.UNIT_GHOUL, attackUnit:GetX(), attackUnit:GetY());
    Players[Game.GetActivePlayer()]:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, "A Ghoul arises from your foe!", "Victory");
    print("Function Complete");
   end
  end
 end

)
 
Looking at Events.EndCombatSim(PlayerID attackingPlayer, UnitID attackingUnit, int attackingUnitDamage, int attackingUnitFinalDamage, int attackingUnitMaxHitPoints, PlayerID defendingPlayer, UnitID defendingUnit, int defendingUnitDamage, int defendingUnitFinalDamage, int defendingUnitMaxHitPoints)

First, it's in Events not game events. Second the params are wrong.

Code:
Events.EndCombatSim.Add(

	function(attackingPlayer, attackingUnit, attackingUnitDamage, attackingUnitFinalDamage, attackingUnitMaxHitPoints, defendingPlayer, defendingUnit, defendingUnitDamage, defendingUnitFinalDamage, defendingUnitMaxHitPoints)
          -- code goes here
         end
)
 
Okay, thanks for that. Getting a little further. I now get this runtime error:

[488917.234] Runtime Error: C:\Users\User\Documents\My Games\Sid Meier's Civilization 5\MODS\Mods\Civilizations of Warcraft - The Scourge (v 1)\Lua/Ghoul Conversion Script.lua:18: attempt to index local 'attackUnit' (a number value)

So, if I understand that correctly, that's an error because I'm trying to put non-number data into a number variable? If so, how do I assign the attacking unit a numeric ID that AttackingUnit will store? I'm quite confused :)

I presume I need something like "Players[attackingPlayer:getUnits[attackingUnit]"?
 
Code:
--- ScourgeRacial
-- Author: Sigmaflux, Bamington, Hambil
-- DateCreated: 8/5/2013 11:16:42 AM
--------------------------------------------------------------

print("Now loading Scourge Racial ability script");

local uGHOUL = GameInfoTypes.UNIT_GHOUL

Events.EndCombatSim.Add(

	function(attackingPlayer, attackingUnit, attackingUnitDamage, attackingUnitFinalDamage, attackingUnitMaxHitPoints, defendingPlayer, defendingUnit, defendingUnitDamage, defendingUnitFinalDamage, defendingUnitMaxHitPoints)
		local pPlayer = Players[attackingPlayer];
		local attackUnit = attackingUnit;
		local defendUnit = defendingUnit;
		print("Function Starts");
		--Checking that attacking player is scourge
		if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_SCOURGE and (attackUnit:GetUnitType() == uGHOUL) and (defendUnit:IsDead())) then
		print("Attacker is Scourge + Ghoul");
			--Spawn new unit on loser.
			local iRand = math.random(1, 100)
			if (iRand <100 ) then -- GHOUL
				local pNewUnit = attackPlayer:InitUnit(GameInfoTypes.UNIT_GHOUL, defendUnit:GetX(), defendUnit:GetY());
				Players[Game.GetActivePlayer()]:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, "A Ghoul arises from your foe!", "Victory");
				print("Function Complete");
			end
		end
	end

)
 
Hmm, that code doesn't seem to be gathering the defending units ID correctly.

[495459.843] Runtime Error: C:\Users\User\Documents\My Games\Sid Meier's Civilization 5\MODS\Mods\Civilizations of Warcraft - The Scourge (v 1)\Lua/Ghoul Conversion Script.lua:19: attempt to index local 'defendUnit' (a nil value)


Current code:
Code:
print("Now loading Scourge Racial ability script");

local uGHOUL = GameInfoTypes.UNIT_GHOUL

Events.EndCombatSim.Add(

	function(attackingPlayer, attackingUnit, attackingUnitDamage, attackingUnitFinalDamage, attackingUnitMaxHitPoints, defendingPlayer, defendingUnit, defendingUnitDamage, defendingUnitFinalDamage, defendingUnitMaxHitPoints)
		local pAttackingPlayer = Players[attackingPlayer];
        local pDefendingPlayer = Players[defendingPlayer];
		local attackUnit = pAttackingPlayer:GetUnitByID(attackingUnit);
		local defendUnit = pDefendingPlayer:GetUnitByID(defendingUnit);
		print("Function Starts");
		--Checking that attacking player is scourge
		if (pAttackingPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_SCOURGE and (attackUnit:GetUnitType() == uGHOUL) and (defendUnit:IsDead())) then
		print("Attacker is Scourge, Ghoul, and enemy is dead.");
			--Spawn new unit on loser.
			local iRand = math.random(1, 100)
			if (iRand <100 ) then -- GHOUL
				local pNewUnit = attackPlayer:InitUnit(GameInfoTypes.UNIT_GHOUL, defendUnit:GetX(), defendUnit:GetY());
				Players[Game.GetActivePlayer()]:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, "A Ghoul arises from your foe!", "Victory");
				print("Function Complete");
			end
		end
	end

)

Thanks again for your help with this. I'm learning so much.
 
Remember that this will get called for every combat not just ghouls and the API does odd things now and again. The problem can probably be solved by just exiting out of the function if you're not given all the data you need.

e.g.
Code:
		local pAttackingPlayer = Players[attackingPlayer];
                local pDefendingPlayer = Players[defendingPlayer];
                if (not pAttackingPlayer or not pDefendingPlayer) then
                    return
                end

		local attackUnit = pAttackingPlayer:GetUnitByID(attackingUnit);
		local defendUnit = pDefendingPlayer:GetUnitByID(defendingUnit);
                if (not attackUnit or not defendUnit) then
                    return
                end
 
EndCombatSim is not reliable since patch .674

IIRC it's not called when one of the unit is dead. And if it is, I think that the dead unit is nil at this point of the code.
 
Okay, one last problem! Hopefully people are still checking in.

This script works great for the player, but when used by the AI it spawns a unit for every attacker, not just the one who dealt the killing blow.

Is there a way to determine if the unit was the actual killer or not?
 
If that is (reliably) the case then the solution would be to just substitute (defendUnit:IsDead()) for (not defendUnit)

Persumably the attacking unit could be dead also, so same there except if it's null you want to exit.

An attacking unit can never die under normal circumstances, I thought.
 
Unless if it's the AI using it with too much optimism... Then an attacker can die.
A human may also sacrifice one unit on purpose in a suicidal attack.

There is also other cases to note: attacking and defending cities, the "unit" will be nil then.

And during the AI turn since patch .674, all the attacks are made, the results computed (and killed units removed) then all the EndCombatSim events are called, hence the multiple unit spawning during the AI turn.

When I've said "not reliable since patch .674", it's from my past experience trying to fix the WWII mod after that change, and believe me, "not reliable" is an understatement.
 
Back
Top Bottom