378 lines
7.7 KiB
Plaintext
378 lines
7.7 KiB
Plaintext
local Players = game:GetService("Players")
|
|
local ServerScriptService = game:GetService("ServerScriptService")
|
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
|
|
local ServerStorage = game:GetService("ServerStorage")
|
|
|
|
local Data = ReplicatedStorage.Data
|
|
|
|
local BotData = require(Data.BotData)
|
|
local DataTypes = require(Data.DataTypes)
|
|
local GameState = require(Data.GameState)
|
|
|
|
local sData = ServerScriptService.Data
|
|
local DataManager = require(sData.DataManager)
|
|
local ValueNames = require(sData.ValueNames)
|
|
|
|
local sModules = ServerScriptService.Modules
|
|
local Bot = require(sModules.Classes.GameObject.Bot)
|
|
local VotingHandlerServer = require(sModules.VotingHandlerServer)
|
|
local TurnManager = require(sModules.TurnManager)
|
|
local ObjectManager = require(sModules.ObjectManager)
|
|
|
|
local MapManager = require(sModules.Map.MapManager)
|
|
|
|
|
|
local FerrUtils = require(ReplicatedStorage.Shared.SharedUtils.FerrUtils)
|
|
local rBotUtils = require(ReplicatedStorage.Shared.SharedUtils.sharedBotUtils)
|
|
|
|
local BotUtils = require(sModules.Utils.BotUtils)
|
|
|
|
local Remote = ReplicatedStorage.Remote
|
|
|
|
local rev_statusRemoteEvent = Remote.StatusRemoteEvent
|
|
local rev_timerRemoteEvent = Remote.TimerRemoteEvent
|
|
local rev_UpdateGameState = Remote.UpdateGameState
|
|
|
|
local Round = {}
|
|
Round.__index = Round
|
|
|
|
function getPlaying() : {Player}
|
|
return game:GetService("CollectionService"):GetTagged("PLAYING")
|
|
end
|
|
|
|
function Round.new()
|
|
local self = setmetatable({}, Round)
|
|
if game:GetService("RunService"):IsStudio() then
|
|
self.IntermissionTime = 1
|
|
else
|
|
self.IntermissionTime = 1
|
|
end
|
|
|
|
self.MapVotingTime = 100
|
|
self.GraceTime = 1
|
|
self.DecisionTime = 15
|
|
self.Status = ""
|
|
self.RoundResults = {}
|
|
|
|
self:ChangeGameState(GameState.LOBBY)
|
|
self.Timer = 0
|
|
|
|
return self
|
|
end
|
|
|
|
function Round:ChangeStatus(newText : DataStoreListingPages)
|
|
self.Status = newText
|
|
self:UpdateState()
|
|
end
|
|
|
|
function Round:FireTo(remote,players,...)
|
|
players = players or game.Players:GetPlayers()
|
|
for i,v in pairs(players) do
|
|
remote:FireClient(v,...)
|
|
end
|
|
end
|
|
|
|
function Round:ChangeGameState(newState : number)
|
|
self.GameState = newState
|
|
shared.Phase = newState
|
|
self:FireTo(rev_UpdateGameState,getPlaying(),newState)
|
|
end
|
|
|
|
|
|
|
|
function Round:UpdateState()
|
|
rev_statusRemoteEvent:FireAllClients(self.Status .. ": " .. self.Timer)
|
|
end
|
|
|
|
function Round:EnoughPlayers()
|
|
return #Players:GetPlayers() >= 2 or game:GetService("RunService"):IsStudio() and script:GetAttribute("StudioEnoughPlayersOverride")
|
|
end
|
|
|
|
function Round:AllPlayersReady()
|
|
return #getPlaying() == TurnManager.GetReadyPlayers()
|
|
end
|
|
|
|
function Round:WaitFor(sec : number,condition,...)
|
|
for index = sec,0,-1 do
|
|
self.Timer = index
|
|
self:UpdateState()
|
|
task.wait(.5)
|
|
if self.Break then
|
|
self.Break = false
|
|
self.Timer = 0
|
|
self:UpdateState()
|
|
break
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
function Round:Halt()
|
|
repeat task.wait() until self.Break == false
|
|
end
|
|
|
|
function Round:Intermission()
|
|
|
|
self:ChangeGameState(GameState.LOBBY)
|
|
self:ChangeStatus("Intermission")
|
|
self:WaitFor(self.IntermissionTime)
|
|
end
|
|
function Round:ChooseMap()
|
|
workspace.Map:ClearAllChildren()
|
|
|
|
|
|
while task.wait() do
|
|
|
|
self:ChangeStatus("Choose Map")
|
|
VotingHandlerServer.StartVoting(1,"MapData",workspace.Lobby["Map Voting Stands"]:GetChildren())
|
|
self:WaitFor(self.MapVotingTime)
|
|
local winnerIndex,winnerData : DataTypes.VoteOptionData = VotingHandlerServer.EndVoting()
|
|
print(winnerIndex)
|
|
print(winnerData)
|
|
|
|
MapManager.SpawnMap(winnerData.Name)
|
|
break
|
|
end
|
|
|
|
self:ChangeStatus("Loading map...")
|
|
self:WaitFor(MapManager.MAP_LOAD_TIME)
|
|
end
|
|
|
|
function Round:BringPlayers()
|
|
local pick = "PlasmaBot"
|
|
|
|
|
|
|
|
for _,plr in pairs(game.Players:GetPlayers()) do
|
|
local char = plr.Character
|
|
if not char then
|
|
continue
|
|
end
|
|
char:PivotTo(workspace.BoxOfDoom.PrimaryPart.CFrame)
|
|
|
|
local newBot = Bot.new(plr,pick,char)
|
|
newBot:_Init()
|
|
plr:AddTag("PLAYING")
|
|
end
|
|
|
|
BotUtils.SpawnBots(getPlaying())
|
|
|
|
end
|
|
|
|
Round.END_TYPES = {
|
|
WIN = 1,
|
|
DRAW = 2,
|
|
}
|
|
|
|
function Round:ShouldRoundEnd()
|
|
local max = #getPlaying()
|
|
|
|
if game:GetService("RunService"):IsStudio() then
|
|
return
|
|
end
|
|
|
|
|
|
|
|
local alive = {}
|
|
|
|
for i,id in pairs(#getPlaying()) do
|
|
local b = ObjectManager.Get(id)
|
|
if b.Components.Health:IsAlive() then
|
|
table.insert(alive,id)
|
|
else
|
|
ObjectManager.Destroy(id)
|
|
end
|
|
end
|
|
|
|
if #alive == 0 then
|
|
return Round.END_TYPES.DRAW
|
|
end
|
|
|
|
if #alive == 1 then
|
|
return Round.END_TYPES.WIN,alive[1]
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
function Round:GracePeriod()
|
|
self:ChangeStatus("Grace period")
|
|
self:ChangeGameState(GameState.GRACE)
|
|
self:WaitFor(self.GraceTime)
|
|
|
|
end
|
|
|
|
|
|
function Round:TryStopEarlyAim()
|
|
task.spawn(function()
|
|
repeat task.wait() until self.GameState == GameState.RESOLVING or self:AllPlayersReady()
|
|
if self.GameState ~= GameState.RESOLVING then
|
|
self.Break = true
|
|
end
|
|
self:Halt()
|
|
end)
|
|
end
|
|
|
|
function Round:StartAimPhase()
|
|
--for i,v in pairs(workspace.Playing:GetChildren()) do
|
|
-- v.PrimaryPart.Anchored = true
|
|
--end
|
|
self:ChangeStatus("Decision making")
|
|
self:ChangeGameState(GameState.AIMING)
|
|
|
|
for i,plr in pairs(getPlaying()) do
|
|
local primary = rBotUtils.GetBotRoot(plr.UserId)
|
|
local rot = primary.Orientation
|
|
primary.Orientation = Vector3.new(0,0,rot.Z)
|
|
end
|
|
|
|
TurnManager.collectInputs()
|
|
|
|
self:TryStopEarlyAim()
|
|
|
|
|
|
self:WaitFor(self.DecisionTime)
|
|
|
|
end
|
|
|
|
|
|
function Round:ShouldStopEarlyResolve()
|
|
for _,gameObject in pairs(ObjectManager.GameObject) do
|
|
if not gameObject.model or not gameObject.model.Parent then
|
|
continue
|
|
end
|
|
local vel = gameObject.model.PrimaryPart.AssemblyLinearVelocity
|
|
|
|
local horizontalVel = Vector3.new(vel.X, 0, vel.Z).Magnitude
|
|
local verticalVel = math.abs(vel.Y)
|
|
if horizontalVel > 0.1 or verticalVel > 0.5 or not rBotUtils.IsObjectOnFloor(gameObject.model) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
|
|
|
|
return true
|
|
end
|
|
function Round:TryStopEarlyResolve()
|
|
task.spawn(function()
|
|
local stableTime = 0
|
|
print(self.GameState)
|
|
while self.GameState == GameState.RESOLVING do
|
|
task.wait(0.1)
|
|
|
|
if self:ShouldStopEarlyResolve() then
|
|
stableTime += 0.1
|
|
if stableTime >= 0.5 then -- must be stable for 0.5s
|
|
self.Break = true
|
|
break
|
|
end
|
|
else
|
|
stableTime = 0
|
|
end
|
|
end
|
|
|
|
self:Halt()
|
|
end)
|
|
end
|
|
|
|
function Round:StartResolvePhase()
|
|
self:ChangeGameState(GameState.RESOLVING)
|
|
|
|
self:TryStopEarlyResolve()
|
|
|
|
for _, v : Model in pairs(workspace.Bots:GetChildren()) do
|
|
|
|
local root = v.PrimaryPart
|
|
root:SetNetworkOwner(nil)
|
|
v:PivotTo(v:GetPivot())
|
|
|
|
root.Velocity = Vector3.zero
|
|
root.Anchored = false
|
|
end
|
|
TurnManager.resolve()
|
|
|
|
self:ChangeStatus("Resolve")
|
|
self:WaitFor(10)
|
|
end
|
|
|
|
function Round:Start()
|
|
|
|
local endType,winner = nil,nil
|
|
|
|
while task.wait() do
|
|
|
|
endType,winner = self:ShouldRoundEnd()
|
|
|
|
if endType then
|
|
return endType,winner
|
|
end
|
|
|
|
|
|
self:StartAimPhase()
|
|
self:StartResolvePhase()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function Round:Results(endtype,winner : number)
|
|
|
|
for i,v in pairs(getPlaying()) do
|
|
v:RemoveTag("PLAYING")
|
|
end
|
|
|
|
|
|
ObjectManager.DestroyAll()
|
|
MapManager.DestroyMap()
|
|
|
|
local text
|
|
|
|
if endtype == Round.END_TYPES.WIN then
|
|
local winnerName
|
|
pcall(function()
|
|
winnerName = game.Players:GetNameFromUserIdAsync(winner)
|
|
end)
|
|
winnerName = winnerName or "Studio guy"
|
|
|
|
text = winnerName .. " has won!"
|
|
pcall(function()
|
|
DataManager.AddValue(game.Players:GetPlayerByUserId(winner),ValueNames.Wins,1)
|
|
end)
|
|
else
|
|
text = "It's a draw!"
|
|
end
|
|
for i,v in pairs(game.Players:GetPlayers()) do
|
|
v:LoadCharacterAsync()
|
|
end
|
|
self:ChangeGameState(GameState.RESULTS)
|
|
self:ChangeStatus(text)
|
|
self:WaitFor(5)
|
|
|
|
end
|
|
|
|
function Round:Initiate()
|
|
|
|
while true do
|
|
local result = self:EnoughPlayers()
|
|
if not result then
|
|
self:ChangeStatus("Not enough players")
|
|
return
|
|
end
|
|
|
|
self:Intermission()
|
|
self:ChooseMap()
|
|
self:BringPlayers()
|
|
|
|
self:GracePeriod()
|
|
|
|
local endType,winner = self:Start()
|
|
|
|
self:Results(endType,winner)
|
|
|
|
end
|
|
end
|
|
|
|
return Round |