Page 1 of 2

Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 2:17 pm
by Noobasaurus
I've been pulling out my hair over this one. For some reason, nothing I do seems to work. I've also searched on the topic but I haven't found anything that works, either. Here's what I've tried:

Code: Select all

	Setup = OnCharacterSpawn(function(character)
		if IsCharacterHuman(character) then
			ReleaseCharacterSpawn(Setup)
			print(FindEntityClass(character))
			print(FindEntityClass(GetCharacterUnit(character)))
			print(GetEntityClass(character))
			print(GetEntityClass(GetCharacterUnit(character)))
			print(GetEntityClassName(character))
			print(GetEntityClassName(GetCharacterUnit(character)))
			Setup = nil
		end
	end)
And here are the results of each:
Hidden/Spoiler:
[code]userdata: 00000000[/code]
[code]crash[/code]
[code]
Message Severity: 2
C:\Battlefront2\main\Battlefront2\Source\LuaCallbacks_Mission.cpp(635)
Entity "0" not found
nil[/code]
[code]
userdata: 06C378C0[/code]
[code]
Message Severity: 2
C:\Battlefront2\main\Battlefront2\Source\LuaCallbacks_Mission.cpp(635)
Entity "0" not found
nil[/code]
[code]nil[/code]
Now it looks like GetEntityClass(GetCharacterUnit(character)) is the only one returning some sort of data, but I'm not sure how to get the unit's class out of it. Any ideas?

Mav also posted this but I'm not sure on how to use it.

Code: Select all

GetEntityClass(etc) == FindEntityClass("ex_type_entity")

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 4:05 pm
by Maveritchell
Yeah, nothing returns character class names simply. What you quoted from me is how to compare strings of object class names, but character class names are different. The suggestion that you're given in the Battlefront2_scripting_system.doc is to use "GetEntityClassName(GetCharacterUnit(player))," but as you've seen, that doesn't work.

What you can pull is the ID of the class (0-n) based on the order classes are loaded in (with AddUnitClass) using GetCharacterClass. I did a short test and verified this awful hackjob of a workaround, and while I'm sure you could make it cleaner, it's a starting point.

I edited SetupTeams.lua (since that's where classes are added by default) around line 17 to initialize two tables:

Code: Select all

--ADDED	
unittablemaster1 = {}	
unittablemaster2 = {}	
    
    -- for each specified side...
I then edited the for loop that adds classes to fill those (non-local) tables:

Code: Select all

        -- add unit classes in type order
		--ADDED: changed _ to index 
        for index, type in ipairs(typeList) do
            if side[type] and (not teamItems or not teamItems[name] or teamItems[name][type]) then
                AddUnitClass(team, side[type][1], side[type][2], side[type][3])
				
				--ADDED
				table.insert (unittablemaster1, {unitteam = team, unitclass = side[type][1]})
				print("Added one", index)
				print("Unittable", unittablemaster1[1].unitteam)
				if index ~= 1 and unittablemaster1[1].unitteam ~= team then
					print("Checked index")
					table.insert (unittablemaster2, {unitteam = team, unitclass = side[type][1]})
				end
				
            end
        end
Then you can call your table positions however you want. I used a test function with OnCharacterChangeClass (added to ScriptPostLoad) to test:

Code: Select all

	testname = OnCharacterChangeClass(
		function(player)
		
			if GetCharacterUnit(player) then
			
				if GetObjectTeam(GetCharacterUnit(player)) == 1 then
				print(unittablemaster1[GetCharacterClass(player) + 1].unitclass)
				elseif GetObjectTeam(GetCharacterUnit(player)) == 2 then
				print(unittablemaster2[GetCharacterClass(player) + 1].unitclass)
				end
				
			end
			
		end
	) 
That'll spit back your character class names as strings, which is what you want.

Edit: A simpler way might just to be to write a function that tests AddUnitClass for its team and class name arguments every time it's run (and make your table from that), but you'd have to make sure to run it before ScriptPostLoad. Same principle, though.

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 5:52 pm
by Noobasaurus
Awesome! Thanks, Mav.

It works fine for the most part, but somehow when it returns the name it gives the name of the unit on the opposite team. I've fiddled around with a few other things but I haven't been able to get it to work quite right.
Hidden/Spoiler:
[code]
-- for each specified side...
for name, side in pairs(sides) do
local team = side.team
unittablemaster1 = {}
unittablemaster2 = {}


-- set team properties
local name = string.lower(name)
SetTeamName(team, name)
SetTeamIcon(team, name .. "_icon", "hud_reinforcement_icon", "flag_icon")
SetUnitCount(team, side.units)
SetReinforcementCount(team, side.reinforcements)

-- add unit classes in type order
for index, type in ipairs(typeList) do
if side[type] and (not teamItems or not teamItems[name] or teamItems[name][type]) then
AddUnitClass(team, side[type][1], side[type][2], side[type][3])

table.insert (unittablemaster1, {unitteam = team, unitclass = side[type][1]})
print("Added one", index)
print("Unittable", unittablemaster1[1].unitteam)
if index ~= 1 and unittablemaster1[1].unitteam ~= team then
print("Checked index")
table.insert (unittablemaster2, {unitteam = team, unitclass = side[type][1]})
end
end
end
[/code]
Hidden/Spoiler:
[code]
Setup = OnCharacterSpawn(function(character)
if IsCharacterHuman(character) then
ReleaseCharacterSpawn(Setup)
print(GetObjectTeam(GetCharacterUnit(character)))
if GetObjectTeam(GetCharacterUnit(character)) == 1 then
print("Team 1")
print("Character Class: ", GetCharacterClass(character))
print(unittablemaster1[GetCharacterClass(character) + 1].unitclass)
elseif GetObjectTeam(GetCharacterUnit(character)) == 2 then
print("Team 2")
print("Character Class: ", GetCharacterClass(character))
print(unittablemaster2[GetCharacterClass(character) + 1].unitclass)
end
...[/code]
I put in the team checking just to make sure that it was working right, and it was. I may try the other way you suggested if I can't get this right.

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 6:19 pm
by Maveritchell
Just switch the numbers, then. It checks in the order that setupteams reads the units in (which in my test map was ALL as 1 and IMP as 2). It's not a very robust solution, just a quick one.

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 6:24 pm
by Noobasaurus
Ah, I forgot to tell you that I did that. It returns the following error:

Code: Select all

Message Severity: 3
C:\Battlefront2\main\Battlefront2\Source\LuaHelper.cpp(312)
CallProc failed: (none):0: attempt to index field `?' (a nil value)
stack traceback:
	(none): in function <(none):303>

I also tried switching the numbers of the tables, but the result is the same.

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 7:28 pm
by Maveritchell
It's hard to say exactly what's giving you the issue without seeing your setupteams section, but here's the simpler solution I talked about anyway:

Code: Select all

function CompileUnitTables()

	unittablemaster1 = {}	
	unittablemaster2 = {}	
		
	if SetHeroClass then
	
		holdsetheroclass = SetHeroClass
		
		SetHeroClass = function(...)
			if arg[1] == 1 then
				table.insert (unittablemaster1, {unitteam = arg[1], unitclass = arg[2]})
			elseif arg[1] == 2 then
				table.insert (unittablemaster2, {unitteam = arg[1], unitclass = arg[2]})				
			end	

		holdsetheroclass(unpack(arg))	
			
		end
			
	end

	if AddUnitClass then
	
		holdaddunitclass = AddUnitClass	
		
		AddUnitClass = function(...)
			if arg[1] == 1 then
				table.insert (unittablemaster1, {unitteam = arg[1], unitclass = arg[2]})
			elseif arg[1] == 2 then
				table.insert (unittablemaster2, {unitteam = arg[1], unitclass = arg[2]})				
			end
			
		holdaddunitclass(unpack(arg))	
			
		end
			
	end

end
If you put that at the top of your script (you just need to define the function first) and then add "CompileUnitTables()" to the beginning of ScriptInit (anywhere before units are loaded is fine), you'll have the same result without having to modify ScriptPostLoad (although you'll still probably want the section I included for ScriptPostLoad just to test the output). You can see this procedure used more extensively in Zerted's utility functions.

Edit: Edited to fix typo.

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 7:59 pm
by Noobasaurus
Thank you so much! It works like a charm.

Re: Getting a player's class name with lua

Posted: Sat Apr 04, 2015 8:04 pm
by razac920
I'm a little confused as to what you'd actually need the class name for. In my experience, GetCharacterClass(character) and GetCharacterTeam(character) tell you everything you need to know about a unit's class. GetCharacterClass returns a number, 0-9, with 0 being the first class in the spawn list, 1, being the second, and so on, up to 9 being the 10th (last possible) class on the list, and GetCharacterTeam tells you which team's unit list to look at.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:09 pm
by Noobasaurus
You say that GetCharacterClass only goes up to 10, which means is it looking at the team sets and not the units loaded? I need to know what class they are so that I can change it later, and not all of them are loaded in a team configuration.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:19 pm
by Maveritchell
Razac's basically saying in plaintext what the script you see above does - it catalogues added units based on class ID (GetCharacterClass) and team ID (GetCharacter/ObjectTeam). His assumption is (probably) that you have a static classlist, in which case you'd always know that ID 0 on team 1 is all_inf_trooper (for example). If you've got a variable classlist, like you mention, then it's a little more justifiable to try and check for the class name.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:23 pm
by razac920
Yes, I believe so. If a unit class is loaded but not added to a team, then there is no way for a character to spawn as that class (to the best of my knowledge). Have you ever successfully spawned a unit in a loaded class that wasn't part of a team? If I'm right, then the basic unit class setup is:
team 1:
class 0 - default rifleman
class 1 - default rocketeer
class 2 - default sniper
class 3 - default engineer
class 4
class 5
class 6
class 7
class 8
class 9

team 2:
class 0
class 1
class 2
class 3
class 4
class 5
class 6
class 7
class 8
class 9

And for example, if you called GetCharacterClass on a unit that was currently spawned as a engineer, the function would return 3 (the 4th entry on the spawn list).

Edit: You are changing the class list midgame? If you just use the function AddUnitClass to append new classes to the end, this is fine, but if you are doing something more complex (is that possible?), then the output of GetCharacterClass will not have a constant meaning. But yes, I believe Maveritchell's script should work in any case. I really just was curious why the name was important, when I would think just knowing the class # should always be sufficient.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:31 pm
by Noobasaurus
Yes, with this new information (I didn't know there was a max of 10 each) I'll have to change the class list mid game. I personally think it'll be easier to organize it based on class names and not numbers, but either way would really work.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:34 pm
by razac920
Yeah, you can't add more than 10 unit classes to any team (or 9 + 1 hero). How will you be changing the class list mid game though? To the best of my knowledge, I only know about adding additional classes with AddUnitClass to the end of the current list. Is it possible to remove classes or rearrange the order of classes? That would be a good thing to know.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:39 pm
by Noobasaurus
...well, I just thought about it. Usually people can only add or change unit classes at the start of a game, and I think that's the way it will stay. However, I've thought of a way around this that fits my mod. It will read the saved data and load the unit classes based on that, ex. You are level 10 and it will load the next 9 levels of your character or whatever. Then, once they reach the maximum level/unit for that set, they'll have to save and restart.

Or, you could load up a bunch of different teams and then do it. Would that work? 10 per team, and the unit just has to be on a team, and you don't need to be on that team.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:42 pm
by Maveritchell
You haven't ever specified what exactly your use case is. Why are you loading X "levels" of a character? It's much easier to simply modify a character class using SetClassProperty.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:44 pm
by Noobasaurus
Wait, you can modify weapons of classes using that? OH.

That saved me from 140 classes of evil.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:45 pm
by razac920
Well, humans can only be on teams 1 or 2, and can only spawn as classes of teams 1 or 2, so there is a max 20 classes that you can cycle through (all of which I used in my gun game mode). Alternatively, you can use SetClassProperty which is very handy for most applications, but necessarily limits your mod to SP if you make changes midgame.

EDIT: Well, you cannot modify the weapon properties directly, but you can modify which weapons a class uses. One BIG caveat to that approach is that you are limited to changes in the first 4 weapons (WeaponName1, 2, 3, and 4 work but not higher), so you can't fully customize all 8 weapons.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 8:46 pm
by Maveritchell
As long as you're working in a weaponsection that's already been created (i.e. in the .odf), you can modify those to your heart's content.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 9:06 pm
by razac920
Well, you can also add new weaponsections entirely, by using the labels WeaponName#, WeaponAmmo#, and WeaponChannel#, but # only works for 1-4.

Re: Getting a player's class name with lua [Solved]

Posted: Sat Apr 04, 2015 9:36 pm
by Noobasaurus
I see. Well, that makes my life much easier. Thanks guys!