Kill The Target example question [Solved]

In this forum you will find and post information regarding the modding of Star Wars Battlefront 2. DO NOT POST MOD IDEAS/REQUESTS.

Moderator: Moderators

Post Reply
jedimoose32
Field Commander
Field Commander
Posts: 938
Joined: Thu Jan 24, 2008 12:41 am
Projects :: Engineering Degree
Location: The Flatlands of Canada

Kill The Target example question [Solved]

Post by jedimoose32 »

Hi everyone.

I was looking at the Kill The Target example code and I understand all of it perfectly except this part:

Code: Select all

	i = 1
		
	TEAM = OnCharacterDeath(
		function(character, killer)
			if GetObjectTeam(killer) == 1 then --if anyone dies and the killer was on team 1?
				SpawnCharacter(GetTeamMember(1,i),GetEntityMatrix(killer)) --i'm not sure who we're spawning
				i = i + 1
			end
		end)
I've tried block commenting it out and it doesn't seem to make any difference in the gameplay. The stock examples of SpawnCharacter are usually heroes that are being force-spawned somewhere specific, but in this case team 1 is the human team, and the human character is alive the whole time (immediate defeat if you die). There are no AI on team 1. As for GetEntityMatrix, this is where my lack of Lua experience rears its ugly head and I don't really get what that does. I'm assuming it runs through a list of numbers?

Thanks in advance.
Last edited by jedimoose32 on Tue Mar 10, 2015 2:48 pm, edited 1 time in total.
User avatar
[RDH]Zerted
Gametoast Staff
Gametoast Staff
Posts: 2982
Joined: Sun Feb 26, 2006 7:36 am
Projects :: Bos Wars AI - a RTS game
Games I'm Playing :: SWBF2 and Bos Wars
xbox live or psn: No gamertag set
Location: USA
Contact:

Re: Kill The Target example question

Post by [RDH]Zerted »

That code has a few bugs in it. You shouldn't be clear on which unit is being re-spawned because it isn't clear. First, if killer was nil then the code fails in multiple places. Second, i increases forever. There isn't an unlimited amount of team members on team 1. Eventually that code will attempt to spawn team member 4325 even if there were only 20 members. Third, it's better practice to select a character before trying to spawn one. Not all team members/characters may have selected a character class by the time that code tries to spawn them. Fourth, the character it attempts to spawn might already be alive.

GetEntityMatrix() takes an entity (an object-like thing that's ingame) and returns its location. You can use the location in other functions, such as SetEntityMatrix(), to teleport some other entity to the same location.

The code ignores team member 0, but that may be on purpose. In SP player 0 is the human.

GetTeamMember() lets you get a reference to a player/character without having to wait for an OnXXXX event. You can use it to loop through all the players and do something to each of them, such as teleporting everyone to a specific location.
jedimoose32
Field Commander
Field Commander
Posts: 938
Joined: Thu Jan 24, 2008 12:41 am
Projects :: Engineering Degree
Location: The Flatlands of Canada

Re: Kill The Target example question

Post by jedimoose32 »

Interesting. So I should be pruning this code somewhat to make it more logical.

Thanks for explaining all that. What I did just a few minutes ago was put a print() command inside each and every function, which would output a label (e.g. "Damage confirmed" or "Target killed") and then ran the map in BF2_ModTools so that I could get a nicely debugged play-by-play of what was happening behind the scenes. And yeah, I noticed that the "TEAM = OnCharacterDeath" bit never printed anything no matter what I did. So I think it may be redundant.

On a somewhat side note, if I wanted to do what this block of code is attempting to do and spawn all of team 1 at the killer's location, what would be a better way of doing it? A while or for loop that ends once i = the highest number on the team?
User avatar
[RDH]Zerted
Gametoast Staff
Gametoast Staff
Posts: 2982
Joined: Sun Feb 26, 2006 7:36 am
Projects :: Bos Wars AI - a RTS game
Games I'm Playing :: SWBF2 and Bos Wars
xbox live or psn: No gamertag set
Location: USA
Contact:

Re: Kill The Target example question

Post by [RDH]Zerted »

If you want to improve the code, you'd be at least doubling its size, not making it smaller (pruning).

OnCharacterDeath should be called each time a character dies. If that's not happening, something else is wrong. This should work:

Code: Select all

print('Registering an OnCharacterDeath event callback')
OnCharacterDeath(function(...) print('A character died') end)
print('Finished registration')
spawn all of team 1 at the killer's location, what would be a better way of doing it? A while or for loop that ends once i = the highest number on the team?
In simple terms, yes. Though it doesn't matter which type of loop you use, they all loop. But the code for it is more like:
Hidden/Spoiler:
[code]--Note: This is a slightly modified version of uf_applyFunctionOnTeamUnits(). uf_applyFunctionOnTeamUnits() only calls the cont function if the unit is alive. This version ignores the unit's alive state.
local applyFunctionOnTeamMembers = function(cont, property, value, teams, aiOrHuman)
if cont == nil then return end --if have nothing to do, then do nothing

--the teams whos units will have the given function applied to them
local teams = teams or {1, 2}

--for each team,
local team
for team = 1, table.getn(teams) do

--get the team's size
local size = GetTeamSize( teams[team] )

--for each team member,
local m
for m = 0, size-1 do

--check if the team member is the requested type
local player = GetTeamMember(teams[team], m)
local type = IsCharacterHuman(player)
if (type and (aiOrHuman == "ai")) or ((not type) and (aiOrHuman == "human")) then
--player is not the correct type
else
local unit = GetCharacterUnit(player)
cont(player, unit, property, value)
end
end
end
end

local moveUnit = function(player, unit, location, dontCare)
--force-spawn the dead player
if unit == nil then
--Use SelectCharacterClass(player, <unit class goes here>) if you want to select what they'll spawn as
SpawnCharacter(player, location)
return
end

--player is alive, so simply teleport it
SetEntityMatrix(unit, location)
end

OnCharacterDeath(function(player, killer)
if killer == nil then return end --ignore suicides and protect the GetCharacterTeam() call from bad input/arguments
if GetCharacterTeam(killer) ~= 1 then return end --we only care when team 1 kills someone

--determine the teleport destination
local killersUnit = GetCharacterUnit(killer)
if killersUnit == nil then return end --oops, the killer already died
local teleportLocation = GetEntityMatrix(killersUnit)

--table of all the teams we want to spawn against the killer
local teams = {2,}

--picking which type of players to teleport in
--"ai" to only apply to bots, "human" to only apply to humans, nil to apply to all units
local aiOrHuman = "human"

--spawn/teleport everyone
applyFunctionOnTeamMembers(moveUnit, teleportLocation, nil, teams, aiOrHuman)
end)
[/code]The above code is almost exactly what you need (it's more complicated than you need it, but it's also more flexible and someone might find it useful). It may have a couple typos. It all goes in ScriptPostLoad.
razac920
2nd Lieutenant
2nd Lieutenant
Posts: 365
Joined: Sun Jan 16, 2011 12:42 am

Re: Kill The Target example question

Post by razac920 »

Also, another bug -- GetEntityMatrix takes an object as an input, but killer is a character. So you'd need to replace killer with GetCharacterUnit(killer). Obviously this wouldn't work if the killer happens to be dead (such as getting a kill with a mine after death). And I'm not sure why you'd want each kill to be rewarded with an allied spawn at your location. I don't remember ever seeing that feature in Kill the Target.

EDIT: Nevermind, sorry, Zerted already mentioned those in his example on the last post.
jedimoose32
Field Commander
Field Commander
Posts: 938
Joined: Thu Jan 24, 2008 12:41 am
Projects :: Engineering Degree
Location: The Flatlands of Canada

Re: Kill The Target example question

Post by jedimoose32 »

Yeah the original code is very strange. I ended up removing about half of it and, true to what Zerted said, the code is now about 3 times as long (and still not done). I've removed the part of the code that I asked about originally, since that wasn't really useful at all. I'll share the finished code once I'm done with it (and give credit to Noobasaurus for the original).

Edit: I'm having some trouble with MapAddEntityMarker. I have two targets. They're supposed to be killed in a certain order. The map marker code for the first one looks like this:
Hidden/Spoiler:
[code]
dummy = CreateTimer("dummy")
SetTimerValue(dummy, 0.5)
StartTimer(dummy)
print("Timer dummy elapsed")

OnTimerElapse(
function(timer)
ClearAIGoals(2)
AddAIGoal(2, "follow", 1000, GetCharacterUnit(target1))
MapAddEntityMarker(GetCharacterUnit(target1), "hud_objective_icon_circle", 5, 1, "RED", true, true, true) --map marker
DestroyTimer(dummy)
print("Map marker created")
end,
dummy
)
[/code]
That works fine. But then the second one causes this error in my log:

Code: Select all

Message Severity: 3
.\Source\LuaHelper.cpp(312)
CallProc failed: bad argument #1 to `MapAddEntityMarker' (string expected, got nil)
stack traceback:
	[C]: in function `MapAddEntityMarker'
	(none): in function <(none):262>
Here's how I called it:
Hidden/Spoiler:
[code]
target1 = GetTeamMember(3,0)
target2 = GetTeamMember(3,1)
playerone = GetTeamMember(1,0)
AddAIGoal(3, "deathmatch", 100)
AddAIGoal(4, "deathmatch", 100)
SetClassProperty("cis_hero_darthmaul", "MaxSpeed", 4.0)
SetClassProperty("cis_hero_countdooku", "MaxSpeed", 4.0)
SetClassProperty("cis_inf_rifleman", "MaxSpeed", 4.0)
SelectCharacterClass(target1, "cis_hero_darthmaul")
SelectCharacterClass(target2, "cis_hero_countdooku")
SpawnCharacter(target1, GetPathPoint("cp4_spawn", 0))
SpawnCharacter(target2, GetPathPoint("cp4_spawn", 0))
print("Target setup complete")

...

function EnemyDistance()
detected = 0
for unitnum = 0, 9 do --make sure this is updated to reflect the number of people on team 2, or face the consequences
enemynum = GetTeamMember(2,unitnum)
xenemy,yenemy,zenemy = GetWorldPosition(GetCharacterUnit(enemynum))
print("\nGetting enemy X: " .. xenemy)
print("Getting enemy Y: " .. yenemy)
print("Getting enemy Z: " .. zenemy)
if (math.abs(xenemy - xplayer) <= 16) and (math.abs(zenemy - zplayer) <= 16) then
print("Enemy too close")
ShowMessageText("level.jer.noevade")
StartTimer(noevadetimer)
detected = detected + 1
break
else
print("Enemy far enough away, moving on")
end
end
if detected == 0 then
print("State: Anonymous")
SetTeamAsFriend(1,2)
SetTeamAsFriend(2,1)
ClearAIGoals(2)
ShowMessageText("level.jer.evadecomplete")
if numTargetsDone == 1 then
StartTimer(switchtargettimer)
end
end
end

OnTimerElapse(
function(timer)
if numTargetsDone == 1 then
StopTimer(switchtargettimer)
SetTimerValue(switchtargettimer, 0.5)
ClearAIGoals(2)
AddAIGoal(2, "follow", 1000, GetCharacterUnit(target2))
MapAddEntityMarker(GetCharacterUnit(target2), "hud_objective_icon_circle", 5, 1, "RED", true, true, true) --map marker
print("Second map marker created")
ShowMessageText("level.jer.kill2")
end
end,
switchtargettimer)
[/code]
Any idea what I'm doing wrong? (Edit 2: added the part of the code that defines my targets so you can see they are set up the same way)

Never mind. Apparently I forgot to munge before I tried this code. What I posted actually does work. This is what happens when I spend too long on the same issue. I think I need to take more walks while I'm working on BF2 stuff...
Post Reply