Enhanced Common.lvl by Phobos January 2015
Improves various LUA scripts to add more online features, everything else is default except for two invisible textures: border_3_pieces.tga and border_3a_pieces.tga
Included Main Features
Pause Menu: Freecam and Exit To Windows - http://www.swbfgamers.com/index.php?topic=4225
Multiplayer Lobby: Player Count and Mission Time - http://www.swbfgamers.com/index.php?topic=7941
End Stats: Exit To Windows, Restart Mission, Server Name, Mission Time - http://www.swbfgamers.com/index.php?topic=8712
Disable Menu Button Flashing: Discovered by Phobos, open interface_util.lua and change the numbers on line 1378 to 0.
-- local num = random(1,50) -- old value
local num = random(0,0) -- new value
Features
- Removed startdelay for stats screen load.
- Changed text and added colors to buttons. 
- Added Exit To Windows, works in SP and MP. If the server hangs at 0 this will freeze the game, but this is rare.
- Added Restart Mission, is intended for SP/Campaigns. If used in MP, it will reload the mission LUA for that map in SP.
- Added Mission Time to top right corner. This will reset to 0 if you rejoin the server before the current round ends, so it's only accurate if you are in the server from start to finish. Divide by 60 for total minutes.
- Added Server Name to top left corner. When the score screen first loads click Awards or Details then go back to the main stats page and it will show Server Name + Mission Time right away, otherwise you have to wait.
Enhanced Teamstats Preview - http://i.imgur.com/7QhTL7z.png
ifs_teamstats.lua mod source by Phobos
---- Enhanced ifs_teamstats.LUA by Phobos
-- Multiplayer game name screen.
-- Helper function. Given a layout (x,y,width, height), returns a
-- fully-built item.
function Teamstats_Listbox_CreateItem(layout)
	local insidewidth = layout.width - 10;
	-- Make a coordinate system pegged to the top-left of where the cursor would go.
	local Temp = NewIFContainer {
		x = layout.x - 0.5 * insidewidth, y=layout.y,
		bInertPos = 1,
	}
	Temp.labelstr = NewIFText {
		HScale = 0.8,
		VScale = 1,
		x = 2, y = -10, textw = 0.65 * insidewidth, 
		texth = ScriptCB_GetFontHeight("gamefont_small"),
		clip = "character",
		halign = "left", font = "gamefont_small",
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	local WidthPer = insidewidth * 0.133
	Temp.val1str = NewIFText{
		HScale = 0.8,
		VScale = 1,
		x = insidewidth - WidthPer * 3, y = -10, 
		textw = WidthPer, halign = "right", font = "gamefont_small",		
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	Temp.val2str = NewIFText{
		HScale = 0.8,
		VScale = 1,
		x = insidewidth - WidthPer * 2, y = -10, 
		textw = WidthPer, halign = "right", font = "gamefont_small",
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	Temp.val3str = NewIFText{ 
		HScale = 0.8,
		VScale = 1,
		x = insidewidth - WidthPer * 1, y = -10, 
		textw = WidthPer, halign = "right", font = "gamefont_small",
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	return Temp
end
-- Helper function. For a destination item (previously created w/
-- CreateItem), fills it in with data, which may be nil (==blank it)
function Teamstats_Listbox_PopulateItem(Dest,Data)
	if(Data) then
		-- force the name into word clipping
		if(Dest.labelstr.cpointer) then
			ScriptCB_IFText_SetTextBreak(Dest.labelstr.cpointer,"none")
		end
		-- Contents to show. Do so.
		IFText_fnSetUString(Dest.labelstr,Data.labelustr)
		IFText_fnSetString(Dest.val1str,Data.val1str)
		IFText_fnSetString(Dest.val2str,Data.val2str)
		IFText_fnSetString(Dest.val3str,Data.val3str)
-- 		IFText_fnSetString(Dest.labelstr,"WWWWWWWWWWWWWWM")
-- 		IFText_fnSetString(Dest.val1str,"11111")
-- 		IFText_fnSetString(Dest.val2str,"22222")
-- 		IFText_fnSetString(Dest.val3str,"33333")
		if(Data.ColorR) then
			IFObj_fnSetColor(Dest.labelstr,Data.ColorR,Data.ColorG,Data.ColorB)
			IFObj_fnSetColor(Dest.val1str,Data.ColorR,Data.ColorG,Data.ColorB)
			IFObj_fnSetColor(Dest.val2str,Data.ColorR,Data.ColorG,Data.ColorB)
			IFObj_fnSetColor(Dest.val3str,Data.ColorR,Data.ColorG,Data.ColorB)
		end
	end
	IFObj_fnSetVis(Dest,Data) -- Show if there are contents
	
	-- if the cpp == -1, then don't show this entry (its padding)
	if(Data and Data.val3str == "-1") then
		IFObj_fnSetVis(Dest,nil)
	end
	
end
teamstats_listbox_layoutL = {
--	showcount = 20, -- filled in from code later
--	yTop = -130 + 13,
	yHeight = 27,
	ySpacing  = 0,
-- 	width = 430, -- filled in from code later
	x = 0,
--	slider = 1,
	CreateFn = Teamstats_Listbox_CreateItem,
	PopulateFn = Teamstats_Listbox_PopulateItem,
}
teamstats_listbox_layoutR = {
--	showcount = 20, -- filled in from code later
--	yTop = -130 + 13,
	yHeight = 27,
	ySpacing  = 0,
-- 	width = 430, -- filled in from code later
	x = 0,
--	slider = 1,
	CreateFn = Teamstats_Listbox_CreateItem,
	PopulateFn = Teamstats_Listbox_PopulateItem,
}
function ifs_teamstats_fnFillContents(this,noAnimate)
	-- Reset listbox, show it. [Remember, Lua starts at 1!]
	local playerIdxL,playerIdxR
	playerIdxR = ScriptCB_GetTeamstats(1)
	playerIdxL = ScriptCB_GetTeamstats(0)
	if(this.SetCursorToPlayer) then
		if(playerIdxL >= 0) then
			this.bCursorOnLeft = 1
			teamstats_listbox_layoutL.CursorIdx = playerIdxL + 1
			teamstats_listbox_layoutL.SelectedIdx = playerIdxL + 1
			teamstats_listbox_layoutL.FirstShownIdx = max(playerIdxL-4,1)
			teamstats_listbox_layoutR.CursorIdx = nil
			teamstats_listbox_layoutR.SelectedIdx = nil
			teamstats_listbox_layoutR.FirstShownIdx = max(playerIdxL-4,1)
		end
		if(playerIdxR >= 0) then
			this.bCursorOnLeft = nil
			teamstats_listbox_layoutL.CursorIdx = nil
			teamstats_listbox_layoutL.SelectedIdx = nil
			teamstats_listbox_layoutL.FirstShownIdx = max(playerIdxR-4,1)
			teamstats_listbox_layoutR.CursorIdx = playerIdxR + 1
			teamstats_listbox_layoutR.SelectedIdx = playerIdxR + 1
			teamstats_listbox_layoutR.FirstShownIdx = max(playerIdxR-4,1)
		end
	end
	
	-- and set the colors of each side
	this.playerTeam = 1
	if(playerIdxR>=0) then
		this.playerTeam = 2
	end
	
	-- set the title text, icons, models
	ScriptCB_TeamStatsSetTitles(this.playerTeam)
	if(not noAnimate) then
		-- animate the models	
		local w,h = ScriptCB_GetSafeScreenInfo()
		local fw,fh = ScriptCB_GetScreenInfo()
		local es = fw/800
		local xs,xe
		local spinL,spinR
		xs=0; xe=0; ys=0; sa=0; spinL=1
		if(this.returnAnim == 1) then
			xs = -w*0.15
			ys = -h*0.30
			sa = 0.4
			spinL = 20
		end
		AnimationMgr_AddAnimation(this.LeftModel,{ fTotalTime = 0.4,fStartAlpha = sa, fEndAlpha = 0.2,
				fStartX=xs,fStartY=ys,fEndX=0,fEndY=0,
				fStartW=0.5*es,fStartH=0.5*es,fEndW=es,fEndH=es,})
		xs=0; xe=0; ys=0; sa=0; spinR=1
		if(this.returnAnim == 2) then
			xs = w*0.15
			ys = -h*0.30
			sa = 0.4
			spinR = 20
		end
		AnimationMgr_AddAnimation(this.RightModel,{ fTotalTime = 0.4,fStartAlpha = sa, fEndAlpha = 0.2,
				fStartX=xs,fStartY=ys,fEndX=0,fEndY=0,
				fStartW=0.5*es,fStartH=0.5*es,fEndW=es,fEndH=es,})
		this.returnAnim = nil
		-- make them spin fast while moving
		ScriptCB_IFModel_SetOmegaY(this.LeftModel.cpointer,spinL)
		ScriptCB_IFModel_SetOmegaY(this.RightModel.cpointer,spinR)
		this.IconModelFastMode = 1
	else
		AnimationMgr_AddAnimation(this.LeftModel,{ fTotalTime = 0.1,fStartAlpha = 0.2, fEndAlpha = 0.2, })
		AnimationMgr_AddAnimation(this.RightModel,{ fTotalTime = 0.1,fStartAlpha = 0.2, fEndAlpha = 0.2, })
	end			
	-- fill them	
	ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
	ScriptCB_GetTeamstats(1)
	ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
end
-- Helper function, blanks out the onscreen contents. Used to keep the
-- glyphcache from overloading.
function ifs_teamstats_fnBlankContents(this)
	local i,Max
	local BlankUStr = ScriptCB_tounicode("")
	Max = getn(teamstats_listbox_contentsL)
	for i=1,Max do
		teamstats_listbox_contentsL[i].labelustr = BlankUStr
		teamstats_listbox_contentsL[i].val1str = ""
		teamstats_listbox_contentsL[i].val2str = ""
		teamstats_listbox_contentsL[i].val3str = ""
	end
	Max = getn(teamstats_listbox_contentsR)
	for i=1,Max do
		teamstats_listbox_contentsR[i].labelustr = BlankUStr
		teamstats_listbox_contentsR[i].val1str = ""
		teamstats_listbox_contentsR[i].val2str = ""
		teamstats_listbox_contentsR[i].val3str = ""
	end
	-- Repaint
	ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
	ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
end
teamstats_listbox_contents = {}
teamstats_listbox_contentsL = {
	-- Filled in from C++
	-- Stubbed to show the format it wants.
--	{ labelustr = "Player 1", contentsstr = "5"},
-- **OR**
--	{ labelustr = " Favorite Vehicle", contentsustr = "AT-ST"}, 
}
teamstats_listbox_contentsR = {
	-- Filled in from C++
	-- Stubbed to show the format it wants.
--	{ labelustr = "Player 1", contentsstr = "5"},
-- **OR**
--	{ labelustr = " Favorite Vehicle", contentsustr = "AT-ST"}, 
}
function ifs_teamstats_fnFlipLeftRight(this)
	if(teamstats_listbox_layoutL.SelectedIdx) then
		this.bCursorOnLeft = nil
		teamstats_listbox_layoutR.SelectedIdx = teamstats_listbox_layoutL.SelectedIdx
		teamstats_listbox_layoutL.SelectedIdx = nil
	else
		this.bCursorOnLeft = 1
		teamstats_listbox_layoutL.SelectedIdx = teamstats_listbox_layoutR.SelectedIdx
		teamstats_listbox_layoutR.SelectedIdx = nil
	end
	ifs_teamstats_fnValidateCursor(this)
end
--validate the cursor position (make sure we're not on a null entry)
function ifs_teamstats_fnValidateCursor(this)
	local onLeft = nil
	if(teamstats_listbox_layoutL.SelectedIdx) then
		onLeft = 1		
	end
	this.bCursorOnLeft = onLeft
	local Pos = teamstats_listbox_layoutL.SelectedIdx or teamstats_listbox_layoutR.SelectedIdx
	if(onLeft) then
		Pos = ScriptCB_TeamStatsValidatePos( 0, Pos );
	else
		Pos = ScriptCB_TeamStatsValidatePos( 1, Pos );
	end
	
	--set the cursor to the validated position
	if(onLeft) then		
		teamstats_listbox_layoutL.CursorIdx = Pos
		teamstats_listbox_layoutR.CursorIdx = nil
		teamstats_listbox_layoutL.SelectedIdx = Pos
		teamstats_listbox_layoutR.SelectedIdx = nil
	else
		teamstats_listbox_layoutL.CursorIdx = nil
		teamstats_listbox_layoutR.CursorIdx = Pos
		teamstats_listbox_layoutL.SelectedIdx = nil
		teamstats_listbox_layoutR.SelectedIdx = Pos
	end
	ListManager_fnMoveCursor(this.LeftList,teamstats_listbox_layoutL)
	ListManager_fnMoveCursor(this.RightList,teamstats_listbox_layoutR)
end
function ifs_teamstats_fnNav(fn)
	local this = ifs_teamstats
	if(teamstats_listbox_layoutL.SelectedIdx) then
		teamstats_listbox_layoutR.SelectedIdx = teamstats_listbox_layoutL.SelectedIdx
		fn(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
		fn(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
		teamstats_listbox_layoutR.SelectedIdx = nil
	else
		teamstats_listbox_layoutL.SelectedIdx = teamstats_listbox_layoutR.SelectedIdx
		fn(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
		fn(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
		teamstats_listbox_layoutL.SelectedIdx = nil
	end
	ifs_teamstats_fnValidateCursor(this)
	this.fCurIdleTime = this.fMAX_IDLE_TIME 
end
ifs_teamstats = NewIFShellScreen {
	nologo = 1,
	fMAX_IDLE_TIME = 30.0,
	fCurIdleTime = 0,
	movieIntro      = nil, -- played before the screen is displayed
	movieBackground = nil, -- played while the screen is displayed
	bNohelptext_backPC = 1,
	bgTexture = NewIFImage { 
		ZPos = 250,
		ScreenRelativeX = 0,
		ScreenRelativeY = 0,
		UseSafezone = 0,
		texture = "opaque_black", 
		localpos_l = 0,
		localpos_t = 0,
		-- Size, UVs aren't fully specified here, but in NewIFShellScreen()
	},
	
	quit = NewIFContainer
	{
		ScreenRelativeX = 0.35, ---- stock 0.0
		ScreenRelativeY = 1.0,
		btn = NewClickableIFButton
		{ 
		----	x = 60,
		----	y = -15,
			ColorR= 255, ColorG = 0, ColorB = 0,
			btnw = 130, 
			btnh = 25,
			font = "gamefont_small", 
		----	bg_tail = 20,
			tag = "quit",
			----string = "ifs.stats.done",
			string = "NEXT MAP",
			nocreatebackground = 1,
		}, -- end of btn
	},
	
	details = NewIFContainer
	{
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.5,
		btn = NewClickableIFButton
		{ 
			x = 0,
			y = 0,
			ColorR= 0, ColorG = 255, ColorB = 0,
			btnw = 10, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small", 
			tag = "details",
			string = "ifs.Stats.details",
			nocreatebackground=1,
			noTransitionFlash = 1,
		}, -- end of btn
	},
	
	--phobos test--
	restart = NewIFContainer
	{
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.95,
		btn = NewClickableIFButton
		{ 
			x = 0,
			y = 0,
			ColorR= 0, ColorG = 255, ColorB = 255,
			btnw = 10, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small",
			-- ColorR= 255, ColorG = 0, ColorB = 0,		-- red color	
			tag = "restart",
			string = "RESTART MISSION",
			nocreatebackground=1,
		}, -- end of btn
	},	
	
	exitwin = NewIFContainer
	{
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 1.0,
		btn = NewClickableIFButton
		{ 
			x = 0,
			y = 0,
			ColorR= 255, ColorG = 0, ColorB = 255,
			btnw = 10, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small",
			-- ColorR= 255, ColorG = 0, ColorB = 0,		-- red color	
			tag = "exitwin",
			string = "EXIT TO WINDOWS",
			nocreatebackground=1,
		}, -- end of btn
	},
	
	ServerName = NewIFText {
--		string = "ifs.mp.connection.title",
		font = "gamefont_small",
		textw = 460,
		halign = "left",
		ScreenRelativeX = 0.25, -- left ---- 0.35
		ScreenRelativeY = 0.05, -- near top
		y = 0,
		x = 0,
		ColorR = 0, ColorG = 255, ColorB = 255,
		nocreatebackground=1,
	},
	
	MissionTime = NewIFText {
--		string = "ifs.mp.connection.title",
		font = "gamefont_small",
		textw = 460,
		halign = "left",
		ScreenRelativeX = 0.75, -- right ---- 0.55
		ScreenRelativeY = 0.05, -- near top
		y = 0,
		x = 0,
		ColorR = 0, ColorG = 255, ColorB = 0,
		nocreatebackground=1,
	},
	
	awards = NewIFContainer
	{
		ScreenRelativeX = 0.7, ---- stock 1.0
		ScreenRelativeY = 1.0,
		btn = NewClickableIFButton
		{ 
		----	x = 0,
		----	y = -15,
			ColorR= 0, ColorG = 0, ColorB = 255,
			btnw = 180, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small", 
			tag = "awards",
			string = "ifs.Stats.awards",
			--rotY = -35,
			nocreatebackground=1,
		}, -- end of btn
	},
	
	bCursorOnLeft = 1,
	Enter = function(this, bFwd)
		gIFShellScreenTemplate_fnEnter(this, bFwd) -- call default enter function
		IFModel_fnSetMsh(this.LeftModel,"")
		IFModel_fnSetMsh(this.RightModel,"")		
		gIFShellScreenTemplate_fnMoveClickableButton(this.awards.btn,this.awards.btn.label,0)
		gIFShellScreenTemplate_fnCenterClickableButton(this.details.btn,this.details.btn.label,0,"ifs.Stats.details")
		gIFShellScreenTemplate_fnCenterClickableButton(this.restart.btn,this.restart.btn.label,0,"RESTART MISSION")
		gIFShellScreenTemplate_fnCenterClickableButton(this.exitwin.btn,this.exitwin.btn.label,0,"EXIT TO WINDOWS")
		
--		AnimationMgr_AddAnimation(this.buttons.LeftColumnHeader1, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.LeftColumnHeader2, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.LeftColumnHeader3, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.RightColumnHeader1, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.RightColumnHeader2, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.RightColumnHeader3, { fStartAlpha = 0, fEndAlpha = 1,})
		
		-- if we're in MP and the client never recieved stats, just skip the stats and go
		-- back to the shell now. [DISABLED NM 10/19/04 - gotta wait for server]
		if(nil and (not ScriptCB_ClientGotStats())) then
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
			return
		end
		if(bFwd) then
			-- Horrible hack -- We need the memory on the PS2 for the stats,
			-- and the only way to get that now is to kick some screens out of
			-- memory.
			if(gPlatformStr == "PS2") then
				ifs_pausemenu = nil -- die if we ever exit out of here.
				ifs_opt_controller = nil -- we need memory, NOW
				ifs_mp_lobby = nil -- we need memory, NOW			
			end
			this.bCursorOnLeft = 1
			teamstats_listbox_layoutL.FirstShownIdx = 1
			teamstats_listbox_layoutR.FirstShownIdx = 1
			teamstats_listbox_layoutL.SelectedIdx = 1
			teamstats_listbox_layoutR.SelectedIdx = nil
			teamstats_listbox_layoutL.CursorIdx = 1
			teamstats_listbox_layoutR.CursorIdx = nil
			
			this.SetCursorToPlayer = 1
		end
		ifs_teamstats_fnFillContents(this,nil)
		this.SetCursorToPlayer = nil
		
		this.fCurIdleTime = this.fMAX_IDLE_TIME
		if(gE3Build) then
			if(ScriptCB_GetAmHost()) then
				gE3StatsTimeout = 15
			else
				gE3StatsTimeout = 20
			end
		else
			gE3StatsTimeout = 0 -- can quit right away
		end
		
		if(gPlatformStr == "PC") then --quickee hack for PC
			gE3StatsTimeout = 0 
		end
		if((ScriptCB_InNetGame()) and (ScriptCB_AreMetagameRulesOn()) and (ScriptCB_GetAmHost())) then
			this.fCurIdleTime = 0
			gE3StatsTimeout = 0
		end
	end,
	Exit = function(this, bFwd)
		-- Reduce lua memory, glyphcache usage
		ifs_teamstats_fnBlankContents(this)
		teamstats_listbox_contents = nil
		teamstats_listbox_contentsL = nil
		teamstats_listbox_contentsR = nil
		if(gCurHiliteButton) then
			IFButton_fnSelect(gCurHiliteButton,nil)
		end
	end,
	-- Accept button bumps the page
	Input_Accept = function(this)
		-- If base class handled this work, then we're done
		if(gShellScreen_fnDefaultInputAccept(this)) then
			-- check for a double click
			ScriptCB_ResetMouseMark()
			if(gMouseListBox) then
				if( gMouseListBox.Layout.SelectedIdx == gMouseListBox.Layout.CursorIdx and this.lastDoubleClickTime and ScriptCB_GetMissionTime()<this.lastDoubleClickTime+0.4) then
					this.lastDoubleClickTime = nil
					this.CurButton = "details"
				else
					this.lastDoubleClickTime = ScriptCB_GetMissionTime()
					return
				end
			else
				return
			end
		end
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		-- Todo: PC needs to read current listbox instead
		local Selection
		if(teamstats_listbox_layoutL.SelectedIdx) then
			ifs_personalstats.fTeam = 1
			ifs_personalstats.fIdx = teamstats_listbox_layoutL.SelectedIdx
			Selection = teamstats_listbox_contentsL[teamstats_listbox_layoutL.SelectedIdx]
		else
			ifs_personalstats.fTeam = 2
			ifs_personalstats.fIdx = teamstats_listbox_layoutR.SelectedIdx
			Selection = teamstats_listbox_contentsR[teamstats_listbox_layoutR.SelectedIdx]
		end
		if(Selection and this.CurButton == "details") then
			IFText_fnSetUString(ifs_personalstats.title2,Selection.labelustr)
			-- set the title text, icons, models
			ScriptCB_PersonalStatsSetTitles(this.playerTeam,ifs_personalstats.fTeam)
			-- animate the models
			local w,h = ScriptCB_GetSafeScreenInfo()
			local fw,fh = ScriptCB_GetScreenInfo()
			local es = fw/800
			local xs,xe
			local spin
			if(ifs_personalstats.fTeam==1) then
				xs = -w*0.25
				xe = -w*0.4
				this.returnAnim = 1
			else
				xs = w*0.25
				xe = w*0.4
				this.returnAnim = 2
			end
			AnimationMgr_AddAnimation(ifs_personalstats.IconModel,{ fTotalTime = 0.4, fStartAlpha = 0.2, fEndAlpha = 0.4,
					fStartX=xs,fStartY=0,fEndX=xe,fEndY=-h*0.30,
					fStartW=1*es,fStartH=1*es,fEndW=0.5*es,fEndH=0.5*es,})
			-- make it spin fast
			ScriptCB_IFModel_SetOmegaY(ifs_personalstats.IconModel.cpointer,20)
			ifs_personalstats.IconModelFastMode = 1
		end
		
		IFText_fnSetString(this.ServerName,"SERVER NAME: " .. ScriptCB_GetGameName()) ---- advanced code by Phobos
		IFText_fnSetString(this.MissionTime,"MISSION TIME: " .. ScriptCB_GetMissionTime()) ---- advanced code by Phobos
		
		-- buttons?
		if(this.CurButton == "quit") then
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
			return
		elseif(this.CurButton == "details") then
			ifs_movietrans_PushScreen(ifs_personalstats)
			ScriptCB_SndPlaySound("shell_menu_enter");
			return
		elseif(this.CurButton == "restart") then
			ScriptCB_RestartMission() ---- useful for campaigns
			return
		elseif(this.CurButton == "exitwin") then
			ScriptCB_QuitToWindows()
			return
		elseif(this.CurButton == "awards") then
			ifs_movietrans_PushScreen(ifs_awardstats)
			ScriptCB_SndPlaySound("shell_menu_enter");
			return
		elseif(this.CurButton == "_upL" or this.CurButton == "_upR") then
			ifs_teamstats_fnNav(ListManager_fnScrollUp)
			ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
			ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)			
		elseif(this.CurButton == "_downL" or this.CurButton == "_downR") then
			ifs_teamstats_fnNav(ListManager_fnScrollDown)
			ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
			ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)			
		elseif(this.CurButton == "_sortKillsL" or this.CurButton == "_sortKillsR") then
			ScriptCB_SndPlaySound("shell_select_change")
			ScriptCB_SetTeamStatsSortMode(0);
			ifs_teamstats_fnFillContents(this,1);
		elseif(this.CurButton == "_sortDeathsL" or this.CurButton == "_sortDeathsR") then
			ScriptCB_SndPlaySound("shell_select_change");
			ScriptCB_SetTeamStatsSortMode(1);
			ifs_teamstats_fnFillContents(this,1);
		elseif(this.CurButton == "_sortCppL" or this.CurButton == "_sortCppR") then
			ScriptCB_SndPlaySound("shell_select_change");
			ScriptCB_SetTeamStatsSortMode(2);
			ifs_teamstats_fnFillContents(this,1);
		elseif(this.CurButton == "_sortNameL" or this.CurButton == "_sortNameR") then
			ScriptCB_SndPlaySound("shell_select_change");
			ScriptCB_SetTeamStatsSortMode(3);
			ifs_teamstats_fnFillContents(this,1);
		end
		
	end,
	--Back button quits stats
	Input_Back = function(this)
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		if(not gE3StatsTimeout or gE3StatsTimeout < 0) then
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
		end
	end,
	-- No U/D/L/R functionality possible on this screen (gotta have stubs
	-- here, or the base class will override)
	Input_GeneralUp = function(this)
		ifs_teamstats_fnNav(ListManager_fnNavUp)		
	end,
	Input_GeneralDown = function(this)
		ifs_teamstats_fnNav(ListManager_fnNavDown)
	end,
	Input_LTrigger = function(this)
		ifs_teamstats_fnNav(ListManager_fnPageUp)
	end,
	Input_RTrigger = function(this)
		ifs_teamstats_fnNav(ListManager_fnPageDown)
	end,
	Input_GeneralLeft = function(this)
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		ifs_teamstats_fnFlipLeftRight(this)
		ScriptCB_SndPlaySound("shell_select_change");
	end,
	Input_GeneralRight = function(this)
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		ifs_teamstats_fnFlipLeftRight(this)
		ScriptCB_SndPlaySound("shell_select_change");
	end,
	Update = function(this, fDt)
 		-- Call default base class's update function (make button bounce)
 		gIFShellScreenTemplate_fnUpdate(this,fDt)
		-- If the host is busy, then wait on this screen
		if(ScriptCB_CanClientLeaveStats) then
			if(fDt > 0.5) then
				fDt = 0.5 -- clamp this to sane values
			end
			if(ScriptCB_CanClientLeaveStats()) then
				IFObj_fnSetVis(this.quit, 1) -- show quit button
				gE3StatsTimeout = 0 -- allow quit now
			else
				IFObj_fnSetVis(this.quit, nil) -- hidden
				gE3StatsTimeout = 1 -- keep clients from leaving
			end
		end
			
		if(gE3StatsTimeout) then
			gE3StatsTimeout = gE3StatsTimeout - fDt
		end
 		-- if the models are done animating, slow down the rotations
 		if(this.IconModelFastMode and not this.LeftModel.bAnimActive) then
 			this.IconModelFastMode = nil
			ScriptCB_IFModel_SetOmegaY(this.LeftModel.cpointer,0.3)
			ScriptCB_IFModel_SetOmegaY(this.RightModel.cpointer,0.25)
		end
		
		if(gPlatformStr == "PC") then
			if( gMouseListBox ) then
				if(ScriptCB_CheckMouseMark()) then
					if( gMouseListBox == this.LeftList ) then
						this.bCursorOnLeft = 1
						if( teamstats_listbox_layoutL.CursorIdx == teamstats_listbox_layoutL.SelectedIdx) then
							teamstats_listbox_layoutR.SelectedIdx = nil
						end
					else
						this.bCursorOnLeft = nil
						if( teamstats_listbox_layoutR.CursorIdx == teamstats_listbox_layoutR.SelectedIdx) then
							teamstats_listbox_layoutL.SelectedIdx = nil
						end
					end
					this.RepaintListbox( this, this.bCursorOnLeft )
				end
				ScriptCB_SetMouseMark()
			end	
		end
		-- if we've been sitting here for a while, bail to the teaser screen
		this.fCurIdleTime = this.fCurIdleTime - fDt
		if((this.fCurIdleTime < 0) and (not gE3StatsTimeout or gE3StatsTimeout < 0)) then
			this.fCurIdleTime = 100
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
		end
		
		-- update the visibility of the up/down arrows
		IFObj_fnSetVis(this.buttons.LeftUpArrow,teamstats_listbox_layoutL.FirstShownIdx > 1)
		IFObj_fnSetVis(this.buttons.RightUpArrow,teamstats_listbox_layoutL.FirstShownIdx > 1)
		local num = max(getn(teamstats_listbox_contentsL),getn(teamstats_listbox_contentsR))
		IFObj_fnSetVis(this.buttons.LeftDownArrow,teamstats_listbox_layoutL.FirstShownIdx+teamstats_listbox_layoutL.showcount <= num)
		IFObj_fnSetVis(this.buttons.RightDownArrow,teamstats_listbox_layoutL.FirstShownIdx+teamstats_listbox_layoutL.showcount <= num)
		
		-- animate the up/down arrows
		IFObj_UpdateBlinkyAnim(this.buttons.LeftUpArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftUpArrow.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightUpArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.RightUpArrow.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.LeftDownArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftDownArrow.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightDownArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.RightDownArrow.cpointer),0.4,1,0.4,0.2)
		-- animate the stat sort icons	
		IFObj_UpdateBlinkyAnim(this.buttons.LeftColumnHeader1,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftColumnHeader1.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.LeftColumnHeader2,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftColumnHeader2.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.LeftColumnHeader3,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftColumnHeader3.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightColumnHeader1,ScriptCB_IFObj_TestHotSpot(this.buttons.RightColumnHeader1.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightColumnHeader2,ScriptCB_IFObj_TestHotSpot(this.buttons.RightColumnHeader2.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightColumnHeader3,ScriptCB_IFObj_TestHotSpot(this.buttons.RightColumnHeader3.cpointer),0.4,1,0.4,0.2)
			
 	end,
	-- Callback (from C++) to repaint the listbox with the current contents
	-- in the global teamstats_listbox_contents
	RepaintListbox = function(this, bOnLeft)	
  		if( bOnLeft ) then
			teamstats_listbox_layoutR.CursorIdx = nil
		else
			teamstats_listbox_layoutL.CursorIdx = nil
		end
		ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
		ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
		
--		print(teamstats_listbox_layoutR.SelectedIdx, teamstats_listbox_layoutL.SelectedIdx)
	 end,	
}
-- Helper function, sets up parts of this screen that need any
-- programmatic work (i.e. scaling to screensize)
function ifs_teamstats_fnBuildScreen(this)
	-- Ask game for screen size, fill in values
	local r, b, v, widescreen = ScriptCB_GetScreenInfo()
	this.bgTexture.localpos_l = 0
	this.bgTexture.localpos_t = 0
	this.bgTexture.localpos_r = r*widescreen
	this.bgTexture.localpos_b = b
	this.bgTexture.uvs_b = v
--	if(this.Helptext_Back) then
--		IFText_fnSetString(this.Helptext_Back.helpstr,"ifs.stats.done")
--	end
--	if(this.Helptext_Accept) then
--		IFText_fnSetString(this.Helptext_Accept.helpstr,"ifs.stats.details")
--	end
	-- Inset slightly from fulls screen size
	local fw,fh = ScriptCB_GetScreenInfo()
	local w,h = ScriptCB_GetSafeScreenInfo()
	h = h * 0.82
	this.listbox = NewButtonWindow { ZPos = 200, x=0, y = 0,
		ScreenRelativeX = 0.5, -- center
		ScreenRelativeY = 0.48, -- middle of screen
		width = w,
		height = h,
		noEnterAnimation = 1,
	}
	
	--details button is bottom center of the listbox
	this.details.btn.y = h*0.485 + 4
	-- Cut width in half for 2-column layout, make containers to drop them into
	w = w * 0.5
	this.LeftList = NewIFContainer {
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.53,
		x =-w * 0.5
	}
	this.RightList = NewIFContainer {
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.53,
		x = w * 0.5
	}
	
	local iconWidth = 30
	local iconHeight = 30
	local pos1 = w * 0.20 - iconWidth/2
	local pos2 = w * 0.32 - iconWidth/2
	local pos3 = w * 0.44 - iconWidth/2
	local ypos = -h/2
	
	this.LeftList.Title = NewIFText {
		string = "TITLE: 30",
		font = "gamefont_medium",
		flashy = 0,
		textw = w * 0.5,
		texth = iconHeight,
		halign = "left",
		x = -w/2 + 15,
		y = ypos,
	}		
	this.LeftModel = NewIFModel {
		ScreenRelativeX = 0.25,
		ScreenRelativeY = 0.5,
		x=0,y=0,scale = 1,
		OmegaY = 0.3,
		lighting = 1,
	}
	this.RightList.Title = NewIFText {
		string = "TITLE: 30",
		font = "gamefont_medium",
		flashy = 0,
		textw = w * 0.5,
		texth = iconHeight,
		halign = "left",
		x = -w/2 + 15,
		y = ypos,
	}		
	this.RightModel = NewIFModel {
		ScreenRelativeX = 0.75,
		ScreenRelativeY = 0.5,
		x=0,y=0,scale = 1,
		OmegaY = 0.25,
		lighting = 1,
	}
	teamstats_listbox_layoutL.width = w - 20
	teamstats_listbox_layoutR.width = w - 20
	local listh = h * 0.85
	teamstats_listbox_layoutL.showcount = floor(listh / (teamstats_listbox_layoutL.yHeight + teamstats_listbox_layoutL.ySpacing)) - 1
	teamstats_listbox_layoutR.showcount = teamstats_listbox_layoutL.showcount
	ListManager_fnInitList(ifs_teamstats.LeftList,teamstats_listbox_layoutL)
	ListManager_fnInitList(ifs_teamstats.RightList,teamstats_listbox_layoutR)
	
	this.buttons = NewIFContainer {
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.5,
	}	
	-- make the up and down arrows
	local arrowsize = 30
	this.buttons.LeftUpArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = -w*0.5, 
 		y = -h/2 + arrowsize*2.5 - 10,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t = -arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b =  arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_upL",
		uvs_diag = 1,
 	}
	this.buttons.RightUpArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = w*0.5, 
 		y = -h/2 + arrowsize*2.5 - 10,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t = -arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b =  arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_upR",
		uvs_diag = 1,
 	}
	this.buttons.LeftDownArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = -w*0.5, 
 		y = h/2 - arrowsize*1.5 + 15,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t =  arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b = -arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_downL",
		uvs_diag = 1,
 	}
	this.buttons.RightDownArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = w*0.5, 
 		y = h/2 - arrowsize*1.5 + 15,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t =  arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b = -arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_downR",
		uvs_diag = 1,
 	}
	
	this.buttons.LeftColumnHeader1 = NewIFImage {
		x = pos1 - w/2, y = ypos + fh*0.03,
		texture = "stats_kills", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortKillsL",
	}
	this.buttons.LeftColumnHeader2 = NewIFImage {
		x = pos2 - w/2, y = ypos + fh*0.03,
		texture = "stats_deaths", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortDeathsL",
	}
	this.buttons.LeftColumnHeader3 = NewIFImage {
		x = pos3 - w/2, y = ypos + fh*0.03,
		texture = "stats_cpp", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortCppL",
	}
	this.buttons.RightColumnHeader1 = NewIFImage {
		x = pos1 + w/2, y = ypos + fh*0.03,
		texture = "stats_kills", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortKillsR",
	}
	this.buttons.RightColumnHeader2 = NewIFImage {
		x = pos2 + w/2, y = ypos + fh*0.03,
		texture = "stats_deaths", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortDeathsR",
	}
	this.buttons.RightColumnHeader3 = NewIFImage {
		x = pos3 + w/2, y = ypos + fh*0.03,
		texture = "stats_cpp", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortCppR",
	}
	
end
ifs_teamstats_fnBuildScreen(ifs_teamstats) -- programatic chunks
ifs_teamstats_fnBuildScreen = nil
AddIFScreen(ifs_teamstats,"ifs_teamstats")
- also included -
Player Count Common.lvl Mod by Phobos
Instructions: Replace this game file with the new one
C:\Program Files (x86)\LucasArts\Star Wars Battlefront\GameData\Data\_LVL_PC\Common\ENG\Common.lvl
Included in this common.lvl is the new Player Count Mod by Phobos, Freecam, and Exit To Windows for Pausemenu. It is very useful for admins and spectators of large tournament battles. 
The LUA source and a possible tutorial for this will be released later for adding to other common.lvl mods. 
Mod Preview - http://i.imgur.com/dbtCED0.jpg
Included Features
TOTAL PLAYERS: Shows the total number of players in server.
MISSION TIME: Shows the total number of elapsed game seconds for the server session. 
RESTART MISSION: Added to the pausemenu. If used in a multiplayer server it will leave and restart your game on the same map in singleplayer.
DISABLED MENU FLASHING: Buttons on the various game and shell menus no longer flash randomly. 
DISABLED BLUE BACKGROUNDS: border_3_pieces.tga were modified to a green outline instead of blue box, which gives a minimal appearance for several buttons including the spawn menu. Preview - http://i.imgur.com/ooAyJFJ.jpg
Not Included
FRIENDLY/ENEMY PLAYERS: Is supposed to show the number per faction, doesn't work yet. I will upload a new common when this feature works.
IDIOT MODE: A toggler for this is still being worked on there is a glitch with the ping bars so it was disabled. 
DISPLAY DATE/TIME: The ScriptCB function for this doesn't appear to work yet so it could not be included.
CROSSHAIRS: These were not modified.
			
			
			
				Nice work  :cheers:
			
			
			
				Really cool stuff, Phobos, Thanks for sharing!
			
			
			
				Players using this script have probably noticed the pla cloud city server doesn't show on end stats. I changed the textw under ServerName from 460 to 660. Now it displays long server names for end stats :cheers:
---- Enhanced ifs_teamstats.LUA by Phobos -- edited 2-23-16
-- Multiplayer game name screen.
-- Helper function. Given a layout (x,y,width, height), returns a
-- fully-built item.
function Teamstats_Listbox_CreateItem(layout)
	local insidewidth = layout.width - 10;
	-- Make a coordinate system pegged to the top-left of where the cursor would go.
	local Temp = NewIFContainer {
		x = layout.x - 0.5 * insidewidth, y=layout.y,
		bInertPos = 1,
	}
	Temp.labelstr = NewIFText {
		HScale = 0.8,
		VScale = 1,
		x = 2, y = -10, textw = 0.65 * insidewidth, 
		texth = ScriptCB_GetFontHeight("gamefont_small"),
		clip = "character",
		halign = "left", font = "gamefont_small",
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	local WidthPer = insidewidth * 0.133
	Temp.val1str = NewIFText{
		HScale = 0.8,
		VScale = 1,
		x = insidewidth - WidthPer * 3, y = -10, 
		textw = WidthPer, halign = "right", font = "gamefont_small",		
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	Temp.val2str = NewIFText{
		HScale = 0.8,
		VScale = 1,
		x = insidewidth - WidthPer * 2, y = -10, 
		textw = WidthPer, halign = "right", font = "gamefont_small",
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	Temp.val3str = NewIFText{ 
		HScale = 0.8,
		VScale = 1,
		x = insidewidth - WidthPer * 1, y = -10, 
		textw = WidthPer, halign = "right", font = "gamefont_small",
		ColorR= 255, ColorG = 255, ColorB = 255,
		style = "normal",
		bInertPos = 1,
		nocreatebackground = 1,
		startdelay = 0,
		inert_all = 1,
	}
	return Temp
end
-- Helper function. For a destination item (previously created w/
-- CreateItem), fills it in with data, which may be nil (==blank it)
function Teamstats_Listbox_PopulateItem(Dest,Data)
	if(Data) then
		-- force the name into word clipping
		if(Dest.labelstr.cpointer) then
			ScriptCB_IFText_SetTextBreak(Dest.labelstr.cpointer,"none")
		end
		-- Contents to show. Do so.
		IFText_fnSetUString(Dest.labelstr,Data.labelustr)
		IFText_fnSetString(Dest.val1str,Data.val1str)
		IFText_fnSetString(Dest.val2str,Data.val2str)
		IFText_fnSetString(Dest.val3str,Data.val3str)
-- 		IFText_fnSetString(Dest.labelstr,"WWWWWWWWWWWWWWM")
-- 		IFText_fnSetString(Dest.val1str,"11111")
-- 		IFText_fnSetString(Dest.val2str,"22222")
-- 		IFText_fnSetString(Dest.val3str,"33333")
		if(Data.ColorR) then
			IFObj_fnSetColor(Dest.labelstr,Data.ColorR,Data.ColorG,Data.ColorB)
			IFObj_fnSetColor(Dest.val1str,Data.ColorR,Data.ColorG,Data.ColorB)
			IFObj_fnSetColor(Dest.val2str,Data.ColorR,Data.ColorG,Data.ColorB)
			IFObj_fnSetColor(Dest.val3str,Data.ColorR,Data.ColorG,Data.ColorB)
		end
	end
	IFObj_fnSetVis(Dest,Data) -- Show if there are contents
	
	-- if the cpp == -1, then don't show this entry (its padding)
	if(Data and Data.val3str == "-1") then
		IFObj_fnSetVis(Dest,nil)
	end
	
end
teamstats_listbox_layoutL = {
--	showcount = 20, -- filled in from code later
--	yTop = -130 + 13,
	yHeight = 27,
	ySpacing  = 0,
-- 	width = 430, -- filled in from code later
	x = 0,
--	slider = 1,
	CreateFn = Teamstats_Listbox_CreateItem,
	PopulateFn = Teamstats_Listbox_PopulateItem,
}
teamstats_listbox_layoutR = {
--	showcount = 20, -- filled in from code later
--	yTop = -130 + 13,
	yHeight = 27,
	ySpacing  = 0,
-- 	width = 430, -- filled in from code later
	x = 0,
--	slider = 1,
	CreateFn = Teamstats_Listbox_CreateItem,
	PopulateFn = Teamstats_Listbox_PopulateItem,
}
function ifs_teamstats_fnFillContents(this,noAnimate)
	-- Reset listbox, show it. [Remember, Lua starts at 1!]
	local playerIdxL,playerIdxR
	playerIdxR = ScriptCB_GetTeamstats(1)
	playerIdxL = ScriptCB_GetTeamstats(0)
	if(this.SetCursorToPlayer) then
		if(playerIdxL >= 0) then
			this.bCursorOnLeft = 1
			teamstats_listbox_layoutL.CursorIdx = playerIdxL + 1
			teamstats_listbox_layoutL.SelectedIdx = playerIdxL + 1
			teamstats_listbox_layoutL.FirstShownIdx = max(playerIdxL-4,1)
			teamstats_listbox_layoutR.CursorIdx = nil
			teamstats_listbox_layoutR.SelectedIdx = nil
			teamstats_listbox_layoutR.FirstShownIdx = max(playerIdxL-4,1)
		end
		if(playerIdxR >= 0) then
			this.bCursorOnLeft = nil
			teamstats_listbox_layoutL.CursorIdx = nil
			teamstats_listbox_layoutL.SelectedIdx = nil
			teamstats_listbox_layoutL.FirstShownIdx = max(playerIdxR-4,1)
			teamstats_listbox_layoutR.CursorIdx = playerIdxR + 1
			teamstats_listbox_layoutR.SelectedIdx = playerIdxR + 1
			teamstats_listbox_layoutR.FirstShownIdx = max(playerIdxR-4,1)
		end
	end
	
	-- and set the colors of each side
	this.playerTeam = 1
	if(playerIdxR>=0) then
		this.playerTeam = 2
	end
	
	-- set the title text, icons, models
	ScriptCB_TeamStatsSetTitles(this.playerTeam)
	if(not noAnimate) then
		-- animate the models	
		local w,h = ScriptCB_GetSafeScreenInfo()
		local fw,fh = ScriptCB_GetScreenInfo()
		local es = fw/800
		local xs,xe
		local spinL,spinR
		xs=0; xe=0; ys=0; sa=0; spinL=1
		if(this.returnAnim == 1) then
			xs = -w*0.15
			ys = -h*0.30
			sa = 0.4
			spinL = 20
		end
		AnimationMgr_AddAnimation(this.LeftModel,{ fTotalTime = 0.4,fStartAlpha = sa, fEndAlpha = 0.2,
				fStartX=xs,fStartY=ys,fEndX=0,fEndY=0,
				fStartW=0.5*es,fStartH=0.5*es,fEndW=es,fEndH=es,})
		xs=0; xe=0; ys=0; sa=0; spinR=1
		if(this.returnAnim == 2) then
			xs = w*0.15
			ys = -h*0.30
			sa = 0.4
			spinR = 20
		end
		AnimationMgr_AddAnimation(this.RightModel,{ fTotalTime = 0.4,fStartAlpha = sa, fEndAlpha = 0.2,
				fStartX=xs,fStartY=ys,fEndX=0,fEndY=0,
				fStartW=0.5*es,fStartH=0.5*es,fEndW=es,fEndH=es,})
		this.returnAnim = nil
		-- make them spin fast while moving
		ScriptCB_IFModel_SetOmegaY(this.LeftModel.cpointer,spinL)
		ScriptCB_IFModel_SetOmegaY(this.RightModel.cpointer,spinR)
		this.IconModelFastMode = 1
	else
		AnimationMgr_AddAnimation(this.LeftModel,{ fTotalTime = 0.1,fStartAlpha = 0.2, fEndAlpha = 0.2, })
		AnimationMgr_AddAnimation(this.RightModel,{ fTotalTime = 0.1,fStartAlpha = 0.2, fEndAlpha = 0.2, })
	end			
	-- fill them	
	ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
	ScriptCB_GetTeamstats(1)
	ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
end
-- Helper function, blanks out the onscreen contents. Used to keep the
-- glyphcache from overloading.
function ifs_teamstats_fnBlankContents(this)
	local i,Max
	local BlankUStr = ScriptCB_tounicode("")
	Max = getn(teamstats_listbox_contentsL)
	for i=1,Max do
		teamstats_listbox_contentsL[i].labelustr = BlankUStr
		teamstats_listbox_contentsL[i].val1str = ""
		teamstats_listbox_contentsL[i].val2str = ""
		teamstats_listbox_contentsL[i].val3str = ""
	end
	Max = getn(teamstats_listbox_contentsR)
	for i=1,Max do
		teamstats_listbox_contentsR[i].labelustr = BlankUStr
		teamstats_listbox_contentsR[i].val1str = ""
		teamstats_listbox_contentsR[i].val2str = ""
		teamstats_listbox_contentsR[i].val3str = ""
	end
	-- Repaint
	ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
	ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
end
teamstats_listbox_contents = {}
teamstats_listbox_contentsL = {
	-- Filled in from C++
	-- Stubbed to show the format it wants.
--	{ labelustr = "Player 1", contentsstr = "5"},
-- **OR**
--	{ labelustr = " Favorite Vehicle", contentsustr = "AT-ST"}, 
}
teamstats_listbox_contentsR = {
	-- Filled in from C++
	-- Stubbed to show the format it wants.
--	{ labelustr = "Player 1", contentsstr = "5"},
-- **OR**
--	{ labelustr = " Favorite Vehicle", contentsustr = "AT-ST"}, 
}
function ifs_teamstats_fnFlipLeftRight(this)
	if(teamstats_listbox_layoutL.SelectedIdx) then
		this.bCursorOnLeft = nil
		teamstats_listbox_layoutR.SelectedIdx = teamstats_listbox_layoutL.SelectedIdx
		teamstats_listbox_layoutL.SelectedIdx = nil
	else
		this.bCursorOnLeft = 1
		teamstats_listbox_layoutL.SelectedIdx = teamstats_listbox_layoutR.SelectedIdx
		teamstats_listbox_layoutR.SelectedIdx = nil
	end
	ifs_teamstats_fnValidateCursor(this)
end
--validate the cursor position (make sure we're not on a null entry)
function ifs_teamstats_fnValidateCursor(this)
	local onLeft = nil
	if(teamstats_listbox_layoutL.SelectedIdx) then
		onLeft = 1		
	end
	this.bCursorOnLeft = onLeft
	local Pos = teamstats_listbox_layoutL.SelectedIdx or teamstats_listbox_layoutR.SelectedIdx
	if(onLeft) then
		Pos = ScriptCB_TeamStatsValidatePos( 0, Pos );
	else
		Pos = ScriptCB_TeamStatsValidatePos( 1, Pos );
	end
	
	--set the cursor to the validated position
	if(onLeft) then		
		teamstats_listbox_layoutL.CursorIdx = Pos
		teamstats_listbox_layoutR.CursorIdx = nil
		teamstats_listbox_layoutL.SelectedIdx = Pos
		teamstats_listbox_layoutR.SelectedIdx = nil
	else
		teamstats_listbox_layoutL.CursorIdx = nil
		teamstats_listbox_layoutR.CursorIdx = Pos
		teamstats_listbox_layoutL.SelectedIdx = nil
		teamstats_listbox_layoutR.SelectedIdx = Pos
	end
	ListManager_fnMoveCursor(this.LeftList,teamstats_listbox_layoutL)
	ListManager_fnMoveCursor(this.RightList,teamstats_listbox_layoutR)
end
function ifs_teamstats_fnNav(fn)
	local this = ifs_teamstats
	if(teamstats_listbox_layoutL.SelectedIdx) then
		teamstats_listbox_layoutR.SelectedIdx = teamstats_listbox_layoutL.SelectedIdx
		fn(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
		fn(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
		teamstats_listbox_layoutR.SelectedIdx = nil
	else
		teamstats_listbox_layoutL.SelectedIdx = teamstats_listbox_layoutR.SelectedIdx
		fn(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
		fn(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
		teamstats_listbox_layoutL.SelectedIdx = nil
	end
	ifs_teamstats_fnValidateCursor(this)
	this.fCurIdleTime = this.fMAX_IDLE_TIME 
end
ifs_teamstats = NewIFShellScreen {
	nologo = 1,
	fMAX_IDLE_TIME = 30.0,
	fCurIdleTime = 0,
	movieIntro      = nil, -- played before the screen is displayed
	movieBackground = nil, -- played while the screen is displayed
	bNohelptext_backPC = 1,
	bgTexture = NewIFImage { 
		ZPos = 250,
		ScreenRelativeX = 0,
		ScreenRelativeY = 0,
		UseSafezone = 0,
		texture = "opaque_black", 
		localpos_l = 0,
		localpos_t = 0,
		-- Size, UVs aren't fully specified here, but in NewIFShellScreen()
	},
	
	quit = NewIFContainer
	{
		ScreenRelativeX = 0.35, ---- stock 0.0
		ScreenRelativeY = 1.0,
		btn = NewClickableIFButton
		{ 
		----	x = 60,
		----	y = -15,
			ColorR= 255, ColorG = 0, ColorB = 0,
			btnw = 130, 
			btnh = 25,
			font = "gamefont_small", 
		----	bg_tail = 20,
			tag = "quit",
			----string = "ifs.stats.done",
			string = "NEXT MAP",
			nocreatebackground = 1,
		}, -- end of btn
	},
	
	details = NewIFContainer
	{
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.5,
		btn = NewClickableIFButton
		{ 
			x = 0,
			y = 0,
			ColorR= 0, ColorG = 255, ColorB = 0,
			btnw = 10, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small", 
			tag = "details",
			string = "ifs.Stats.details",
			nocreatebackground=1,
			noTransitionFlash = 1,
		}, -- end of btn
	},
	
	--phobos test--
	restart = NewIFContainer
	{
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.95,
		btn = NewClickableIFButton
		{ 
			x = 0,
			y = 0,
			ColorR= 0, ColorG = 255, ColorB = 255,
			btnw = 10, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small",
			-- ColorR= 255, ColorG = 0, ColorB = 0,		-- red color	
			tag = "restart",
			string = "RESTART MISSION",
			nocreatebackground=1,
		}, -- end of btn
	},	
	
	exitwin = NewIFContainer
	{
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 1.0,
		btn = NewClickableIFButton
		{ 
			x = 0,
			y = 0,
			ColorR= 255, ColorG = 0, ColorB = 255,
			btnw = 10, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small",
			-- ColorR= 255, ColorG = 0, ColorB = 0,		-- red color	
			tag = "exitwin",
			string = "EXIT TO WINDOWS",
			nocreatebackground=1,
		}, -- end of btn
	},
	
	ServerName = NewIFText {
--		string = "ifs.mp.connection.title",
		font = "gamefont_small",
		textw = 660, -- stock 460
		halign = "left",
		ScreenRelativeX = 0.25, -- left ---- 0.35
		ScreenRelativeY = 0.05, -- near top
		y = 0,
		x = 0,
		ColorR = 0, ColorG = 255, ColorB = 255,
		nocreatebackground=1,
	},
	
	MissionTime = NewIFText {
--		string = "ifs.mp.connection.title",
		font = "gamefont_small",
		textw = 460,
		halign = "left",
		ScreenRelativeX = 0.75, -- right ---- 0.55
		ScreenRelativeY = 0.05, -- near top
		y = 0,
		x = 0,
		ColorR = 0, ColorG = 255, ColorB = 0,
		nocreatebackground=1,
	},
	
	awards = NewIFContainer
	{
		ScreenRelativeX = 0.7, ---- stock 1.0
		ScreenRelativeY = 1.0,
		btn = NewClickableIFButton
		{ 
		----	x = 0,
		----	y = -15,
			ColorR= 0, ColorG = 0, ColorB = 255,
			btnw = 180, 
			btnh = ScriptCB_GetFontHeight("gamefont_small"),
			font = "gamefont_small", 
			tag = "awards",
			string = "ifs.Stats.awards",
			--rotY = -35,
			nocreatebackground=1,
		}, -- end of btn
	},
	
	bCursorOnLeft = 1,
	Enter = function(this, bFwd)
		gIFShellScreenTemplate_fnEnter(this, bFwd) -- call default enter function
		IFModel_fnSetMsh(this.LeftModel,"")
		IFModel_fnSetMsh(this.RightModel,"")		
		gIFShellScreenTemplate_fnMoveClickableButton(this.awards.btn,this.awards.btn.label,0)
		gIFShellScreenTemplate_fnCenterClickableButton(this.details.btn,this.details.btn.label,0,"ifs.Stats.details")
		gIFShellScreenTemplate_fnCenterClickableButton(this.restart.btn,this.restart.btn.label,0,"RESTART MISSION")
		gIFShellScreenTemplate_fnCenterClickableButton(this.exitwin.btn,this.exitwin.btn.label,0,"EXIT TO WINDOWS")
		
--		AnimationMgr_AddAnimation(this.buttons.LeftColumnHeader1, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.LeftColumnHeader2, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.LeftColumnHeader3, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.RightColumnHeader1, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.RightColumnHeader2, { fStartAlpha = 0, fEndAlpha = 1,})
--		AnimationMgr_AddAnimation(this.buttons.RightColumnHeader3, { fStartAlpha = 0, fEndAlpha = 1,})
		
		-- if we're in MP and the client never recieved stats, just skip the stats and go
		-- back to the shell now. [DISABLED NM 10/19/04 - gotta wait for server]
		if(nil and (not ScriptCB_ClientGotStats())) then
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
			return
		end
		if(bFwd) then
			-- Horrible hack -- We need the memory on the PS2 for the stats,
			-- and the only way to get that now is to kick some screens out of
			-- memory.
			if(gPlatformStr == "PS2") then
				ifs_pausemenu = nil -- die if we ever exit out of here.
				ifs_opt_controller = nil -- we need memory, NOW
				ifs_mp_lobby = nil -- we need memory, NOW			
			end
			this.bCursorOnLeft = 1
			teamstats_listbox_layoutL.FirstShownIdx = 1
			teamstats_listbox_layoutR.FirstShownIdx = 1
			teamstats_listbox_layoutL.SelectedIdx = 1
			teamstats_listbox_layoutR.SelectedIdx = nil
			teamstats_listbox_layoutL.CursorIdx = 1
			teamstats_listbox_layoutR.CursorIdx = nil
			
			this.SetCursorToPlayer = 1
		end
		ifs_teamstats_fnFillContents(this,nil)
		this.SetCursorToPlayer = nil
		
		this.fCurIdleTime = this.fMAX_IDLE_TIME
		if(gE3Build) then
			if(ScriptCB_GetAmHost()) then
				gE3StatsTimeout = 15
			else
				gE3StatsTimeout = 20
			end
		else
			gE3StatsTimeout = 0 -- can quit right away
		end
		
		if(gPlatformStr == "PC") then --quickee hack for PC
			gE3StatsTimeout = 0 
		end
		if((ScriptCB_InNetGame()) and (ScriptCB_AreMetagameRulesOn()) and (ScriptCB_GetAmHost())) then
			this.fCurIdleTime = 0
			gE3StatsTimeout = 0
		end
	end,
	Exit = function(this, bFwd)
		-- Reduce lua memory, glyphcache usage
		ifs_teamstats_fnBlankContents(this)
		teamstats_listbox_contents = nil
		teamstats_listbox_contentsL = nil
		teamstats_listbox_contentsR = nil
		if(gCurHiliteButton) then
			IFButton_fnSelect(gCurHiliteButton,nil)
		end
	end,
	-- Accept button bumps the page
	Input_Accept = function(this)
		-- If base class handled this work, then we're done
		if(gShellScreen_fnDefaultInputAccept(this)) then
			-- check for a double click
			ScriptCB_ResetMouseMark()
			if(gMouseListBox) then
				if( gMouseListBox.Layout.SelectedIdx == gMouseListBox.Layout.CursorIdx and this.lastDoubleClickTime and ScriptCB_GetMissionTime()<this.lastDoubleClickTime+0.4) then
					this.lastDoubleClickTime = nil
					this.CurButton = "details"
				else
					this.lastDoubleClickTime = ScriptCB_GetMissionTime()
					return
				end
			else
				return
			end
		end
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		-- Todo: PC needs to read current listbox instead
		local Selection
		if(teamstats_listbox_layoutL.SelectedIdx) then
			ifs_personalstats.fTeam = 1
			ifs_personalstats.fIdx = teamstats_listbox_layoutL.SelectedIdx
			Selection = teamstats_listbox_contentsL[teamstats_listbox_layoutL.SelectedIdx]
		else
			ifs_personalstats.fTeam = 2
			ifs_personalstats.fIdx = teamstats_listbox_layoutR.SelectedIdx
			Selection = teamstats_listbox_contentsR[teamstats_listbox_layoutR.SelectedIdx]
		end
		if(Selection and this.CurButton == "details") then
			IFText_fnSetUString(ifs_personalstats.title2,Selection.labelustr)
			-- set the title text, icons, models
			ScriptCB_PersonalStatsSetTitles(this.playerTeam,ifs_personalstats.fTeam)
			-- animate the models
			local w,h = ScriptCB_GetSafeScreenInfo()
			local fw,fh = ScriptCB_GetScreenInfo()
			local es = fw/800
			local xs,xe
			local spin
			if(ifs_personalstats.fTeam==1) then
				xs = -w*0.25
				xe = -w*0.4
				this.returnAnim = 1
			else
				xs = w*0.25
				xe = w*0.4
				this.returnAnim = 2
			end
			AnimationMgr_AddAnimation(ifs_personalstats.IconModel,{ fTotalTime = 0.4, fStartAlpha = 0.2, fEndAlpha = 0.4,
					fStartX=xs,fStartY=0,fEndX=xe,fEndY=-h*0.30,
					fStartW=1*es,fStartH=1*es,fEndW=0.5*es,fEndH=0.5*es,})
			-- make it spin fast
			ScriptCB_IFModel_SetOmegaY(ifs_personalstats.IconModel.cpointer,20)
			ifs_personalstats.IconModelFastMode = 1
		end
		
		IFText_fnSetString(this.ServerName,"SERVER NAME: " .. ScriptCB_GetGameName()) ---- advanced code by Phobos
		IFText_fnSetString(this.MissionTime,"MISSION TIME: " .. ScriptCB_GetMissionTime()) ---- advanced code by Phobos
		
		-- buttons?
		if(this.CurButton == "quit") then
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
			return
		elseif(this.CurButton == "details") then
			ifs_movietrans_PushScreen(ifs_personalstats)
			ScriptCB_SndPlaySound("shell_menu_enter");
			return
		elseif(this.CurButton == "restart") then
			ScriptCB_RestartMission() ---- useful for campaigns
			return
		elseif(this.CurButton == "exitwin") then
			ScriptCB_QuitToWindows()
			return
		elseif(this.CurButton == "awards") then
			ifs_movietrans_PushScreen(ifs_awardstats)
			ScriptCB_SndPlaySound("shell_menu_enter");
			return
		elseif(this.CurButton == "_upL" or this.CurButton == "_upR") then
			ifs_teamstats_fnNav(ListManager_fnScrollUp)
			ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
			ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)			
		elseif(this.CurButton == "_downL" or this.CurButton == "_downR") then
			ifs_teamstats_fnNav(ListManager_fnScrollDown)
			ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
			ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)			
		elseif(this.CurButton == "_sortKillsL" or this.CurButton == "_sortKillsR") then
			ScriptCB_SndPlaySound("shell_select_change")
			ScriptCB_SetTeamStatsSortMode(0);
			ifs_teamstats_fnFillContents(this,1);
		elseif(this.CurButton == "_sortDeathsL" or this.CurButton == "_sortDeathsR") then
			ScriptCB_SndPlaySound("shell_select_change");
			ScriptCB_SetTeamStatsSortMode(1);
			ifs_teamstats_fnFillContents(this,1);
		elseif(this.CurButton == "_sortCppL" or this.CurButton == "_sortCppR") then
			ScriptCB_SndPlaySound("shell_select_change");
			ScriptCB_SetTeamStatsSortMode(2);
			ifs_teamstats_fnFillContents(this,1);
		elseif(this.CurButton == "_sortNameL" or this.CurButton == "_sortNameR") then
			ScriptCB_SndPlaySound("shell_select_change");
			ScriptCB_SetTeamStatsSortMode(3);
			ifs_teamstats_fnFillContents(this,1);
		end
		
	end,
	--Back button quits stats
	Input_Back = function(this)
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		if(not gE3StatsTimeout or gE3StatsTimeout < 0) then
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
		end
	end,
	-- No U/D/L/R functionality possible on this screen (gotta have stubs
	-- here, or the base class will override)
	Input_GeneralUp = function(this)
		ifs_teamstats_fnNav(ListManager_fnNavUp)		
	end,
	Input_GeneralDown = function(this)
		ifs_teamstats_fnNav(ListManager_fnNavDown)
	end,
	Input_LTrigger = function(this)
		ifs_teamstats_fnNav(ListManager_fnPageUp)
	end,
	Input_RTrigger = function(this)
		ifs_teamstats_fnNav(ListManager_fnPageDown)
	end,
	Input_GeneralLeft = function(this)
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		ifs_teamstats_fnFlipLeftRight(this)
		ScriptCB_SndPlaySound("shell_select_change");
	end,
	Input_GeneralRight = function(this)
		this.fCurIdleTime = this.fMAX_IDLE_TIME 
		ifs_teamstats_fnFlipLeftRight(this)
		ScriptCB_SndPlaySound("shell_select_change");
	end,
	Update = function(this, fDt)
 		-- Call default base class's update function (make button bounce)
 		gIFShellScreenTemplate_fnUpdate(this,fDt)
		-- If the host is busy, then wait on this screen
		if(ScriptCB_CanClientLeaveStats) then
			if(fDt > 0.5) then
				fDt = 0.5 -- clamp this to sane values
			end
			if(ScriptCB_CanClientLeaveStats()) then
				IFObj_fnSetVis(this.quit, 1) -- show quit button
				gE3StatsTimeout = 0 -- allow quit now
			else
				IFObj_fnSetVis(this.quit, nil) -- hidden
				gE3StatsTimeout = 1 -- keep clients from leaving
			end
		end
			
		if(gE3StatsTimeout) then
			gE3StatsTimeout = gE3StatsTimeout - fDt
		end
 		-- if the models are done animating, slow down the rotations
 		if(this.IconModelFastMode and not this.LeftModel.bAnimActive) then
 			this.IconModelFastMode = nil
			ScriptCB_IFModel_SetOmegaY(this.LeftModel.cpointer,0.3)
			ScriptCB_IFModel_SetOmegaY(this.RightModel.cpointer,0.25)
		end
		
		if(gPlatformStr == "PC") then
			if( gMouseListBox ) then
				if(ScriptCB_CheckMouseMark()) then
					if( gMouseListBox == this.LeftList ) then
						this.bCursorOnLeft = 1
						if( teamstats_listbox_layoutL.CursorIdx == teamstats_listbox_layoutL.SelectedIdx) then
							teamstats_listbox_layoutR.SelectedIdx = nil
						end
					else
						this.bCursorOnLeft = nil
						if( teamstats_listbox_layoutR.CursorIdx == teamstats_listbox_layoutR.SelectedIdx) then
							teamstats_listbox_layoutL.SelectedIdx = nil
						end
					end
					this.RepaintListbox( this, this.bCursorOnLeft )
				end
				ScriptCB_SetMouseMark()
			end	
		end
		-- if we've been sitting here for a while, bail to the teaser screen
		this.fCurIdleTime = this.fCurIdleTime - fDt
		if((this.fCurIdleTime < 0) and (not gE3StatsTimeout or gE3StatsTimeout < 0)) then
			this.fCurIdleTime = 100
			ScriptCB_QuitFromStats()
			ScriptCB_SndPlaySound("shell_menu_exit");
		end
		
		-- update the visibility of the up/down arrows
		IFObj_fnSetVis(this.buttons.LeftUpArrow,teamstats_listbox_layoutL.FirstShownIdx > 1)
		IFObj_fnSetVis(this.buttons.RightUpArrow,teamstats_listbox_layoutL.FirstShownIdx > 1)
		local num = max(getn(teamstats_listbox_contentsL),getn(teamstats_listbox_contentsR))
		IFObj_fnSetVis(this.buttons.LeftDownArrow,teamstats_listbox_layoutL.FirstShownIdx+teamstats_listbox_layoutL.showcount <= num)
		IFObj_fnSetVis(this.buttons.RightDownArrow,teamstats_listbox_layoutL.FirstShownIdx+teamstats_listbox_layoutL.showcount <= num)
		
		-- animate the up/down arrows
		IFObj_UpdateBlinkyAnim(this.buttons.LeftUpArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftUpArrow.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightUpArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.RightUpArrow.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.LeftDownArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftDownArrow.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightDownArrow,ScriptCB_IFObj_TestHotSpot(this.buttons.RightDownArrow.cpointer),0.4,1,0.4,0.2)
		-- animate the stat sort icons	
		IFObj_UpdateBlinkyAnim(this.buttons.LeftColumnHeader1,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftColumnHeader1.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.LeftColumnHeader2,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftColumnHeader2.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.LeftColumnHeader3,ScriptCB_IFObj_TestHotSpot(this.buttons.LeftColumnHeader3.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightColumnHeader1,ScriptCB_IFObj_TestHotSpot(this.buttons.RightColumnHeader1.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightColumnHeader2,ScriptCB_IFObj_TestHotSpot(this.buttons.RightColumnHeader2.cpointer),0.4,1,0.4,0.2)
		IFObj_UpdateBlinkyAnim(this.buttons.RightColumnHeader3,ScriptCB_IFObj_TestHotSpot(this.buttons.RightColumnHeader3.cpointer),0.4,1,0.4,0.2)
			
 	end,
	-- Callback (from C++) to repaint the listbox with the current contents
	-- in the global teamstats_listbox_contents
	RepaintListbox = function(this, bOnLeft)	
  		if( bOnLeft ) then
			teamstats_listbox_layoutR.CursorIdx = nil
		else
			teamstats_listbox_layoutL.CursorIdx = nil
		end
		ListManager_fnFillContents(this.LeftList,teamstats_listbox_contentsL,teamstats_listbox_layoutL)
		ListManager_fnFillContents(this.RightList,teamstats_listbox_contentsR,teamstats_listbox_layoutR)
		
--		print(teamstats_listbox_layoutR.SelectedIdx, teamstats_listbox_layoutL.SelectedIdx)
	 end,	
}
-- Helper function, sets up parts of this screen that need any
-- programmatic work (i.e. scaling to screensize)
function ifs_teamstats_fnBuildScreen(this)
	-- Ask game for screen size, fill in values
	local r, b, v, widescreen = ScriptCB_GetScreenInfo()
	this.bgTexture.localpos_l = 0
	this.bgTexture.localpos_t = 0
	this.bgTexture.localpos_r = r*widescreen
	this.bgTexture.localpos_b = b
	this.bgTexture.uvs_b = v
--	if(this.Helptext_Back) then
--		IFText_fnSetString(this.Helptext_Back.helpstr,"ifs.stats.done")
--	end
--	if(this.Helptext_Accept) then
--		IFText_fnSetString(this.Helptext_Accept.helpstr,"ifs.stats.details")
--	end
	-- Inset slightly from fulls screen size
	local fw,fh = ScriptCB_GetScreenInfo()
	local w,h = ScriptCB_GetSafeScreenInfo()
	h = h * 0.82
	this.listbox = NewButtonWindow { ZPos = 200, x=0, y = 0,
		ScreenRelativeX = 0.5, -- center
		ScreenRelativeY = 0.48, -- middle of screen
		width = w,
		height = h,
		noEnterAnimation = 1,
	}
	
	--details button is bottom center of the listbox
	this.details.btn.y = h*0.485 + 4
	-- Cut width in half for 2-column layout, make containers to drop them into
	w = w * 0.5
	this.LeftList = NewIFContainer {
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.53,
		x =-w * 0.5
	}
	this.RightList = NewIFContainer {
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.53,
		x = w * 0.5
	}
	
	local iconWidth = 30
	local iconHeight = 30
	local pos1 = w * 0.20 - iconWidth/2
	local pos2 = w * 0.32 - iconWidth/2
	local pos3 = w * 0.44 - iconWidth/2
	local ypos = -h/2
	
	this.LeftList.Title = NewIFText {
		string = "TITLE: 30",
		font = "gamefont_medium",
		flashy = 0,
		textw = w * 0.5,
		texth = iconHeight,
		halign = "left",
		x = -w/2 + 15,
		y = ypos,
	}		
	this.LeftModel = NewIFModel {
		ScreenRelativeX = 0.25,
		ScreenRelativeY = 0.5,
		x=0,y=0,scale = 1,
		OmegaY = 0.3,
		lighting = 1,
	}
	this.RightList.Title = NewIFText {
		string = "TITLE: 30",
		font = "gamefont_medium",
		flashy = 0,
		textw = w * 0.5,
		texth = iconHeight,
		halign = "left",
		x = -w/2 + 15,
		y = ypos,
	}		
	this.RightModel = NewIFModel {
		ScreenRelativeX = 0.75,
		ScreenRelativeY = 0.5,
		x=0,y=0,scale = 1,
		OmegaY = 0.25,
		lighting = 1,
	}
	teamstats_listbox_layoutL.width = w - 20
	teamstats_listbox_layoutR.width = w - 20
	local listh = h * 0.85
	teamstats_listbox_layoutL.showcount = floor(listh / (teamstats_listbox_layoutL.yHeight + teamstats_listbox_layoutL.ySpacing)) - 1
	teamstats_listbox_layoutR.showcount = teamstats_listbox_layoutL.showcount
	ListManager_fnInitList(ifs_teamstats.LeftList,teamstats_listbox_layoutL)
	ListManager_fnInitList(ifs_teamstats.RightList,teamstats_listbox_layoutR)
	
	this.buttons = NewIFContainer {
		ScreenRelativeX = 0.5,
		ScreenRelativeY = 0.5,
	}	
	-- make the up and down arrows
	local arrowsize = 30
	this.buttons.LeftUpArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = -w*0.5, 
 		y = -h/2 + arrowsize*2.5 - 10,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t = -arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b =  arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_upL",
		uvs_diag = 1,
 	}
	this.buttons.RightUpArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = w*0.5, 
 		y = -h/2 + arrowsize*2.5 - 10,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t = -arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b =  arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_upR",
		uvs_diag = 1,
 	}
	this.buttons.LeftDownArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = -w*0.5, 
 		y = h/2 - arrowsize*1.5 + 15,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t =  arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b = -arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_downL",
		uvs_diag = 1,
 	}
	this.buttons.RightDownArrow = NewIFImage 
	{
 		ZPos = 0, 
 		x = w*0.5, 
 		y = h/2 - arrowsize*1.5 + 15,
 		inertUVs = 1,alpha = 180,
 		localpos_l = -arrowsize/2, localpos_t =  arrowsize/2,
 		localpos_r =  arrowsize/2, localpos_b = -arrowsize/2, 		
		texture = "small_arrow",
		AutoHotspot = "_downR",
		uvs_diag = 1,
 	}
	
	this.buttons.LeftColumnHeader1 = NewIFImage {
		x = pos1 - w/2, y = ypos + fh*0.03,
		texture = "stats_kills", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortKillsL",
	}
	this.buttons.LeftColumnHeader2 = NewIFImage {
		x = pos2 - w/2, y = ypos + fh*0.03,
		texture = "stats_deaths", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortDeathsL",
	}
	this.buttons.LeftColumnHeader3 = NewIFImage {
		x = pos3 - w/2, y = ypos + fh*0.03,
		texture = "stats_cpp", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortCppL",
	}
	this.buttons.RightColumnHeader1 = NewIFImage {
		x = pos1 + w/2, y = ypos + fh*0.03,
		texture = "stats_kills", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortKillsR",
	}
	this.buttons.RightColumnHeader2 = NewIFImage {
		x = pos2 + w/2, y = ypos + fh*0.03,
		texture = "stats_deaths", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortDeathsR",
	}
	this.buttons.RightColumnHeader3 = NewIFImage {
		x = pos3 + w/2, y = ypos + fh*0.03,
		texture = "stats_cpp", -- .tga assumed
		localpos_r = iconWidth, localpos_b = iconHeight,
		AutoHotspot = "_sortCppR",
	}
	
end
ifs_teamstats_fnBuildScreen(ifs_teamstats) -- programatic chunks
ifs_teamstats_fnBuildScreen = nil
AddIFScreen(ifs_teamstats,"ifs_teamstats")
			
			
			
				Not sure why the link wasn't posted on here before but here is the download 
http://www.swbfgamers.com/index.php?action=downloads;sa=view;down=1246