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.
Re: Kill The Target example question
Posted: Mon Mar 09, 2015 1:35 am
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.
Re: Kill The Target example question
Posted: Mon Mar 09, 2015 1:45 am
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?
Re: Kill The Target example question
Posted: Mon Mar 09, 2015 10:05 pm
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:
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.
Re: Kill The Target example question
Posted: Tue Mar 10, 2015 12:16 am
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.
Re: Kill The Target example question
Posted: Tue Mar 10, 2015 12:21 am
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:
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>
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
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...