Need help with GetCharacterTeam() [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
User avatar
Benoz
Corporal
Corporal
Posts: 140
Joined: Tue May 28, 2013 12:34 pm
Projects :: Clone Wars Era Mod Version 2
Games I'm Playing :: OldFront - EAFront
xbox live or psn: No gamertag set
Location: Germany

Need help with GetCharacterTeam() [Solved]

Post by Benoz »

I'm working on a lua function and I'm currently struggling with the correct usage of GetCharacterTeam().

The base of the code looks like this:

Code: Select all

OnObjectDamage
(
	function(object,attacker)
	if attacker == nil then return end
	if not IsCharacterHuman(attacker) then return end
	ScriptCB_SndPlaySound("sound")
	end
)
The above code works fine, now here's the part where I'm messing up. I want the code to only execute when the object is in the opposing team as the attacker. I tried several approaches with GetCharacterTeam() and GetObjectTeam(), but I'm pretty sure I'm not using the function correctly. I tried it like this:

Code: Select all

if GetCharacterTeam(object) == 1 and GetCharacterTeam(attacker) == 1 then return end
if GetCharacterTeam(object) == 2 and GetCharacterTeam(attacker) == 2 then return end
if GetCharacterTeam(object) == 0 then return end
then I tried it like this:

Code: Select all

if GetCharacterTeam(attacker) == if GetCharacterTeam(object) or if GetCharacterTeam(object) == 0 then return end
and like this:

Code: Select all

attackerTeam = GetCharacterTeam(attacker)
objectTeam = GetCharacterTeam(object)
if attackerTeam  == objectTeam  or if objectTeam  == 0 then return end
This is the error I'm getting:
CallProc failed: bad argument #1 to `GetCharacterTeam' (number expected, got userdata)
stack traceback:
[C]: in function `GetCharacterTeam'
(none): in function <(none):91>
Can anyone tell me how to implement this code corretly so it checks if the object that gets hit is on the enemy team?
Last edited by Benoz on Sat Mar 13, 2021 7:39 pm, edited 1 time in total.
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: Need help with GetCharacterTeam()

Post by Sporadia »

GetCharacterTeam() won't work on a regular object, only characters. Your event is fetching you userdata for your object and the character index of the attacker. The attacker's character index is a number from 1 to 64 (I think); every player on the battlefield has a different character index. GetCharacterTeam(characterIndex) uses the character index to tell you what team a player or AI is currently on.

Userdata isn't even a number, it's a completely different data type so it's crashing the function. Every object that's spawned on the map has a unique piece of userdata, so that's what you're being given to identify the object (because there are other functions in the game that use userdata). Such as GetObjectTeam(userdata) which I think is what you want.

Also userdata is a good test for if characters are alive because it only exists for spawned objects. If you ever need the userdata of a character you can find it with GetCharacterUnit(characterIndex). Dead characters return null. Just giving you a heads up because the userdata that you're given for the object might not work after the object's been destroyed. That's always something to be aware of.

Edit: I'd suggest this:

Code: Select all

if object then -- check object is alive
    if GetObjectTeam(object) == GetCharacterTeam(attacker) then
    return
else
    -- object is dead
    return
end
Last edited by Sporadia on Mon Mar 08, 2021 3:09 pm, edited 3 times in total.
User avatar
Benoz
Corporal
Corporal
Posts: 140
Joined: Tue May 28, 2013 12:34 pm
Projects :: Clone Wars Era Mod Version 2
Games I'm Playing :: OldFront - EAFront
xbox live or psn: No gamertag set
Location: Germany

Re: Need help with GetCharacterTeam()

Post by Benoz »

Alright, thanks for the explanation. Although if I use GetObjectTeam() with one of my code attempts, it's giving me this error:
Entity "0" not found
The sound is playing fine. But now the problem is it plays on the enemy and the allied units. Can you tell me if the generell approach of 'checking if the hit unit is in the enemy team' is correct?
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: Need help with GetCharacterTeam()

Post by Sporadia »

Benoz wrote:
Mon Mar 08, 2021 3:07 pm
Alright, thanks for the explanation. Although if I use GetObjectTeam() with one of my code attempts, it's giving me this error:
Entity "0" not found
Do you get the error when the object is dead or alive? See my edit above.
Benoz wrote:
Mon Mar 08, 2021 3:07 pm
The sound is playing fine. But now the problem is it plays on the enemy and the allied units. Can you tell me if the generell approach of 'checking if the hit unit is in the enemy team' is correct?
Don't know. I've never used lua to play sounds before. I can't tell if you mean the sound is physically playing in the wrong place, or if you mean that the sound is playing when players shoot other team members. Or if you mean that you only want the sound to play when one team is shot and not the other.

Edit: try this to see what happens

Code: Select all

print("Object:", object) -- don't use .. for userdata or the print will crash
print("Attacker: "..attacker)
print("Object Team: "..GetObjectTeam(object))
print("Attacker Team: "..GetCharacterTeam(attacker))
Sorry if I'm remembering the syntax wrong.
Last edited by Sporadia on Fri Mar 12, 2021 9:24 am, edited 2 times in total.
User avatar
AnthonyBF2
Sith
Sith
Posts: 1255
Joined: Wed Aug 21, 2013 3:55 pm
Projects :: PS2+PSP Overhaul

Re: Need help with GetCharacterTeam()

Post by AnthonyBF2 »

Try messing around with BroadcastVoiceOver, it allows you to specify which team hears the sounds, this function is heavily used in space maps, if you kill the empire's engines, two sounds will be played but only one for one team, empire hears "our engines are destroyed" and rebels here "their engines are destroyed"

Here is an example code I pulled from spa1g_Diet Dr. Pepper.lua:

BroadcastVoiceOver( "IOSMP_obj_20", IMP )
BroadcastVoiceOver( "AOSMP_obj_21", ALL )
User avatar
Benoz
Corporal
Corporal
Posts: 140
Joined: Tue May 28, 2013 12:34 pm
Projects :: Clone Wars Era Mod Version 2
Games I'm Playing :: OldFront - EAFront
xbox live or psn: No gamertag set
Location: Germany

Re: Need help with GetCharacterTeam()

Post by Benoz »

No, what I mean is the sound function works. What doesn't work is the implementation of 'check if target hit is on enemy team'. That's where I'm struggling with. With this code:

Code: Select all

OnObjectDamage
(
	function(object,attacker)
	if attacker == nil then return end
	if not IsCharacterHuman(attacker) then return end
	ScriptCB_SndPlaySound("sound")
	end
)
the sound plays whenever I hit an object, whether it's an enemy, ally or destructable prop. But I want this function to execute only if the 'object' from the function is on the enemy team and else return to end.

EDIT: I get the 'Entity "0" found' even whit the target alive.
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: Need help with GetCharacterTeam()

Post by Sporadia »

Just to double check, are you still using the GetCharacterTeam() function for the attacker?

If you are, then I don't understand why GetObjectTeam(object) is throwing an error. It's possible that I'm wrong about what argument the function takes. There are mission scripts where the function works but they are in different events like OnObjectKill. I don't know if the object in OnObjectKill is different to the object in OnObjectDamage. Maybe you could try it with a pointer, but that's a guess.

eg

Code: Select all

if object then
    objectPtr = GetObjectPtr(object)
    if GetObjectTeam(objectPtr) == GetCharacterTeam(attacker) then
        -- friendly fire
        return
    end
else
    -- destroyed object
    return
end
MileHighGuy
Jedi
Jedi
Posts: 1194
Joined: Fri Dec 19, 2008 7:58 pm

Re: Need help with GetCharacterTeam()

Post by MileHighGuy »

GetCharacterTeam(attacker) will work

GetCharacterTeam(object) will give the error (because object is not a character)


also maybe use this instead:

Code: Select all

OnObjectDamageTeam(function(object, attacker) 
	if GetCharacterTeam(attacker) ~= objectTeam then
	--do stuff
	print("Hey, you damaged the enemy object!")
	end
end, objectTeam)
that way you already have the team of the damaged object

Let me know if that works

you ought to add the safety checks like Sporadia did... but that is the basic idea to try


While I am here.. This is how I make debug print statements that don't crash if the value is nil.

Code: Select all

print( "object value is " .. tostring(object) )
the "tostring" will make it print "nil" if it is nil. otherwise you get an error trying to print if its nil.
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: Need help with GetCharacterTeam()

Post by Sporadia »

MileHighGuy wrote:
Fri Mar 12, 2021 2:02 am
GetCharacterTeam(object) will give the error (because object is not a character)
That was causing the "expecting number, found userdata" error. But the "Entity "0" not found" error is happening with GetObjectTeam. My first guess is that they've used the line GetObjectTeam(attacker), which won't work because attacker is a Character Index. Just because Character Index 0 is normally the human player, it looks like a plausible error message.

But assuming that they haven't done that, then GetObjectTeam(object) is a confusing error. Unless there's something unusual about the data for the object that OnObjectDamage gives you. You can definitely use GetObjectTeam(object) inside of OnObjectKill with no problems because it's in the stock missions. But it's weird because GetCharacterUnit gives you userdata that only exists when the character is alive. Whereas OnObjectKill or OnObjectHeadshot must give you userdata that still exists after the object is dead. That's why I was wondering if they use a pointer.
MileHighGuy wrote:
Fri Mar 12, 2021 2:02 am
you ought to add the safety checks like Sporadia did... but that is the basic idea to try
This might have been overkill from me. They don't check for destroyed objects in the stock missions.

Does print always crash when you try to print nil, or does it only crash when you try to concatenate nil (ie ..nil)? I feel like I've managed to print nil before and I've never thought to use tostring(). ..object would always crash anyway because you can't concatenate userdata.
But I guess it's worth testing GetObjectTeam(object) on it's own, just in case that's not the cause of the error.

Edit:
MileHighGuy wrote:
Fri Mar 12, 2021 2:02 am
also maybe use this instead:

Code: Select all

OnObjectDamageTeam(function(object, attacker) 
	if GetCharacterTeam(attacker) ~= objectTeam then
	--do stuff
	print("Hey, you damaged the enemy object!")
	end
end, objectTeam)
If this works then that's a really cool use for event filters. But it requires OnObjectDamageTeam to trigger without a filter, and fill in objectTeam for you. I don't think events are that clever. What I expect to happen is that it will think objectTeam is a variable from outside the event, and that you're trying to pass it a filter that's stored inside objectTeam. So you might even get a munge error. Or you'll get an event that only triggers for team nil / treats the contents of objectTeam like a filter. I don't even think you can use variables to change filters midgame; I'm pretty sure whatever value is in objectTeam when the game reaches the line OnObjectDamageTeam, it will permanently become the event's filter (ie it doesn't remember the filter was objectTeam, it just creates an event with filter nil or 1 etc, I remember having this problem).

But what you can do instead is write an OnObjectDamageTeam with the filter 1, and a separate OnObjectDamageTeam with the filter 2. And then you know that the first event triggers when the object is team 1, and in the second event it's 2.

Edit 2: I wrote about using a for loop to make both events in one go, but it doesn't work.
User avatar
Benoz
Corporal
Corporal
Posts: 140
Joined: Tue May 28, 2013 12:34 pm
Projects :: Clone Wars Era Mod Version 2
Games I'm Playing :: OldFront - EAFront
xbox live or psn: No gamertag set
Location: Germany

Re: Need help with GetCharacterTeam()

Post by Benoz »

Unfortunately, MileHigh, your code is giving me a completely different error now. OnObjectDamageTeam causes the AI not to spawn at all, so I am the only one on the map.

But the code from Sporadia did the trick. I am using this:

Code: Select all

OnObjectDamage(function(object,attacker)

	if attacker == nil then return end
	if not IsCharacterHuman(attacker) then return end
	if object then
		objectPtr = GetObjectPtr(object)
		if GetObjectTeam(objectPtr) == 0 then return end
		if GetObjectTeam(objectPtr) == GetCharacterTeam(attacker) then return end
	else return end
			
	print("test")
	ScriptCB_SndPlaySound("snd_hitmarker")
end)
and the sound is only playing when you hit enemy units. Perfect :)

Thank you guys for the help! :thumbs:
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: Need help with GetCharacterTeam() [Solved]

Post by Sporadia »

That's really good. There's no good documentation on what arguments the functions use. But this thread suggests these ones work like this:

Code: Select all

OnObjectDamage(
    function(objectData, attackerCharIndex)
)

Code: Select all

OnObjectKill(
    function(objectPtr, killerCharIndex)
)

Code: Select all

GetObjectTeam(objectPtr)

Code: Select all

GetCharacterTeam(charIndex)

Code: Select all

GetObjectPtr(objectData)
^ Returns objectPtr

Code: Select all

GetCharacterUnit(charIndex)
^ Returns charData (or charUnit if you prefer to call it that), charData is the same as objectData
Post Reply