local J=game:GetService("\080\108\097\121\101\114\115")local s=game:GetService("\083\101\114\118\101\114\083\099\114\105\112\116\083\101\114\118\105\099\101")local p=s:WaitForChild("\070\105\110\100\101\114\115")local Z=require(p:WaitForChild("\068\111\109\097\105\110\070\105\110\100\101\114",2))local d=Z:FindDomain("\084\101\097\109\077\097\110\097\103\101\114")local t=Z:FindDomain("\080\108\097\121\101\114\077\097\110\097\103\101\114")local F=Z:FindDomain("\077\097\112\077\097\110\097\103\101\114")local G=Z:FindDomain("\084\105\109\101\077\097\110\097\103\101\114")local S=Z:FindDomain("\068\105\115\112\108\097\121\077\097\110\097\103\101\114")local C=require(script.Parent:WaitForChild("\067\111\110\102\105\103\077\097\110\097\103\101\114",2))local q={ConfigValues={},GameConfigKeys={INTERMISSION_DURATION="\073\078\084\069\082\077\073\083\083\073\079\078\095\068\085\082\065\084\073\079\078",MIN_PLAYERS="\077\073\078\095\080\076\065\089\069\082\083";ROUND_DURATION="\082\079\085\078\068\095\068\085\082\065\084\073\079\078";END_GAME_WAIT="\069\078\068\095\071\065\077\069\095\087\065\073\084"};FeatureFlagValues={};FeatureFlagKeys={UseVehicleSpawners="\085\115\101\086\101\104\105\099\108\101\083\112\097\119\110\101\114\115",UseNpcSpawners="\085\115\101\078\112\099\083\112\097\119\110\101\114\115",IsCaptureTheFlag="\073\115\067\097\112\116\117\114\101\084\104\101\070\108\097\103";UseSaveMap="\085\115\101\083\097\118\101\077\097\112";UseGameRounds="\085\115\101\071\097\109\101\082\111\117\110\100\115",AssignTeams="\065\115\115\105\103\110\084\101\097\109\115"}}local a=false local v=false local I=false local E=game.ReplicatedStorage.Events local w=E.CaptureFlag local L=E.ReturnFlag local function m(J)t:AddPlayerScore(J,1)d:AddTeamScore(J.TeamColor,1)S:DisplayNotification(J.TeamColor,"\067\097\112\116\117\114\101\100 \070\108\097\103\033")end local function M(J)S:DisplayNotification(J,"\070\108\097\103 \082\101\116\117\114\110\101\100\033")end function q.GetConfigValue(s,J)if s.ConfigValues[J]~=nil then return s.ConfigValues[J]end local p=C:GetConfigValueOrDefault(J)if p~=nil then s.ConfigValues[J]=p end return p end function q.GetFeatureFlagValue(s,J)if s.FeatureFlagValues[J]~=nil then return s.FeatureFlagValues[J]end local p=C:GetFeatureEnabled(J)if p~=nil then s.FeatureFlagValues[J]=p end return p end function q.LoadConfigValues(J)C:Init()for s,p in pairs(J.GameConfigKeys)do J.ConfigValues[s]=C:GetConfigValueOrDefault(p)end for s,p in pairs(J.FeatureFlagKeys)do J.FeatureFlagValues[s]=C:GetFeatureEnabled(p)end end function q.Initialize(J)J:LoadConfigValues()if J.FeatureFlagValues[J.FeatureFlagKeys.UseSaveMap]then F:SaveMap()end if J:GetFeatureFlagValue(J.FeatureFlagKeys.IsCaptureTheFlag)then w.Event:connect(m)L.Event:connect(M)end end function q.RunIntermission(s)a=false if not s:GetFeatureFlagValue(s.FeatureFlagKeys.UseGameRounds)then return end a=true local p=s:GetConfigValue(s.GameConfigKeys.MIN_PLAYERS)local Z=s:GetConfigValue(s.GameConfigKeys.INTERMISSION_DURATION)G:StartTimer(Z)S:StartIntermission()v=J.NumPlayers>=p S:UpdateTimerInfo(true,not v)spawn(function()repeat if v and J.NumPlayers<p then v=false elseif not v and J.NumPlayers>=p then v=true end S:UpdateTimerInfo(true,not v)wait(.5)until a==false end)wait(Z)a=false end function q.StopIntermission(J)S:UpdateTimerInfo(false,false)S:StopIntermission()end function q.GameReady(s)return J.NumPlayers>=s:GetConfigValue(s.GameConfigKeys.MIN_PLAYERS)end function q.StartRound(J)d:ClearTeamScores()t:ClearPlayerScores()t:AllowPlayerSpawn(true)t:LoadPlayers()I=true t:SetGameRunning(true)if J:GetFeatureFlagValue(J.FeatureFlagKeys.UseGameRounds)then G:StartTimer(J:GetConfigValue(J.GameConfigKeys.ROUND_DURATION))end end function q.Update(J) end function q.RoundOver(J)if J:GetFeatureFlagValue(J.FeatureFlagKeys.UseGameRounds)then local J=d:HasTeamWon()if J then S:DisplayVictory(J)return true end if G:TimerDone()then if d:AreTeamsTied()then S:DisplayVictory("\084\105\101")else J=d:GetWinningTeam()S:DisplayVictory(J)end return true end end return false end function q.RoundCleanup(J)if J:GetFeatureFlagValue(J.FeatureFlagKeys.UseGameRounds)then t:SetGameRunning(false)wait(J:GetConfigValue(J.GameConfigKeys.END_GAME_WAIT))t:AllowPlayerSpawn(false)t:DestroyPlayers()S:DisplayVictory(nil)d:ClearTeamScores()t:ClearPlayerScores()if J:GetFeatureFlagValue(J.FeatureFlagKeys.AssignTeams)then d:ShuffleTeams()end if J:GetFeatureFlagValue(J.FeatureFlagKeys.UseSaveMap)then F:ClearMap()F:LoadMap()end end end return q
-- ROBLOX services
local Players = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
local findersFolder = ServerScriptService:WaitForChild("Finders")
local DomainFinder = require(findersFolder:WaitForChild("DomainFinder", 2))

-- Game services
local TeamManager = DomainFinder:FindDomain("TeamManager")
local PlayerManager = DomainFinder:FindDomain("PlayerManager")
local MapManager = DomainFinder:FindDomain("MapManager")
local TimeManager = DomainFinder:FindDomain("TimeManager")
local DisplayManager = DomainFinder:FindDomain("DisplayManager")
local ConfigManager = require(script.Parent:WaitForChild("ConfigManager", 2))


local GameManager = {
	ConfigValues = {},
	GameConfigKeys = {
		INTERMISSION_DURATION = "INTERMISSION_DURATION",
		MIN_PLAYERS = "MIN_PLAYERS",
		ROUND_DURATION = "ROUND_DURATION",
		END_GAME_WAIT = "END_GAME_WAIT"
	},
	FeatureFlagValues = {},
	FeatureFlagKeys = {
		UseVehicleSpawners = "UseVehicleSpawners",
		UseNpcSpawners = "UseNpcSpawners",
		IsCaptureTheFlag = "IsCaptureTheFlag",
		UseSaveMap = "UseSaveMap",
		UseGameRounds = "UseGameRounds",
		AssignTeams = "AssignTeams"
	}
}

-- Local Variables
local IntermissionRunning = false
local EnoughPlayers = false
local GameRunning = false
local Events = game.ReplicatedStorage.Events
local CaptureFlag = Events.CaptureFlag
local ReturnFlag = Events.ReturnFlag

-- Local Functions
local function OnCaptureFlag(player)
	PlayerManager:AddPlayerScore(player, 1)
	TeamManager:AddTeamScore(player.TeamColor, 1)
	DisplayManager:DisplayNotification(player.TeamColor, 'Captured Flag!')
end

local function OnReturnFlag(flagColor)
	DisplayManager:DisplayNotification(flagColor, 'Flag Returned!')
end

-- Public Functions
function GameManager:GetConfigValue(configKey)
	if self.ConfigValues[configKey] ~= nil then
		return self.ConfigValues[configKey]
	end
	local configValue = ConfigManager:GetConfigValueOrDefault(configKey)
	if configValue ~= nil then
		self.ConfigValues[configKey] = configValue
	end
	return configValue
end

function GameManager:GetFeatureFlagValue(featureFlagKey)
	if self.FeatureFlagValues[featureFlagKey] ~= nil then
		return self.FeatureFlagValues[featureFlagKey]
	end
	local featureFlagValue = ConfigManager:GetFeatureEnabled(featureFlagKey)
	if featureFlagValue ~= nil then
		self.FeatureFlagValues[featureFlagKey] = featureFlagValue
	end
	return featureFlagValue
end

function GameManager:LoadConfigValues()
	ConfigManager:Init()
	for key, val in pairs(self.GameConfigKeys) do
		self.ConfigValues[key] = ConfigManager:GetConfigValueOrDefault(val)
	end
	for key, val in pairs(self.FeatureFlagKeys) do
		self.FeatureFlagValues[key] = ConfigManager:GetFeatureEnabled(val)
	end
end

function GameManager:Initialize()
	self:LoadConfigValues()
	if self.FeatureFlagValues[self.FeatureFlagKeys.UseSaveMap] then
		MapManager:SaveMap()
	end
	-- Bind Events
	if self:GetFeatureFlagValue(self.FeatureFlagKeys.IsCaptureTheFlag) then
		CaptureFlag.Event:connect(OnCaptureFlag)
		ReturnFlag.Event:connect(OnReturnFlag)
	end
end

function GameManager:RunIntermission()
	IntermissionRunning = false
	if not self:GetFeatureFlagValue(self.FeatureFlagKeys.UseGameRounds) then
		return
	end

	IntermissionRunning = true
	local MIN_PLAYERS = self:GetConfigValue(self.GameConfigKeys.MIN_PLAYERS)
	local INTERMISSION_DURATION = self:GetConfigValue(self.GameConfigKeys.INTERMISSION_DURATION)
	TimeManager:StartTimer(INTERMISSION_DURATION)
	DisplayManager:StartIntermission()
	EnoughPlayers = Players.NumPlayers >= MIN_PLAYERS
	DisplayManager:UpdateTimerInfo(true, not EnoughPlayers)
	spawn(function()
		repeat
			if EnoughPlayers and Players.NumPlayers < MIN_PLAYERS then
				EnoughPlayers = false
			elseif not EnoughPlayers and Players.NumPlayers >= MIN_PLAYERS then
				EnoughPlayers = true
			end
			DisplayManager:UpdateTimerInfo(true, not EnoughPlayers)
			wait(.5)
		until IntermissionRunning == false
	end)

	wait(INTERMISSION_DURATION)
	IntermissionRunning = false
end

function GameManager:StopIntermission()
	--IntermissionRunning = false
	DisplayManager:UpdateTimerInfo(false, false)
	DisplayManager:StopIntermission()
end

function GameManager:GameReady()
	return Players.NumPlayers >= self:GetConfigValue(self.GameConfigKeys.MIN_PLAYERS)
end

function GameManager:StartRound()
	TeamManager:ClearTeamScores()
	PlayerManager:ClearPlayerScores()

	PlayerManager:AllowPlayerSpawn(true)
	PlayerManager:LoadPlayers()

	GameRunning = true
	PlayerManager:SetGameRunning(true)
	if self:GetFeatureFlagValue(self.FeatureFlagKeys.UseGameRounds) then
		TimeManager:StartTimer(self:GetConfigValue(self.GameConfigKeys.ROUND_DURATION))
	end
	
end

function GameManager:Update()
	--TODO: Add custom custom game code here

end

function GameManager:RoundOver()
	if self:GetFeatureFlagValue(self.FeatureFlagKeys.UseGameRounds) then
		local winningTeam = TeamManager:HasTeamWon()
		if winningTeam then
			DisplayManager:DisplayVictory(winningTeam)
			return true
		end
		if TimeManager:TimerDone() then
			if TeamManager:AreTeamsTied() then
				DisplayManager:DisplayVictory('Tie')
			else
				winningTeam = TeamManager:GetWinningTeam()
				DisplayManager:DisplayVictory(winningTeam)
			end
			return true
		end
	end
	return false
end

function GameManager:RoundCleanup()
	if self:GetFeatureFlagValue(self.FeatureFlagKeys.UseGameRounds) then
		PlayerManager:SetGameRunning(false)
		wait(self:GetConfigValue(self.GameConfigKeys.END_GAME_WAIT))

		PlayerManager:AllowPlayerSpawn(false)
		PlayerManager:DestroyPlayers()
		DisplayManager:DisplayVictory(nil)
		TeamManager:ClearTeamScores()
		PlayerManager:ClearPlayerScores()

		if self:GetFeatureFlagValue(self.FeatureFlagKeys.AssignTeams) then
			TeamManager:ShuffleTeams()
		end
		if self:GetFeatureFlagValue(self.FeatureFlagKeys.UseSaveMap) then
			MapManager:ClearMap()
			MapManager:LoadMap()
		end
	end
end

return GameManager
