More Scripting Help Needed

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
Noobasaurus
Droid Pilot Assassin
Droid Pilot Assassin
Posts: 2006
Joined: Tue Aug 17, 2010 5:56 pm

More Scripting Help Needed

Post by Noobasaurus »

I'm trying to make it so that a number is one or two. Then it will affect the corresponding team and select a random team member. The selected team member's team will be changed to a different team. Right now, it's not changing the person's team AFAIK and if there is no one on the chosen team it dies. I'm not sure how to check if there's no value at all. Here's the snipped that needs work:
Hidden/Spoiler:
[code]
local nume = math.floor(ScriptCB_random()+1)
print("Today's lucky number is", nume)
SetReinforcementCount(4, 1)
OnTimerElapse(
function(timer)
if (GetNumTeamMembersAlive(2) + GetNumTeamMembersAlive(1)) >= 2 then
if GetNumTeamMembersAlive(num) == nil then
if GetNumTeamMembersAlive(2) > 0 then
nume = 2
print("Lucky number changed to ", nume)
end
if GetNumTeamMembersAlive(1) > 0 then
nume = 1
print("Lucky number changed to ", nume)
end
end
SetProperty("cp1", "Team", "0")
SetProperty("cp2", "Team", "0")
SetProperty("cp3", "Team", "0")
SetProperty("cp6", "Team", "0")
SetProperty("cp7", "Team", "0")
SetProperty("cp8", "Team", "0")
SelectCharacterTeam(GetTeamMember(nume, (math.floor(ScriptCB_random()*GetNumTeamMembersAlive(nume))-1)), 4)
print("Someone selected from team ", nume)
print("Team member selected: ", (math.floor(ScriptCB_random()*GetNumTeamMembersAlive(nume))-1))
ShowMessageText("level.0TT.begin")
StartTimer(win)
StartTimer(check)
StartTimer(checker)
ShowTimer(win)
DestroyTimer(timer)
end
if (GetNumTeamMembersAlive(2) + GetNumTeamMembersAlive(1)) <= 1 then
ShowMessageText("level.0TT.nope")
SetTimerValue(grace, 30)
StartTimer(grace)
end
end,
grace
)[/code]
The two ifs within if GetNumTeamMembersAlive(num) are relatively new (along with the if GetNumTeamMembersAlive(num)). I'm trying to make them check if there is anyone on the team that was selected. If there isn't anyone on the team, then it sets it to the other team so someone can actually be chosen. I'm pretty much out of ideas on how to do this. As per usual, help is greatly appreciated.
razac920
2nd Lieutenant
2nd Lieutenant
Posts: 365
Joined: Sun Jan 16, 2011 12:42 am

Re: More Scripting Help Needed

Post by razac920 »

OK, first of all I would use 0 instead of nil.
Mostly, your problem is with this line of code:
SelectCharacterTeam(GetTeamMember(nume, (math.floor(ScriptCB_random()*GetNumTeamMembersAlive(nume))-1)), 4)
You aren't checking if GetTeamMember returns a player at all, and if it does, is the player alive, and you also aren't randomly picking a team member, either. The team members are not indexed to have the alive ones first. Here's what you should do instead:

Code: Select all

local alive = false
local player = nil
while not alive do
  local index = math.floor(ScriptCB_random()*GetTeamSize(nume))) // not GetNumTeamMembersAlive and not -1
  player = GetTeamMember(nume, index)
  if player and GetCharacterUnit(player) and IsObjectAlive(player) then
    SelectCharacterTeam(player,4)
    alive = true
  end
end
Noobasaurus
Droid Pilot Assassin
Droid Pilot Assassin
Posts: 2006
Joined: Tue Aug 17, 2010 5:56 pm

Re: More Scripting Help Needed

Post by Noobasaurus »

So I messed around with what you put, and I finally arrived here. When the function goes off, the game freezes and spams the log indefinitely. Here's what it says:

Code: Select all

Message Severity: 2
C:\Battlefront2\main\Battlefront2\Source\LuaCallbacks_Mission.cpp(635)
Entity "1" not found
I'm not sure why it can't find people. It's searching both teams from the amount of people alive on each team. The variable changes each time it doesn't work so it keeps searching. Here's what I have currently:

Code: Select all

				while not alive do
					print("Testing random character for selection...")
					nume = math.floor(ScriptCB_random()*2)+1
					print("RANDOM NUMBER:", nume)
					index = math.floor(ScriptCB_random()*GetNumTeamMembersAlive(nume)) --// not GetNumTeamMembersAlive and not -1
					player = GetTeamMember(nume, index)
					if player and GetCharacterUnit(player) and IsObjectAlive(player) then
						SelectCharacterTeam(player,4)
						alive = true
					end
				end
nume always returns either 1 or 2. I just don't know why it can't find people when there are obviously people running around.

I also have the variables first set up before this.
razac920
2nd Lieutenant
2nd Lieutenant
Posts: 365
Joined: Sun Jan 16, 2011 12:42 am

Re: More Scripting Help Needed

Post by razac920 »

Noobasaurus wrote:It's searching both teams from the amount of people alive on each team.
This is your problem! Suppose there is a team of 2 players, the first one dead and the second alive, as follows:
GetTeamMember(nume,0) is dead and GetTeamMember(nume,1) is alive. If you use what you had:
index = math.floor(ScriptCB_random()*GetNumTeamMembersAlive(nume)), you will do math.floor([num from 0 to 1]*1) = 0 every time, and you will NEVER find the alive player. If instead you use GetTeamSize, like I originally told you, you will do math.floor([num from 0 to 1]*2), which half the time will give 1, the index for the ALIVE player. There is NO way to directly search for alive players (unless you make a list of them and continually update it as players spawn and die), so it's much easier and better to just randomly pick players (alive or dead) repeatedly until you find an alive one.

Also, I forgot that while loops don't always work right, so switch to a for loop like so:
Hidden/Spoiler:
[code]
for i=1,10000 do -- probability of not picking the 1 alive player out of 200 in 10000 trials is (199/200)^10000~10^-22, so safe
print("Testing random character for selection...")
nume = math.floor(ScriptCB_random()*2)+1
print("RANDOM NUMBER:", nume)
index = math.floor(ScriptCB_random()*GetTeamSize(nume))
player = GetTeamMember(nume, index)
if player and GetCharacterUnit(player) and IsObjectAlive(player) then
SelectCharacterTeam(player,4)
i=10000
end
end
[/code]
Noobasaurus
Droid Pilot Assassin
Droid Pilot Assassin
Posts: 2006
Joined: Tue Aug 17, 2010 5:56 pm

Re: More Scripting Help Needed

Post by Noobasaurus »

I did some stuff with that and it works pretty well. However, my continuous timers that check if there are people alive on team 4 don't seem to be working properly. You said that there is no way to get the number of alive people on a team, so how would I do this? Here's what I have:

Code: Select all

				for i=1,10000 do -- probability of not picking the 1 alive player out of 200 in 10000 trials is (199/200)^10000~10^-22, so safe
					print("Testing random character for selection...")
					nume = math.floor(ScriptCB_random()*2)+1
					print("TEAM:", nume)
					index = math.floor(ScriptCB_random()*GetTeamSize(nume))
					print("MEMBER:", index)
					player = GetCharacterUnit(GetTeamMember(nume, index))
					if player and IsObjectAlive(player) then
						SetObjectTeam(player, 4)
						i=10000
					end
				end

	OnTimerElapse(
	  function(timer)
		if (GetNumTeamMembersAlive(1) + GetNumTeamMembersAlive(2)) < 1 then
			MissionDefeat(1)
			MissionDefeat(2)
			MissionDefeat(3)
			MissionVictory(4)
			DestroyTimer(timer)
		end
		if GetNumTeamMembersAlive(4) < 1 then
			MissionVictory(1)
			MissionVictory(2)
			MissionVictory(3)
			MissionDefeat(4)
			DestroyTimer(timer)
		end
		SetTimerValue(checker, 0.1)
		StartTimer(checker)
	  end,
	checker
	)
razac920
2nd Lieutenant
2nd Lieutenant
Posts: 365
Joined: Sun Jan 16, 2011 12:42 am

Re: More Scripting Help Needed

Post by razac920 »

Oh a nonstop timer going? That could be messy and slow things down, much easier and better to check GetNumTeamMembersAlive only after someone dies, so use OnCharacterDeath instead (check name for accuracy). And sorry I didn't say there isn't a way to get the number of alive people, there IS, that is what the function GetNumTeamMembersAlive does, HOWEVER, you won't know the indices of the alive players on the team (meaning which character is returned from GetTeamMember(teamnum,index)), so you must choose random numbers at least in the range from 0 to GetTeamSize(teamnum)-1 to be guaranteed of eventually choosing a living player.
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: More Scripting Help Needed

Post by [RDH]Zerted »

I felt like writing some code:
Hidden/Spoiler:
[code]NumPlayersAlive = [0, 0, 0, 0] --4 spots for 4 teams, tracks alive counts

CharacterTeam = [] --tracks which team each characters' unit is supposed to be on

CheckVictory = function()
--game over check. You need to make sure at least one player spawns on team 4 before any players die else the game will end
if NumPlayersAlive[1] <= 0 and NumPlayersAlice[2] <= 0 then
MissionDefeat({1,2,3})
else if NumPlayersAlive[4] <= 0 then
MissionVictory({1,2,3})
end
end

Shuffle = function(list)
local size = #list

while size >= 2 do
local index = math.random(n) --1 <= index <= n
list[size], list[index] = list[index], list[size]
end

return list
end


--------------------------------------------------------------------------------

--Find the first random player that's alive
--We don't continually loop or continually pick random numbers because there's a chance all the players are dead. We only need to go through them all once. Anything more is wasting CPU time.

--pick a random team
local team = 1
if (ScriptCB_random() > 0.5) then
team = 2

--building a list of all valid ids for this team
local size = GetTeamSize(team)
local teamMembers = []
local m
for m = 0, size-1 do
teamMemberIds.append(m)
end

--randomize player order
teamMemberIds = Shuffle(teamMemberIds)

--find the first living player
local allDead = true
for m = 0, size-1 do
local player = GetTeamMember(team, teamMemberIds[m+1])
local unit = GetCharacterUnit(player)
if unit ~= nil then
allDead = false

--move this player onto team 4
SetProperty(unit, 'Team', 4)
SetProperty(unit, 'PerceivedTeam' 4)
CharacterTeam[character] = 4
NumPlayersAlive[4] += 1
NumPlayersAlive[team] -= 1
CheckVictory()

break --stops the loop
end
end
if allDead then
--no one was alive on the team. If you trying them all again now, they'll probably still all be dead. Best to wait 15 seconds before trying again, or better yet, loop through CharacterTeam and change one of the team numbers. When that player respawns he'll be on the new team.
end

--------------------------------------------------------------------------------

--tracking the amount of spawned players on each team
OnCharacterSpawn(function(character)
local unit = GetCharacterUnit(character)
local expectedTeam = CharacterTeam[character] or GetObjectTeam(unit)

--make sure swapped characters stay on their new team
SetProperty(unit, 'Team', expectedTeam)
SetProperty(unit, 'PerceivedTeam' expectedTeam)

--update tracking
CharacterTeam[character] = expectedTeam
NumPlayersAlive[expectedTeam] += 1
end)
OnCharacterDeath(function(character)
local uTeam = CharacterTeams[character]
NumPlayersAlive[uTeam] -= 1
CheckVictory()
end)

--------------------------------------------------------------------------------
[/code]
I'm not sure what your end goal is so I'm not sure if this is what you wanted or not. It also probably has a typo or two as I can't test it.
Noobasaurus
Droid Pilot Assassin
Droid Pilot Assassin
Posts: 2006
Joined: Tue Aug 17, 2010 5:56 pm

Re: More Scripting Help Needed

Post by Noobasaurus »

Thank you so much for writing this code for me Zerted. I'm trying to make it work but some things written I thought looked like SWBF2 functions so I changed those. The munger was spitting out an error at the first line and I didn't know what was wrong so I commented it out. When it got to the line with #list, it spat out another error. Now I'm really confused because it doesn't look wrong at all.
Hidden/Spoiler:
[code]
---------------------------------------------------------------------
-- GetNumTeamMembersAlive = (0, 0, 0, 0) --4 spots for 4 teams, tracks alive counts

--CharacterTeam = () --tracks which team each characters' unit is supposed to be on

CheckVictory = function()
--game over check. You need to make sure at least one player spawns on team 4 before any players die else the game will end
if GetNumTeamMembersAlive(1) <= 0 and GetNumTeamMembersAlive(2) <= 0 then
MissionDefeat({1,2,3})
else if GetNumTeamMembersAlive(4) <= 0 then
MissionVictory({1,2,3})
end
end

Shuffle = function(list)
local size = #list

while size >= 2 do
local index = math.random(n) --1 <= index <= n
list(size), list(index) = list(index), list(size)
end

return list
end


--------------------------------------------------------------------------------

--Find the first random player that's alive
--We don't continually loop or continually pick random numbers because there's a chance all the players are dead. We only need to go through them all once. Anything more is wasting CPU time.

--pick a random team
local team = 1
if (ScriptCB_random() > 0.5) then
team = 2

--building a list of all valid ids for this team
local size = GetTeamSize(team)
local teamMembers = ()
local m
for m = 0, size-1 do
teamMemberIds.append(m)
end

--randomize player order
teamMemberIds = Shuffle(teamMemberIds)

--find the first living player
local allDead = true
for m = 0, size-1 do
local player = GetTeamMember(team, teamMemberIds(m+1))
local unit = GetCharacterUnit(player)
if unit ~= nil then
allDead = false

--move this player onto team 4
SetProperty(unit, 'Team', 4)
SetProperty(unit, 'PerceivedTeam' 4)
GetCharacterTeam(character) = 4
GetNumTeamMembersAlive(4) += 1
GetNumTeamMembersAlive(team) -= 1
CheckVictory()

break --stops the loop
end
end
if allDead then
--no one was alive on the team. If you trying them all again now, they'll probably still all be dead. Best to wait 15 seconds before trying again, or better yet, loop through CharacterTeam and change one of the team numbers. When that player respawns he'll be on the new team.
end

--------------------------------------------------------------------------------

--tracking the amount of spawned players on each team
OnCharacterSpawn(function(character)
local unit = GetCharacterUnit(character)
local expectedTeam = GetCharacterTeam(character) or GetObjectTeam(unit)

--make sure swapped characters stay on their new team
SetProperty(unit, 'Team', expectedTeam)
SetProperty(unit, 'PerceivedTeam' expectedTeam)

--update tracking
GetCharacterTeam(character) = expectedTeam
GetNumTeamMembersAlive(expectedTeam) += 1
end)
OnCharacterDeath(function(character)
local uTeam = GetCharacterTeam(character)
GetNumTeamMembersAlive(uTeam) -= 1
CheckVictory()
end)[/code]
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: More Scripting Help Needed

Post by [RDH]Zerted »

Sorry, but change them back. NumPlayersAlive and CharacterTeam are supposed to be global array variables (technically dictionaries in Lua). You use brackets to access elements like: array[2] to get the 2nd item stored in the array. () are used for functions, not for arrays.

However I should have used curly brackets to create the arrays. It should be {0, 0, 0, 0} and {} compared to using () or [] for those first two lines. Sorry about that. I've been programming in Python all week and Python and Lua are too similar. Also change local teamMembers = () to use curly braces: local teamMembers = {}. Everywhere else where I used [] should have stayed as [].

# is a shortcut for table.getn(), but maybe SWBF2's version of Lua is too old to have it. Change that line to: local size = table.getn(list)



GetNumTeamMembersAlive/NumPlayersAlive, CharacterTeam, CheckVictory, and Shuffle should be put at the top of your Lua file. You should probably put the middle section (random player selection) into it's own function which will be before ScriptPostLoad. It'll be called by something in ScriptPostLoad. Inside ScriptPostLoad put the OnCharacterDeath/Spawn code.
Noobasaurus
Droid Pilot Assassin
Droid Pilot Assassin
Posts: 2006
Joined: Tue Aug 17, 2010 5:56 pm

Re: More Scripting Help Needed

Post by Noobasaurus »

I reverted everything back and made all of the changed you listed. It still doesn't like NumPlayersAlive = [0, 0, 0, 0] line. It says that there is an unexpected symbol next to the bracket. Now the brackets aren't the problem because the shuffle part is loaded before that now. I figured something out yay

I have the things below before ScriptPostLoad.
Hidden/Spoiler:
[code]
Shuffle = function(list)
local size = table.getn(list)

while size >= 2 do
local index = math.random(n) --1 <= index <= n
list[size], list[index] = list[index], list[size]
end

return list
end

NumPlayersAlive = [0, 0, 0, 0] --4 spots for 4 teams, tracks alive counts

CharacterTeam = [] --tracks which team each characters' unit is supposed to be on

CheckVictory = function()
--game over check. You need to make sure at least one player spawns on team 4 before any players die else the game will end
if NumPlayersAlive[1] <= 0 and NumPlayersAlive[2] <= 0 then
MissionDefeat({1,2,3})
else if NumPlayersAlive[4] <= 0 then
MissionVictory({1,2,3})
end
end

--pick a random team
local team = 1
if (ScriptCB_random() > 0.5) then
team = 2

--building a list of all valid ids for this team
local size = GetTeamSize(team)
local teamMembers = {}
local m
for m = 0, size-1 do
teamMemberIds.append(m)
end

--randomize player order
teamMemberIds = Shuffle(teamMemberIds)
[/code]
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: More Scripting Help Needed

Post by [RDH]Zerted »

Change it to:

Code: Select all

NumPlayersAlive = {0, 0, 0, 0} --4 spots for 4 teams, tracks alive counts

CharacterTeam ={} --tracks which team each characters' unit is supposed to be on
You'll probably want all the code starting with line "--pick a random team" and afterwards somewhere else. Likely in a timer or something inside ScriptPostLoad.
Post Reply