Almost finished garage!
This commit is contained in:
parent
3ff5337437
commit
05c424e6c1
2
.vscode/settings.json
vendored
Normal file
2
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@ -34,6 +34,7 @@
|
|||||||
"ServerScriptService": {
|
"ServerScriptService": {
|
||||||
"$path": "src/server"
|
"$path": "src/server"
|
||||||
},
|
},
|
||||||
|
|
||||||
"StarterPlayer": {
|
"StarterPlayer": {
|
||||||
"StarterPlayerScripts": {
|
"StarterPlayerScripts": {
|
||||||
"$path": "src/client"
|
"$path": "src/client"
|
||||||
|
|||||||
4
luau-lsp.json
Normal file
4
luau-lsp.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"luau-lsp.sourcemap.enabled": true,
|
||||||
|
"luau-lsp.sourcemap.file": "sourcemap.json"
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@ local DataManager = {}
|
|||||||
|
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
|
||||||
|
local Template = require(script.Parent.Template)
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
local OrderedDataStore = require("./OrderedDatastoreHandler")
|
local OrderedDataStore = require("./OrderedDatastoreHandler")
|
||||||
|
|
||||||
local ValueNames = require("./ValueNames")
|
local ValueNames = require("./ValueNames")
|
||||||
@ -9,26 +11,24 @@ local DataStoreNames = require("./DataStoreNames")
|
|||||||
|
|
||||||
local ProfileStore
|
local ProfileStore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Store profiles from ProfileStore
|
-- Store profiles from ProfileStore
|
||||||
DataManager.Profiles = {}
|
DataManager.Profiles = {}
|
||||||
|
|
||||||
local synced = {}
|
local synced = {}
|
||||||
|
|
||||||
function DataManager.getKey(player : Player,key : string)
|
function DataManager.getKey(player: Player, key: string)
|
||||||
return "PLAYER_" .. player.UserId .. "_" .. key
|
return "PLAYER_" .. player.UserId .. "_" .. key
|
||||||
end
|
end
|
||||||
function DataManager.AddValue(player : Player,key : string,num)
|
function DataManager.AddValue(player: Player, key: string, num)
|
||||||
local value = DataManager.GetValue(player,key)
|
local value = DataManager.GetValue(player, key)
|
||||||
if not value then
|
if not value then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
DataManager.SetValue(player, key, value + num)
|
DataManager.SetValue(player, key, value + num)
|
||||||
end
|
end
|
||||||
function DataManager.SubValue(player : Player,key : number,num)
|
function DataManager.SubValue(player: Player, key: number, num)
|
||||||
local value = DataManager.GetValue(player,key)
|
local value = DataManager.GetValue(player, key)
|
||||||
if not value then
|
if not value then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -36,7 +36,7 @@ function DataManager.SubValue(player : Player,key : number,num)
|
|||||||
DataManager.SetValue(player, key, value - num)
|
DataManager.SetValue(player, key, value - num)
|
||||||
end
|
end
|
||||||
|
|
||||||
function DataManager.GetValue(player : Player,key : string)
|
function DataManager.GetValue(player: Player, key: string)
|
||||||
local profile = DataManager.Profiles[player]
|
local profile = DataManager.Profiles[player]
|
||||||
if not profile then
|
if not profile then
|
||||||
return
|
return
|
||||||
@ -44,7 +44,7 @@ function DataManager.GetValue(player : Player,key : string)
|
|||||||
return profile.Data[key]
|
return profile.Data[key]
|
||||||
end
|
end
|
||||||
|
|
||||||
function DataManager.SetValue(player : Player,key : string,num)
|
function DataManager.SetValue(player: Player, key: string, num)
|
||||||
local profile = DataManager.Profiles[player]
|
local profile = DataManager.Profiles[player]
|
||||||
if not profile then
|
if not profile then
|
||||||
return
|
return
|
||||||
@ -52,7 +52,7 @@ function DataManager.SetValue(player : Player,key : string,num)
|
|||||||
|
|
||||||
profile.Data[key] = num
|
profile.Data[key] = num
|
||||||
|
|
||||||
local keyName = DataManager.getKey(player,key)
|
local keyName = DataManager.getKey(player, key)
|
||||||
local s = synced[keyName]
|
local s = synced[keyName]
|
||||||
if not s then
|
if not s then
|
||||||
return
|
return
|
||||||
@ -64,43 +64,47 @@ function DataManager.SetValue(player : Player,key : string,num)
|
|||||||
end
|
end
|
||||||
local datastore = s.Datastore
|
local datastore = s.Datastore
|
||||||
if datastore then
|
if datastore then
|
||||||
OrderedDataStore.SaveData(player,datastore,num)
|
OrderedDataStore.SaveData(player, datastore, num)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function DataManager.GetTanks(player : Player)
|
function DataManager.CreateLoadout(player, tank, loadoutData: DataTypes.Loadout)
|
||||||
|
local profile = DataManager.GetPlayerData(player)
|
||||||
|
|
||||||
|
local tankLoadoutsTbl = profile.Data[tank]
|
||||||
|
|
||||||
|
if not tankLoadoutsTbl then
|
||||||
|
profile.Data[tank] = {}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function DataManager.GetTankData(player : Player,name : string)
|
function DataManager.RemoveLoadout(player) end
|
||||||
|
|
||||||
|
function DataManager.UpdateLoadout() end
|
||||||
|
|
||||||
|
function DataManager.GetPlayerData(player: Player): typeof(Template)
|
||||||
|
return DataManager.Profiles[player]
|
||||||
end
|
end
|
||||||
|
|
||||||
function DataManager.SwitchTank(player : Player,tank : string)
|
function DataManager.GetTanks(player: Player) end
|
||||||
|
|
||||||
end
|
function DataManager.GetTankData(player: Player, name: string) end
|
||||||
|
|
||||||
function DataManager.SwitchTankSkin(player : Player,skinName : string)
|
function DataManager.SwitchTank(player: Player, tank: string) end
|
||||||
|
|
||||||
end
|
function DataManager.SwitchTankSkin(player: Player, skinName: string) end
|
||||||
|
|
||||||
function DataManager.UnlockTank(player : Player,tank : string)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function DataManager.UnlockTankSkin(player : Player,skinName)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
function DataManager.UnlockTank(player: Player, tank: string) end
|
||||||
|
|
||||||
|
function DataManager.UnlockTankSkin(player: Player, skinName) end
|
||||||
|
|
||||||
-- yh ill add it later
|
-- yh ill add it later
|
||||||
|
|
||||||
function DataManager.SyncValue(player : Player,value : IntValue,key : string,datastore : string)
|
function DataManager.SyncValue(player: Player, value: IntValue, key: string, datastore: string)
|
||||||
local keyName = DataManager.getKey(player,key)
|
local keyName = DataManager.getKey(player, key)
|
||||||
synced[keyName] = {Value = value,Datastore = datastore}
|
synced[keyName] = { Value = value, Datastore = datastore }
|
||||||
|
|
||||||
DataManager.SetValue(player,key,DataManager.GetValue(player,key))
|
DataManager.SetValue(player, key, DataManager.GetValue(player, key))
|
||||||
end
|
end
|
||||||
|
|
||||||
--sup
|
--sup
|
||||||
|
|||||||
@ -1,135 +1,173 @@
|
|||||||
|
local HttpService = game:GetService("HttpService")
|
||||||
local Players = game:GetService("Players")
|
local Players = game:GetService("Players")
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
local ServerScriptService = game:GetService("ServerScriptService")
|
local ServerScriptService = game:GetService("ServerScriptService")
|
||||||
local RemoteFunction = ReplicatedStorage.Remote.InventoryService
|
|
||||||
|
local Template = require(script.Parent.Template)
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
|
local DataManager = require(ServerScriptService.Data.DataManager)
|
||||||
|
|
||||||
|
local Remote = ReplicatedStorage.Remote
|
||||||
|
local rfn_Inventory = Remote:WaitForChild("InventoryService") :: RemoteFunction
|
||||||
|
|
||||||
local InventoryService = {}
|
local InventoryService = {}
|
||||||
|
|
||||||
local PlayersInventory : {[number] : {}} = {}
|
-- ─────────────────────────────────────────
|
||||||
|
-- Internal
|
||||||
|
-- ─────────────────────────────────────────
|
||||||
|
|
||||||
local Tanks: {string} = {}
|
type Inventory = typeof(Template.Inventory)
|
||||||
for _, tank in ReplicatedStorage:WaitForChild("Assets"):WaitForChild("Models"):WaitForChild("Tanks"):GetChildren() do
|
|
||||||
if tank.Name ~= "Tank (Testing)" or game:GetService("RunService"):IsStudio() then
|
local function getInventory(player: Player): Inventory?
|
||||||
table.insert(Tanks, tank.Name)
|
local profile = DataManager.Profiles[player]
|
||||||
end
|
if not profile then
|
||||||
end
|
return nil
|
||||||
local Skins: {[typeof(Tanks)] : string} = {}
|
|
||||||
for _, tank in Tanks do
|
|
||||||
Skins[tank] = {}
|
|
||||||
for _, skin in ReplicatedStorage:WaitForChild("Assets"):WaitForChild("Models"):WaitForChild("Tanks"):WaitForChild(tank):GetChildren() do
|
|
||||||
if skin.Name ~= "Base" then
|
|
||||||
table.insert(Skins[tank], skin.Name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
print(profile.Data.Inventory)
|
||||||
|
return profile.Data.Inventory
|
||||||
end
|
end
|
||||||
|
|
||||||
function InventoryService.GetModel(tankName : string, skinName : string)
|
local function syncToClient(player: Player)
|
||||||
local base = ReplicatedStorage:WaitForChild("Assets"):WaitForChild("Models"):WaitForChild("Tanks"):WaitForChild(tankName):FindFirstChild("Base")
|
if true then
|
||||||
local skin = ReplicatedStorage:WaitForChild("Assets"):WaitForChild("Models"):WaitForChild("Tanks"):WaitForChild(tankName):FindFirstChild(skinName)
|
return
|
||||||
if base and skin then
|
|
||||||
return base, skin
|
|
||||||
end
|
end
|
||||||
|
local inv = getInventory(player)
|
||||||
|
--if inv then
|
||||||
|
-- rev_InventorySync:FireClient(player, inv)
|
||||||
|
--end
|
||||||
end
|
end
|
||||||
|
|
||||||
function createPlayerInventory(player : Player)
|
function InventoryService.GetInventory(player: Player): Inventory?
|
||||||
print("Creating inventory: ".. player.Name)
|
return getInventory(player)
|
||||||
PlayersInventory[player.UserId] = {}
|
end
|
||||||
local Loadouts: {[string] : string} = {}
|
|
||||||
local SelectedLoadout: string
|
|
||||||
local PlayerSkins: {[string] : string} = {}
|
|
||||||
|
|
||||||
local Inventory = {}
|
-- Returns the skin currently equipped for a given tank.
|
||||||
Inventory["SelectedLoadout"] = ""
|
function InventoryService.GetSelectedSkin(player: Player, tankName: string): string
|
||||||
Inventory["Loadouts"] = Loadouts
|
local inv = getInventory(player)
|
||||||
Inventory["Tanks"] = {}
|
if not inv then
|
||||||
Inventory["Skins"] = PlayerSkins
|
return "Default"
|
||||||
PlayersInventory[player.UserId] = Inventory
|
end
|
||||||
|
return inv.Loadouts[tankName] or "Default"
|
||||||
|
end
|
||||||
|
|
||||||
if Inventory["Tanks"] == nil or #Inventory["Tanks"] == 0 then
|
function InventoryService.GetCurrentLoadout(player: Player)
|
||||||
Inventory["Tanks"] = {"Tank"}
|
local inv = getInventory(player)
|
||||||
|
local current = inv.CurrentLoadouts[inv.SelectedTank]
|
||||||
|
return current
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryService.CreateLoadout(player, tankName, loadout: DataTypes.Loadout): string
|
||||||
|
local inv = getInventory(player)
|
||||||
|
local randomId = HttpService:GenerateGUID(false)
|
||||||
|
inv.Loadouts[tankName][randomId] = loadout
|
||||||
|
|
||||||
|
return randomId
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryService.SelectTank(player: Player, tankName: string): (boolean, string?)
|
||||||
|
local inv = getInventory(player)
|
||||||
|
if not inv then
|
||||||
|
return false, "Profile not loaded"
|
||||||
|
end
|
||||||
|
if not table.find(inv.Tanks, tankName) then
|
||||||
|
return false, "Tank not owned"
|
||||||
end
|
end
|
||||||
|
|
||||||
if Inventory["SelectedLoadout"] == "" or Inventory["SelectedLoadout"] == nil or table.find(Inventory["Tanks"], Inventory["SelectedLoadout"]) then
|
inv.SelectedTank = tankName
|
||||||
print(InventoryService.SelectLoadout(player, Inventory["Tanks"][1]))
|
syncToClient(player)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
-- Sets which skin is equipped for a specific tank.
|
||||||
|
function InventoryService.UpdateLoadout(player: Player, tank: string, skin: string): (boolean, string?)
|
||||||
|
local inv = getInventory(player)
|
||||||
|
if not inv then
|
||||||
|
return false, "Profile not loaded"
|
||||||
|
end
|
||||||
|
if not table.find(inv.Tanks, tank) then
|
||||||
|
return false, "Tank not owned"
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, tank in Inventory["Tanks"] do
|
local ownedSkins = inv.Skins[tank]
|
||||||
if Inventory["Skins"][tank] == nil or #Inventory["Skins"][tank] == 0 then
|
if not ownedSkins or not table.find(ownedSkins, skin) then
|
||||||
Inventory["Skins"][tank] = {"Default"}
|
return false, "Skin not owned"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if not CheckIfLoadoutExists(player, Inventory["Tanks"][1]) then
|
inv.Loadouts[tank] = skin
|
||||||
InventoryService.UpdateLoadout(player, Inventory["SelectedLoadout"], Inventory["Skins"][Inventory["Tanks"][1]][1])
|
syncToClient(player)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryService.UnlockTank(player: Player, tankName: string)
|
||||||
|
local inv = getInventory(player)
|
||||||
|
if not inv then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if table.find(inv.Tanks, tankName) then
|
||||||
|
return
|
||||||
|
end -- already owned
|
||||||
|
|
||||||
|
table.insert(inv.Tanks, tankName)
|
||||||
|
InventoryService.UnlockSkin(player, tankName, "Default")
|
||||||
|
|
||||||
|
local loadout: DataTypes.Loadout = { Name = "Default", Tank = tankName }
|
||||||
|
InventoryService.CreateLoadout(player, tankName, loadout)
|
||||||
|
inv.CurrentLoadouts[tankName] = loadout
|
||||||
|
|
||||||
|
syncToClient(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryService.UnlockSkin(player: Player, tankName: string, skinName: string)
|
||||||
|
local inv = getInventory(player)
|
||||||
|
if not inv then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not table.find(inv.Tanks, tankName) then
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
return Inventory
|
inv.Skins[tankName] = inv.Skins[tankName] or {}
|
||||||
|
if table.find(inv.Skins[tankName], skinName) then
|
||||||
|
return
|
||||||
|
end -- already owned
|
||||||
|
|
||||||
|
table.insert(inv.Skins[tankName], skinName)
|
||||||
|
syncToClient(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
function InventoryService.GetAllTanks()
|
-- ─────────────────────────────────────────
|
||||||
return Tanks
|
-- Init (called by ModuleLoader)
|
||||||
end
|
-- ─────────────────────────────────────────
|
||||||
|
|
||||||
function InventoryService.GetAllSkins()
|
function InventoryService:Init()
|
||||||
return Skins
|
-- Handle all client requests through one RemoteFunction.
|
||||||
end
|
-- Each action is validated server-side — client input is never trusted.
|
||||||
|
rfn_Inventory.OnServerInvoke = function(player: Player, action: string, ...)
|
||||||
|
|
||||||
function InventoryService.UpdateLoadout(player : Player, tank : string, skin : string)
|
|
||||||
PlayersInventory[player.UserId]["Loadouts"][tank] = skin
|
|
||||||
return PlayersInventory[player.UserId]["Loadouts"][tank]
|
|
||||||
end
|
|
||||||
|
|
||||||
function InventoryService.SelectLoadout(player : Player, loadout : string)
|
|
||||||
PlayersInventory[player.UserId]["SelectedLoadout"] = loadout
|
|
||||||
return PlayersInventory[player.UserId]["SelectedLoadout"]
|
|
||||||
end
|
|
||||||
|
|
||||||
function CheckIfLoadoutExists(player : Player, tank : string)
|
|
||||||
local Loadouts = PlayersInventory[player.UserId].Loadouts
|
|
||||||
if Loadouts[tank] then
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function InventoryService.GetInventory(player : Player)
|
|
||||||
return PlayersInventory[player.UserId]
|
|
||||||
end
|
|
||||||
|
|
||||||
function InventoryService.AllInventories()
|
|
||||||
return PlayersInventory
|
|
||||||
end
|
|
||||||
|
|
||||||
function InventoryService.Init()
|
|
||||||
for _, player in Players:GetPlayers() do
|
|
||||||
createPlayerInventory(player)
|
|
||||||
end
|
|
||||||
Players.PlayerAdded:Connect(function(player)
|
|
||||||
createPlayerInventory(player)
|
|
||||||
end)
|
|
||||||
Players.PlayerRemoving:Connect(function(player)
|
|
||||||
PlayersInventory[player.UserId] = nil
|
|
||||||
end)
|
|
||||||
RemoteFunction.OnServerInvoke = function(player, action, ...)
|
|
||||||
local args = {...}
|
|
||||||
if action == "GetInventory" then
|
if action == "GetInventory" then
|
||||||
return InventoryService.GetInventory(player)
|
return InventoryService.GetInventory(player)
|
||||||
elseif action == "AllInventories" then
|
elseif action == "SelectTank" then
|
||||||
return InventoryService.AllInventories()
|
local ok, err = InventoryService.SelectTank(player, ...)
|
||||||
|
return ok, err
|
||||||
elseif action == "UpdateLoadout" then
|
elseif action == "UpdateLoadout" then
|
||||||
InventoryService.UpdateLoadout(player, args[1], args[2])
|
local ok, err = InventoryService.UpdateLoadout(player, ...)
|
||||||
elseif action == "SelectLoadout" then
|
return ok, err
|
||||||
return InventoryService.SelectLoadout(player, args[1])
|
|
||||||
elseif action == "GetAllTanks" then
|
|
||||||
return InventoryService.GetAllTanks()
|
|
||||||
elseif action == "GetAllSkins" then
|
|
||||||
return InventoryService.GetAllSkins()
|
|
||||||
elseif action == "GetModel" then
|
|
||||||
return InventoryService.GetModel(args[1], args[2])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return false, "Unknown action: " .. tostring(action)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Sync inventory to client once their profile is ready.
|
||||||
|
-- DataManager loads profiles on PlayerAdded, so we wait for it.
|
||||||
|
Players.PlayerAdded:Connect(function(player)
|
||||||
|
local waited = 0
|
||||||
|
while not DataManager.Profiles[player] and waited < 10 do
|
||||||
|
task.wait(0.5)
|
||||||
|
waited += 0.5
|
||||||
|
end
|
||||||
|
|
||||||
|
if DataManager.Profiles[player] then
|
||||||
|
syncToClient(player)
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
return InventoryService
|
return InventoryService
|
||||||
|
|||||||
@ -1,12 +1,19 @@
|
|||||||
|
--!nonstrict
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
|
|
||||||
|
local Inventory: DataTypes.Inventory = {
|
||||||
|
Tanks = { "Tank" }, -- tanks the player owns
|
||||||
|
Skins = { Tank = { "Default" } }, -- skins per tank
|
||||||
|
Loadouts = {} :: { [string]: { [string]: DataTypes.Loadout } }, -- Saved loadouts,
|
||||||
|
CurrentLoadouts = {} :: { [string]: DataTypes.Loadout }, -- Current loadout of tank
|
||||||
|
|
||||||
|
SelectedTank = "Tank",
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Money = 50,
|
Money = 50,
|
||||||
Wins = 0,
|
Wins = 0,
|
||||||
|
|
||||||
UnlockedSkins = {},
|
Inventory = Inventory,
|
||||||
UnlockedTanks = {},
|
|
||||||
UnlockedAccessories = {},
|
|
||||||
|
|
||||||
Loadouts = {},
|
|
||||||
CurrentLoadout = "Default",
|
|
||||||
CurrentTank = "Tank"
|
|
||||||
}
|
}
|
||||||
@ -3,11 +3,11 @@
|
|||||||
local GameObject = require(script.Parent)
|
local GameObject = require(script.Parent)
|
||||||
local InventoryService = require(game:GetService("ServerScriptService").Data.InventoryService)
|
local InventoryService = require(game:GetService("ServerScriptService").Data.InventoryService)
|
||||||
|
|
||||||
local Bot = setmetatable({},GameObject)
|
local Bot = setmetatable({}, GameObject)
|
||||||
Bot.__index = Bot
|
Bot.__index = Bot
|
||||||
|
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local StarterGui = game:GetService("StarterGui")
|
||||||
|
|
||||||
local rAssets = ReplicatedStorage.Assets
|
local rAssets = ReplicatedStorage.Assets
|
||||||
local rHUD = rAssets.HUD
|
local rHUD = rAssets.HUD
|
||||||
@ -18,41 +18,39 @@ local TankFolder = rModels.Tanks
|
|||||||
local rData = ReplicatedStorage.Data
|
local rData = ReplicatedStorage.Data
|
||||||
local BotData = require(rData.BotData)
|
local BotData = require(rData.BotData)
|
||||||
|
|
||||||
|
|
||||||
type self = {
|
type self = {
|
||||||
accuracy : number,
|
accuracy: number,
|
||||||
HUD : typeof(rHUD.HUD_TANK)
|
HUD: typeof(rHUD.HUD_TANK),
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Bot = typeof( setmetatable({} :: self, Bot) ) & GameObject.GameObject
|
export type Bot = typeof(setmetatable({} :: self, Bot)) & GameObject.GameObject
|
||||||
|
|
||||||
local Component = script.Parent.Parent.Component
|
local Component = script.Parent.Parent.Component
|
||||||
local HitboxComponent = require(Component.HitboxComponent)
|
local HitboxComponent = require(Component.HitboxComponent)
|
||||||
local ProjectileComponent = require(Component.ProjectileComponent)
|
local ProjectileComponent = require(Component.ProjectileComponent)
|
||||||
local HealthComponent = require(Component.HealthComponent)
|
local HealthComponent = require(Component.HealthComponent)
|
||||||
|
|
||||||
function Bot.new(player : Player, name, character)
|
function Bot.new(player: Player, name, character)
|
||||||
local self : Bot = setmetatable(GameObject.new(player.UserId,nil,player.UserId) ,Bot)
|
local self: Bot = setmetatable(GameObject.new(player.UserId, nil, player.UserId), Bot)
|
||||||
local Inventory = InventoryService.GetInventory(player)
|
local Inventory = InventoryService.GetInventory(player)
|
||||||
local selectedTank = Inventory["SelectedTank"]
|
local selectedTank = Inventory["SelectedTank"]
|
||||||
local selectedSkin = Inventory["Loadouts"][selectedTank]
|
local selectedSkin = Inventory["Loadouts"][selectedTank]
|
||||||
name = selectedTank or "Tank"
|
name = selectedTank or "Tank"
|
||||||
local skin = selectedSkin or "Default"
|
local skin = selectedSkin or "Default"
|
||||||
local bData : BotData.BotData = BotData[name]
|
local bData: BotData.BotData = BotData[name]
|
||||||
print(name,bData)
|
print(name, bData)
|
||||||
|
|
||||||
print(name)
|
print(name)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.skin = skin
|
self.skin = skin
|
||||||
self.accuracy = bData.accuracy
|
self.accuracy = bData.accuracy
|
||||||
self.weapons = bData.weapons -- { basic = "Missile", special = "ClusterRocket" }
|
self.weapons = bData.weapons -- { basic = "Missile", special = "ClusterRocket" }
|
||||||
|
|
||||||
self:CreateModel()
|
self:CreateModel()
|
||||||
|
|
||||||
local h = HealthComponent.new(self.key,bData.maxHp)
|
local h = HealthComponent.new(self.key, bData.maxHp)
|
||||||
|
|
||||||
|
h.HealthChangedSignal:Connect(function(oldHP, newHP)
|
||||||
h.HealthChangedSignal:Connect(function(oldHP,newHP)
|
|
||||||
local diff = oldHP - newHP
|
local diff = oldHP - newHP
|
||||||
if oldHP > newHP then
|
if oldHP > newHP then
|
||||||
print(self.name .. " took " .. diff .. " damage!")
|
print(self.name .. " took " .. diff .. " damage!")
|
||||||
@ -68,47 +66,40 @@ function Bot.new(player : Player, name, character)
|
|||||||
|
|
||||||
self.Components.Health = h
|
self.Components.Health = h
|
||||||
|
|
||||||
self.Components.Hitbox = HitboxComponent.new(self.key,self.model)
|
self.Components.Hitbox = HitboxComponent.new(self.key, self.model)
|
||||||
|
|
||||||
self.Components.Health:Init()
|
self.Components.Health:Init()
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Bot:CreateModel()
|
function Bot:CreateModel()
|
||||||
print(self.name)
|
print(self.name)
|
||||||
print(TankFolder)
|
print(TankFolder)
|
||||||
local model : Model = TankFolder:FindFirstChild(self.name):FindFirstChild("Base")
|
local model: Model = TankFolder:FindFirstChild(self.name):FindFirstChild("Base")
|
||||||
model = model:Clone()
|
model = model:Clone()
|
||||||
local skin : Model = TankFolder:FindFirstChild(self.name):FindFirstChild(self.skin)
|
local skin: Model = TankFolder:FindFirstChild(self.name):FindFirstChild(self.skin)
|
||||||
skin.Parent = model
|
skin.Parent = model
|
||||||
|
|
||||||
print(self.key)
|
print(self.key)
|
||||||
model.Name = self.key
|
model.Name = self.key
|
||||||
model:SetAttribute("Type",self.name)
|
model:SetAttribute("Type", self.name)
|
||||||
self.model = model
|
self.model = model
|
||||||
self.root = model.PrimaryPart or model.Root
|
self.root = model.PrimaryPart or model.Root
|
||||||
|
|
||||||
|
|
||||||
ReplicatedStorage.Assets.Cooldowns:Clone().Parent = model
|
ReplicatedStorage.Assets.Cooldowns:Clone().Parent = model
|
||||||
|
|
||||||
|
|
||||||
local HUD_TANK = rHUD.HUD_TANK:Clone()
|
local HUD_TANK = rHUD.HUD_TANK:Clone()
|
||||||
HUD_TANK.Parent = model
|
HUD_TANK.Parent = model
|
||||||
self.HUD = HUD_TANK
|
self.HUD = HUD_TANK
|
||||||
|
|
||||||
self:_ResetMass()
|
self:_ResetMass()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bot:DisplayHealth(hp)
|
function Bot:DisplayHealth(hp)
|
||||||
local self = self :: Bot
|
local self = self :: Bot
|
||||||
local Health = self.Components.Health
|
local Health = self.Components.Health
|
||||||
|
|
||||||
|
|
||||||
hp = hp or Health.Health
|
hp = hp or Health.Health
|
||||||
|
|
||||||
local max = Health.MaxHealth
|
local max = Health.MaxHealth
|
||||||
@ -116,7 +107,7 @@ function Bot:DisplayHealth(hp)
|
|||||||
|
|
||||||
local hud = self.HUD
|
local hud = self.HUD
|
||||||
hud.Health.ContainerText.HealthText.Text = hp
|
hud.Health.ContainerText.HealthText.Text = hp
|
||||||
hud.Health.BlackBar.GreenBar.Size = UDim2.new(dif,0,1,0)
|
hud.Health.BlackBar.GreenBar.Size = UDim2.new(dif, 0, 1, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bot:heal(amount)
|
function Bot:heal(amount)
|
||||||
@ -131,7 +122,6 @@ end
|
|||||||
|
|
||||||
function Bot:die()
|
function Bot:die()
|
||||||
self.model:Destroy()
|
self.model:Destroy()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return Bot
|
return Bot
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
local ClientController = {}
|
local ClientController = {}
|
||||||
|
|
||||||
local Players = game:GetService("Players")
|
local Players = game:GetService("Players")
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
|
||||||
local localPlayer = Players.LocalPlayer
|
local localPlayer = Players.LocalPlayer
|
||||||
|
|
||||||
local Data = ReplicatedStorage.Data -- server modules (read-only on client)
|
local Data = ReplicatedStorage.Data -- server modules (read-only on client)
|
||||||
local GameStates = require(Data.GameState)
|
local GameStates = require(Data.GameState)
|
||||||
|
|
||||||
local ClientModules = script.Parent.Modules
|
local ClientModules = script.Parent.Parent.Modules
|
||||||
|
|
||||||
local AimRenderer = require(ClientModules.AimRenderer)
|
local AimRenderer = require(ClientModules.AimRenderer)
|
||||||
local InputHandler = require(ClientModules.InputHandler)
|
local InputHandler = require(ClientModules.InputHandler)
|
||||||
local BotSelectUI = require(ClientModules.BotSelectUI)
|
local BotSelectUI = require(ClientModules.BotSelectUI)
|
||||||
local CameraController = require(ClientModules.CameraController)
|
local CameraController = require(ClientModules.CameraController)
|
||||||
local BotAbilityUI = require(ClientModules.BotAbilityUI)
|
local BotAbilityUI = require(ClientModules.BotAbilityUI)
|
||||||
|
|
||||||
local Remote = ReplicatedStorage.Remote
|
local Remote = ReplicatedStorage.Remote
|
||||||
local rev_SubmitAction = Remote.SubmitAction
|
local rev_SubmitAction = Remote.SubmitAction
|
||||||
local rev_UpdateGameState = Remote.UpdateGameState
|
local rev_UpdateGameState = Remote.UpdateGameState
|
||||||
local rev_HpUpdated = Remote.HpUpdated
|
local rev_HpUpdated = Remote.HpUpdated
|
||||||
local rev_BotDied = Remote.BotDied
|
local rev_BotDied = Remote.BotDied
|
||||||
|
|
||||||
--finish later brochacho chip
|
--finish later brochacho chip
|
||||||
local turns = 1
|
local turns = 1
|
||||||
@ -28,20 +28,16 @@ local turns = 1
|
|||||||
local PLAYING = "PLAYING"
|
local PLAYING = "PLAYING"
|
||||||
|
|
||||||
function ClientController:Init()
|
function ClientController:Init()
|
||||||
|
|
||||||
-- React to server phase changes
|
-- React to server phase changes
|
||||||
rev_UpdateGameState.OnClientEvent:Connect(function(phase)
|
rev_UpdateGameState.OnClientEvent:Connect(function(phase)
|
||||||
shared.Phase = phase
|
shared.Phase = phase
|
||||||
if phase == GameStates.LOBBY then
|
if phase == GameStates.LOBBY then
|
||||||
|
|
||||||
turns = 1
|
turns = 1
|
||||||
CameraController.ResetCamera()
|
CameraController.ResetCamera()
|
||||||
elseif phase == GameStates.GRACE then
|
elseif phase == GameStates.GRACE then
|
||||||
|
|
||||||
CameraController.WideMapView()
|
CameraController.WideMapView()
|
||||||
BotAbilityUI.NewAbilities()
|
BotAbilityUI.NewAbilities()
|
||||||
elseif phase == GameStates.AIMING then
|
elseif phase == GameStates.AIMING then
|
||||||
|
|
||||||
AimRenderer.UnHighlight()
|
AimRenderer.UnHighlight()
|
||||||
|
|
||||||
InputHandler.enable(function(input)
|
InputHandler.enable(function(input)
|
||||||
@ -50,30 +46,21 @@ function ClientController:Init()
|
|||||||
InputHandler.disable()
|
InputHandler.disable()
|
||||||
BotAbilityUI.DisableAll()
|
BotAbilityUI.DisableAll()
|
||||||
AimRenderer.Highlight()
|
AimRenderer.Highlight()
|
||||||
|
end, turns)
|
||||||
end,turns)
|
|
||||||
|
|
||||||
elseif phase == GameStates.RESOLVING then
|
elseif phase == GameStates.RESOLVING then
|
||||||
|
|
||||||
turns += 1
|
turns += 1
|
||||||
BotAbilityUI.HideGUI()
|
BotAbilityUI.HideGUI()
|
||||||
InputHandler.disable()
|
InputHandler.disable()
|
||||||
AimRenderer.hide()
|
AimRenderer.hide()
|
||||||
|
|
||||||
elseif phase == "Results" then
|
elseif phase == "Results" then
|
||||||
if localPlayer:HasTag(PLAYING) then
|
if localPlayer:HasTag(PLAYING) then
|
||||||
BotAbilityUI.HideGUI()
|
BotAbilityUI.HideGUI()
|
||||||
CameraController.ResetCamera()
|
CameraController.ResetCamera()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- TODO: show win screen
|
-- TODO: show win screen
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return ClientController
|
return ClientController
|
||||||
86
src/shared/client/Controllers/GarageController.luau
Normal file
86
src/shared/client/Controllers/GarageController.luau
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local GarageUIHandler = require(ReplicatedStorage.Client.Garage.GarageUIHandler)
|
||||||
|
local InventoryClient = require(ReplicatedStorage.Client.Garage.InventoryClient)
|
||||||
|
local TankShowcase = require(ReplicatedStorage.Client.Garage.TankShowcase)
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
|
local GarageController = {}
|
||||||
|
|
||||||
|
local tabName
|
||||||
|
local items
|
||||||
|
local index
|
||||||
|
|
||||||
|
local garageShown = false
|
||||||
|
|
||||||
|
local AccessorySlotIndex = 1
|
||||||
|
|
||||||
|
local AccessorySlots = {
|
||||||
|
"Head",
|
||||||
|
"Turret",
|
||||||
|
"Back",
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnItemClick(i: ImageButton)
|
||||||
|
local oldIndex = index
|
||||||
|
index = tonumber(i.Name)
|
||||||
|
|
||||||
|
if oldIndex == index then -- same
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local inv = InventoryClient.GetInventory()
|
||||||
|
local itemName = i:GetAttribute("ItemName")
|
||||||
|
|
||||||
|
if tabName == "Tanks" then
|
||||||
|
InventoryClient.SelectTank(itemName)
|
||||||
|
end
|
||||||
|
local currentLoadout = inv.CurrentLoadouts[inv.SelectedTank]
|
||||||
|
|
||||||
|
if tabName == "Skins" then
|
||||||
|
currentLoadout.Skin = i.Name
|
||||||
|
end
|
||||||
|
|
||||||
|
TankShowcase.Showcase(currentLoadout)
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnHandleClicked()
|
||||||
|
garageShown = not garageShown
|
||||||
|
|
||||||
|
if garageShown then
|
||||||
|
GarageController.ShowGarage(true)
|
||||||
|
else
|
||||||
|
GarageController.HideGarage(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnNavigClick(value) end
|
||||||
|
|
||||||
|
function ChangeItem(index)
|
||||||
|
local currentItem = items[index]
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnTabClicked(tab: TextButton)
|
||||||
|
tabName = tab.Name
|
||||||
|
GarageUIHandler.SetActiveTab(tab)
|
||||||
|
items = InventoryClient.GetItemsByTab(tabName)
|
||||||
|
GarageUIHandler.SetItems(items, tabName)
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageController.ShowGarage(anim: boolean?)
|
||||||
|
GarageUIHandler.Show(anim)
|
||||||
|
TankShowcase.Focus()
|
||||||
|
TankShowcase.Showcase({ Tank = "Tank" })
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageController.HideGarage(anim: boolean?)
|
||||||
|
GarageUIHandler.Hide(anim)
|
||||||
|
TankShowcase.UnFocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageController:Init()
|
||||||
|
GarageUIHandler.Events.OnTabClicked:Connect(OnTabClicked)
|
||||||
|
GarageUIHandler.Events.OnHandleClicked:Connect(OnHandleClicked)
|
||||||
|
|
||||||
|
GarageController.HideGarage(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
return GarageController
|
||||||
@ -1,43 +0,0 @@
|
|||||||
local Players = game:GetService("Players")
|
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
||||||
local player = Players.LocalPlayer
|
|
||||||
local Garage = workspace.Garage
|
|
||||||
local TankFolder = ReplicatedStorage:WaitForChild("Assets"):WaitForChild("Models"):WaitForChild("Tanks")
|
|
||||||
|
|
||||||
if not game:GetService("RunService"):IsStudio() then
|
|
||||||
TankFolder:WaitForChild("Tank (Testing)"):Destroy()
|
|
||||||
end
|
|
||||||
|
|
||||||
local SelectedTank = player:WaitForChild("SelectedTank")
|
|
||||||
local SelectedSkin = player:WaitForChild("SelectedSkin")
|
|
||||||
local TankDisplay = Garage:WaitForChild("TankDisplay")
|
|
||||||
|
|
||||||
local garage = {}
|
|
||||||
|
|
||||||
local function updateTank()
|
|
||||||
local tankName = SelectedTank.Value
|
|
||||||
local skinName = SelectedSkin.Value
|
|
||||||
local tankModel = TankFolder:FindFirstChild(tankName)
|
|
||||||
if tankModel then
|
|
||||||
local tankBase = tankModel:FindFirstChild("Base")
|
|
||||||
if tankModel and tankBase then
|
|
||||||
local skin = tankModel:FindFirstChild(skinName) or tankModel:FindFirstChild("Default")
|
|
||||||
if skin then
|
|
||||||
TankDisplay:ClearAllChildren()
|
|
||||||
local Tank = tankBase:Clone()
|
|
||||||
Tank.Parent = TankDisplay
|
|
||||||
skin = skin:Clone()
|
|
||||||
skin.Parent = Tank
|
|
||||||
Tank:PivotTo(TankDisplay.CFrame)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function garage:Init()
|
|
||||||
SelectedTank:GetPropertyChangedSignal("Value"):Connect(updateTank)
|
|
||||||
SelectedSkin:GetPropertyChangedSignal("Value"):Connect(updateTank)
|
|
||||||
updateTank()
|
|
||||||
end
|
|
||||||
|
|
||||||
return garage
|
|
||||||
246
src/shared/client/Garage/GarageUIHandler.luau
Normal file
246
src/shared/client/Garage/GarageUIHandler.luau
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
local Players = game:GetService("Players")
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local StarterGui = game:GetService("StarterGui")
|
||||||
|
local BotData = require(ReplicatedStorage.Data.BotData)
|
||||||
|
local InventoryClient = require(script.Parent.InventoryClient)
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
|
local Signal = require(ReplicatedStorage.Shared.SharedUtils.Signal)
|
||||||
|
local sharedBotUtils = require(ReplicatedStorage.Shared.SharedUtils.sharedBotUtils)
|
||||||
|
local GarageUIHandler = {}
|
||||||
|
|
||||||
|
local localPlayer = Players.LocalPlayer
|
||||||
|
local PlayerGui = localPlayer.PlayerGui
|
||||||
|
|
||||||
|
local GarageGui = PlayerGui:WaitForChild("GarageGui")
|
||||||
|
local WorldOverlay = GarageGui:WaitForChild("WorldOverlay")
|
||||||
|
|
||||||
|
local nav_Left = GarageGui.Navigation.Left
|
||||||
|
local nav_Right = GarageGui.Navigation.Right
|
||||||
|
|
||||||
|
local StatusHUD = GarageGui:WaitForChild("StatusHUD")
|
||||||
|
|
||||||
|
local TopCenter = GarageGui:WaitForChild("TopCenter")
|
||||||
|
local BotName = TopCenter:WaitForChild("BotName")
|
||||||
|
local SkinName = TopCenter:WaitForChild("SkinName")
|
||||||
|
|
||||||
|
local Drawer = GarageGui:WaitForChild("Drawer")
|
||||||
|
|
||||||
|
local SelectedTab = Drawer:WaitForChild("SelectedTab")
|
||||||
|
local Selector = SelectedTab:WaitForChild("Selector")
|
||||||
|
|
||||||
|
local Handle = Drawer:WaitForChild("Handle")
|
||||||
|
|
||||||
|
local Tabs = Drawer:WaitForChild("Tabs")
|
||||||
|
local t_Accessories = Tabs:WaitForChild("Accessories")
|
||||||
|
local t_Skins = Tabs:WaitForChild("Skins")
|
||||||
|
local t_Tanks = Tabs:WaitForChild("Tanks")
|
||||||
|
|
||||||
|
local SafetyDrawer = Drawer:WaitForChild("SafetyDrawer")
|
||||||
|
local ScrollingFrame = SafetyDrawer:WaitForChild("ScollingFrame")
|
||||||
|
|
||||||
|
local InteractionContainer = SafetyDrawer:WaitForChild("InteractionContainer")
|
||||||
|
|
||||||
|
local BuyContainer = InteractionContainer:WaitForChild("BuyContainer")
|
||||||
|
local BuyButton = BuyContainer:WaitForChild("LowerButton")
|
||||||
|
local EquipIndicator = BuyContainer:WaitForChild("Indicator")
|
||||||
|
|
||||||
|
local EquipContainer = InteractionContainer:WaitForChild("EquipContainer")
|
||||||
|
local EquipButton = EquipContainer:WaitForChild("LowerButton")
|
||||||
|
local EquipIndicator = EquipContainer:WaitForChild("Indicator")
|
||||||
|
|
||||||
|
type Inventory = DataTypes.Inventory
|
||||||
|
|
||||||
|
local Models = ReplicatedStorage.Assets.Models
|
||||||
|
local ITEM_TEMPLATE = ReplicatedStorage.Assets.UI:WaitForChild("ITEM_TEMPLATE")
|
||||||
|
|
||||||
|
--t is a tab button :)
|
||||||
|
|
||||||
|
local HANDLE_UP_POSITION = UDim2.new(-0.005, 0, 0.773, 0)
|
||||||
|
local HANDLE_DOWN_POSITION = UDim2.new(-0.005, 0, 0.97, 0)
|
||||||
|
|
||||||
|
local _cachedItemTable = {}
|
||||||
|
|
||||||
|
function _moveTabSelector(t: TextButton)
|
||||||
|
print(t.AbsoluteSize)
|
||||||
|
Selector.Size = UDim2.fromOffset(t.AbsoluteSize.X, t.AbsoluteSize.Y)
|
||||||
|
Selector.Position = UDim2.fromOffset(t.AbsolutePosition.X, t.AbsolutePosition.Y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _cleanUpItems()
|
||||||
|
for _, v in pairs(ScrollingFrame:GetChildren()) do
|
||||||
|
if v:IsA("ImageButton") then
|
||||||
|
v:Destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.clear(_cachedItemTable)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _newTemplate(model: Model)
|
||||||
|
local new = ITEM_TEMPLATE:Clone()
|
||||||
|
model.Parent = new.Viewport
|
||||||
|
new.Viewport.CurrentCamera = Instance.new("Camera", new.Viewport)
|
||||||
|
new.Viewport.CurrentCamera.CFrame = CFrame.new(Vector3.new(0, 2, 12), model:GetPivot().Position)
|
||||||
|
new.Parent = ScrollingFrame
|
||||||
|
|
||||||
|
table.insert(_cachedItemTable, new)
|
||||||
|
new.Name = #_cachedItemTable
|
||||||
|
new:SetAttribute("ItemName", model.Name)
|
||||||
|
return new
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageUIHandler.SetItems(items, currentTab)
|
||||||
|
_cleanUpItems()
|
||||||
|
|
||||||
|
for _, itemModel in items do
|
||||||
|
local ui = _newTemplate(itemModel)
|
||||||
|
|
||||||
|
ui.Activated:Connect(function()
|
||||||
|
GarageUIHandler.Events.OnItemClicked:Fire(itemModel)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
GarageUIHandler.UpdateItemsState(currentTab)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _GetAllItems()
|
||||||
|
return _cachedItemTable
|
||||||
|
end
|
||||||
|
|
||||||
|
function _BrightenItem(item: typeof(ITEM_TEMPLATE))
|
||||||
|
item.BackgroundTransparency = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function _ShadowItem(item: typeof(ITEM_TEMPLATE))
|
||||||
|
item.BackgroundTransparency = 0.5
|
||||||
|
end
|
||||||
|
|
||||||
|
function _PullHandleUp(anim: boolean?)
|
||||||
|
if anim then
|
||||||
|
Drawer:TweenPosition(HANDLE_UP_POSITION, Enum.EasingDirection.In, Enum.EasingStyle.Linear, 0.3)
|
||||||
|
else
|
||||||
|
Drawer.Position = HANDLE_UP_POSITION
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _PullHandleDown(anim: boolean?)
|
||||||
|
if anim then
|
||||||
|
Drawer:TweenPosition(HANDLE_DOWN_POSITION, Enum.EasingDirection.In, Enum.EasingStyle.Linear, 0.3)
|
||||||
|
else
|
||||||
|
Drawer.Position = HANDLE_DOWN_POSITION
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _TransitionBlack(hide: boolean?)
|
||||||
|
if hide then
|
||||||
|
for i = 0, 100, 5 do
|
||||||
|
local v = i / 100
|
||||||
|
WorldOverlay.BackgroundTransparency = v
|
||||||
|
task.wait(0.03)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 100, 0, -5 do
|
||||||
|
local v = i / 100
|
||||||
|
WorldOverlay.BackgroundTransparency = v
|
||||||
|
task.wait(0.03)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _ToggleVisibility(value: boolean?)
|
||||||
|
value = value or false
|
||||||
|
StatusHUD.Visible = value
|
||||||
|
Drawer.Controls.Visible = value
|
||||||
|
GarageGui.AbilityHUD.Visible = value
|
||||||
|
StatusHUD.Visible = value
|
||||||
|
TopCenter.Visible = value
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageUIHandler.Hide(anim: boolean?)
|
||||||
|
_PullHandleDown(anim)
|
||||||
|
if anim then
|
||||||
|
_TransitionBlack(false)
|
||||||
|
end
|
||||||
|
_ToggleVisibility(false)
|
||||||
|
if anim then
|
||||||
|
_TransitionBlack(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageUIHandler.Show(anim: boolean?)
|
||||||
|
_PullHandleUp(anim)
|
||||||
|
if anim then
|
||||||
|
_TransitionBlack(false)
|
||||||
|
end
|
||||||
|
_ToggleVisibility(true)
|
||||||
|
if anim then
|
||||||
|
_TransitionBlack(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageUIHandler.SetActiveTab(t: TextButton)
|
||||||
|
_moveTabSelector(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function GarageUIHandler.UpdateItemsState(tabName)
|
||||||
|
for _, item in pairs(_GetAllItems()) do
|
||||||
|
local itemName = item:GetAttribute("ItemName")
|
||||||
|
local can = true
|
||||||
|
if tabName == "Tanks" then
|
||||||
|
can = InventoryClient.HasTank(itemName)
|
||||||
|
elseif tabName == "Skins" then
|
||||||
|
can = InventoryClient.HasSkin(itemName)
|
||||||
|
end
|
||||||
|
|
||||||
|
if can then
|
||||||
|
_BrightenItem(item)
|
||||||
|
else
|
||||||
|
_ShadowItem(item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
GarageUIHandler.Messages = {
|
||||||
|
CANT_AFFORD = "Not Enough Money",
|
||||||
|
CAN_AFFORD = "BUY",
|
||||||
|
|
||||||
|
CAN_EQUIP = "EQUIP",
|
||||||
|
ALREADY_EQUIPPED = "EQUIPPED",
|
||||||
|
|
||||||
|
ERROR = "Something went wrong",
|
||||||
|
}
|
||||||
|
|
||||||
|
GarageUIHandler.Events = {
|
||||||
|
OnTabClicked = Signal.new(),
|
||||||
|
OnItemClicked = Signal.new(),
|
||||||
|
OnBuyClicked = Signal.new(),
|
||||||
|
OnEquipClicked = Signal.new(),
|
||||||
|
OnNavigClicked = Signal.new(),
|
||||||
|
OnHandleClicked = Signal.new(),
|
||||||
|
}
|
||||||
|
|
||||||
|
function GarageUIHandler:Init()
|
||||||
|
for _, v in pairs(Tabs:GetChildren()) do
|
||||||
|
if not v:IsA("TextButton") then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
v.Activated:Connect(function()
|
||||||
|
_moveTabSelector(v)
|
||||||
|
GarageUIHandler.Events.OnTabClicked:Fire(v)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
nav_Left.Activated:Connect(function()
|
||||||
|
GarageUIHandler.Events.OnNavigClicked:Fire(-1)
|
||||||
|
end)
|
||||||
|
nav_Right.Activated:Connect(function()
|
||||||
|
GarageUIHandler.Events.OnNavigClicked:Fire(1)
|
||||||
|
end)
|
||||||
|
EquipButton.Activated:Connect(function()
|
||||||
|
GarageUIHandler.Events.OnEquipClicked:Fire(EquipButton)
|
||||||
|
end)
|
||||||
|
Handle.Activated:Connect(function()
|
||||||
|
GarageUIHandler.Events.OnHandleClicked:Fire()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return GarageUIHandler
|
||||||
87
src/shared/client/Garage/InventoryClient.luau
Normal file
87
src/shared/client/Garage/InventoryClient.luau
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
|
local sharedBotUtils = require(ReplicatedStorage.Shared.SharedUtils.sharedBotUtils)
|
||||||
|
local InventoryClient = {}
|
||||||
|
|
||||||
|
InventoryClient.Inventory = {}
|
||||||
|
|
||||||
|
local Models = ReplicatedStorage.Assets.Models
|
||||||
|
local Remote = ReplicatedStorage.Remote
|
||||||
|
local rfn_Inventory = Remote.InventoryService
|
||||||
|
|
||||||
|
local _inv = nil
|
||||||
|
|
||||||
|
function InventoryClient.Pull(): DataTypes.Inventory
|
||||||
|
local oldTank = _inv and _inv.SelectedTank
|
||||||
|
|
||||||
|
local new_inv = rfn_Inventory:InvokeServer("GetInventory")
|
||||||
|
|
||||||
|
if not new_inv then
|
||||||
|
return _inv
|
||||||
|
end
|
||||||
|
|
||||||
|
if oldTank then
|
||||||
|
new_inv.SelectedTank = oldTank
|
||||||
|
end
|
||||||
|
|
||||||
|
_inv = new_inv
|
||||||
|
return _inv
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryClient.GetItemsByTab(tabName)
|
||||||
|
local inv = InventoryClient.GetInventory()
|
||||||
|
|
||||||
|
local items = {}
|
||||||
|
|
||||||
|
if tabName == "Tanks" then
|
||||||
|
for _, v in pairs(Models.Tanks:GetChildren()) do
|
||||||
|
local currentTankName = v.Name
|
||||||
|
local currentLoadout = inv.CurrentLoadouts[currentTankName]
|
||||||
|
|
||||||
|
local newModel = sharedBotUtils.CreateBot(currentLoadout, currentTankName)
|
||||||
|
table.insert(items, newModel)
|
||||||
|
end
|
||||||
|
elseif tabName == "Skins" then
|
||||||
|
local tankSelected = InventoryClient.GetTankSelected()
|
||||||
|
local currentTankFolder = Models.Tanks:FindFirstChild(tankSelected)
|
||||||
|
|
||||||
|
for _, v in pairs(currentTankFolder.Skins:GetChildren()) do
|
||||||
|
local currentLoadout = {
|
||||||
|
Skin = v.Name,
|
||||||
|
Tank = tankSelected,
|
||||||
|
}
|
||||||
|
|
||||||
|
local newModel = sharedBotUtils.CreateBot(currentLoadout, tankSelected)
|
||||||
|
table.insert(items, newModel)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryClient.GetTankSelected()
|
||||||
|
return InventoryClient.GetInventory().SelectedTank
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryClient.SelectTank(tank)
|
||||||
|
local inv = InventoryClient.GetInventory()
|
||||||
|
inv.SelectedTank = tank
|
||||||
|
inv.CurrentLoadouts[tank].Tank = tank
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryClient.HasTank(tank)
|
||||||
|
return table.find(InventoryClient.GetInventory().Tanks, tank)
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryClient.HasSkin(skin)
|
||||||
|
local tank = InventoryClient.GetTankSelected()
|
||||||
|
return table.find(InventoryClient.GetInventory().Skins[tank], skin)
|
||||||
|
end
|
||||||
|
|
||||||
|
function InventoryClient.GetInventory(): DataTypes.Inventory
|
||||||
|
if not _inv then
|
||||||
|
return InventoryClient.Pull()
|
||||||
|
end
|
||||||
|
return _inv
|
||||||
|
end
|
||||||
|
|
||||||
|
return InventoryClient
|
||||||
68
src/shared/client/Garage/TankShowcase.luau
Normal file
68
src/shared/client/Garage/TankShowcase.luau
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
local Players = game:GetService("Players")
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
|
local sharedBotUtils = require(ReplicatedStorage.Shared.SharedUtils.sharedBotUtils)
|
||||||
|
|
||||||
|
local TankShowcase = {}
|
||||||
|
|
||||||
|
local GarageFolder = workspace.Garage
|
||||||
|
local TankDisplay = GarageFolder:WaitForChild("TankDisplay")
|
||||||
|
|
||||||
|
local cCamera = workspace.CurrentCamera
|
||||||
|
|
||||||
|
local rotOffset = CFrame.Angles(0, 0, 0)
|
||||||
|
local currentTank
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Anim
|
||||||
|
2:From right to center
|
||||||
|
1:From left to center
|
||||||
|
0:No Anim
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
function _cleanupTank()
|
||||||
|
if currentTank then
|
||||||
|
currentTank:Destroy()
|
||||||
|
currentTank = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _resetRot()
|
||||||
|
rotOffset = CFrame.Angles(0, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TankShowcase.Focus()
|
||||||
|
cCamera.CameraType = Enum.CameraType.Scriptable
|
||||||
|
local position = TankDisplay.Position + TankDisplay.CFrame:VectorToWorldSpace(Vector3.new(0, 0, 10))
|
||||||
|
local newCFrame = CFrame.lookAt(position, TankDisplay.Position)
|
||||||
|
cCamera.CFrame = newCFrame
|
||||||
|
end
|
||||||
|
|
||||||
|
function TankShowcase.UnFocus()
|
||||||
|
cCamera.CameraType = Enum.CameraType.Custom
|
||||||
|
end
|
||||||
|
|
||||||
|
function TankShowcase.Showcase(loadout: DataTypes.Loadout)
|
||||||
|
_cleanupTank()
|
||||||
|
local new = sharedBotUtils.CreateBot(loadout)
|
||||||
|
print(new)
|
||||||
|
new:PivotTo(TankDisplay.CFrame)
|
||||||
|
_resetRot()
|
||||||
|
currentTank = new
|
||||||
|
currentTank.Parent = workspace
|
||||||
|
end
|
||||||
|
|
||||||
|
function TankShowcase.Update(dt)
|
||||||
|
if currentTank then
|
||||||
|
rotOffset = rotOffset * CFrame.Angles(0, math.rad(dt), 0)
|
||||||
|
currentTank:PivotTo(CFrame.new(currentTank:GetPivot().Position) * rotOffset)
|
||||||
|
else
|
||||||
|
_resetRot()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TankShowcase:Init() end
|
||||||
|
|
||||||
|
return TankShowcase
|
||||||
@ -1,22 +0,0 @@
|
|||||||
local GarageUIController = {}
|
|
||||||
|
|
||||||
local localPlayer = game.Players.LocalPlayer
|
|
||||||
|
|
||||||
local PlayerGui = localPlayer.PlayerGui
|
|
||||||
local GarageGui = PlayerGui:WaitForChild("GarageGui")
|
|
||||||
|
|
||||||
function GarageUIController.OpenGUI()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function GarageUIController.CloseGUI()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function GarageUIController:Init()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return GarageUIController
|
|
||||||
@ -1,22 +1,34 @@
|
|||||||
|
local ServerScriptService = game:GetService("ServerScriptService")
|
||||||
export type FireData = {
|
export type FireData = {
|
||||||
weapon : string,
|
weapon: string,
|
||||||
angle : number,
|
angle: number,
|
||||||
power : number,
|
power: number,
|
||||||
origin : Vector3,
|
origin: Vector3,
|
||||||
|
|
||||||
specialArgs : {any}
|
specialArgs: { any },
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VoteOptionData = {
|
export type VoteOptionData = {
|
||||||
Name : string,
|
Name: string,
|
||||||
DisplayName : string,
|
DisplayName: string,
|
||||||
DisplayImage : string
|
DisplayImage: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Loadout = {
|
export type Loadout = {
|
||||||
Skin : string,
|
Tank: string,
|
||||||
HeadAccessory : string?,
|
Skin: string?,
|
||||||
|
HeadAccessory: string?,
|
||||||
|
Name: string?,
|
||||||
|
Locked: boolean?, -- can be edited
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Inventory = {
|
||||||
|
Tanks: { string }, -- tanks the player owns
|
||||||
|
Skins: { [string]: { string } }, -- skins per tank
|
||||||
|
Loadouts: { [string]: { [string]: Loadout } },
|
||||||
|
CurrentLoadouts: { [string]: Loadout }, -- Current loadout of tank
|
||||||
|
|
||||||
|
SelectedTank: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
0
src/shared/data/SkinData.luau
Normal file
0
src/shared/data/SkinData.luau
Normal file
@ -1,161 +0,0 @@
|
|||||||
--!strict
|
|
||||||
-- Partial types for Promise
|
|
||||||
|
|
||||||
local Packages = script.Parent.Packages
|
|
||||||
local Promise: any = if Packages:FindFirstChild("Promise") then require(Packages.Promise) else nil
|
|
||||||
|
|
||||||
export type Status = "Started" | "Resolved" | "Rejected" | "Cancelled"
|
|
||||||
export type ErrorKind = "ExecutionError" | "AlreadyCancelled" | "NotResolvedInTime" | "TimedOut"
|
|
||||||
|
|
||||||
type ErrorStaticAndShared = {
|
|
||||||
Kind: {
|
|
||||||
ExecutionError: "ExecutionError",
|
|
||||||
AlreadyCancelled: "AlreadyCancelled",
|
|
||||||
NotResolvedInTime: "NotResolvedInTime",
|
|
||||||
TimedOut: "TimedOut",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
type ErrorOptions = {
|
|
||||||
error: string,
|
|
||||||
trace: string?,
|
|
||||||
context: string?,
|
|
||||||
kind: ErrorKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Error = typeof(setmetatable(
|
|
||||||
{} :: ErrorStaticAndShared & {
|
|
||||||
error: string,
|
|
||||||
trace: string?,
|
|
||||||
context: string?,
|
|
||||||
kind: ErrorKind,
|
|
||||||
parent: Error?,
|
|
||||||
createdTick: number,
|
|
||||||
createdTrace: string,
|
|
||||||
|
|
||||||
extend: (self: Error, options: ErrorOptions?) -> Error,
|
|
||||||
getErrorChain: (self: Error) -> {Error},
|
|
||||||
},
|
|
||||||
{} :: {__tostring: (self: Error) -> string}
|
|
||||||
))
|
|
||||||
type ErrorStatic = ErrorStaticAndShared & {
|
|
||||||
new: (options: ErrorOptions?, parent: Error?) -> Error,
|
|
||||||
is: (anything: any) -> boolean,
|
|
||||||
isKind: (anything: any, kind: ErrorKind) -> boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Promise = {
|
|
||||||
andThen: (
|
|
||||||
self: Promise,
|
|
||||||
successHandler: (...any) -> ...any,
|
|
||||||
failureHandler: ((...any) -> ...any)?
|
|
||||||
) -> Promise,
|
|
||||||
andThenCall: <TArgs...>(self: Promise, callback: (TArgs...) -> ...any, TArgs...) -> any,
|
|
||||||
andThenReturn: (self: Promise, ...any) -> Promise,
|
|
||||||
|
|
||||||
await: (self: Promise) -> (boolean, ...any),
|
|
||||||
awaitStatus: (self: Promise) -> (Status, ...any),
|
|
||||||
|
|
||||||
cancel: (self: Promise) -> (),
|
|
||||||
catch: (self: Promise, failureHandler: (...any) -> ...any) -> Promise,
|
|
||||||
expect: (self: Promise) -> ...any,
|
|
||||||
|
|
||||||
finally: (self: Promise, finallyHandler: (status: Status) -> ...any) -> Promise,
|
|
||||||
finallyCall: <TArgs...>(self: Promise, callback: (TArgs...) -> ...any, TArgs...) -> Promise,
|
|
||||||
finallyReturn: (self: Promise, ...any) -> Promise,
|
|
||||||
|
|
||||||
getStatus: (self: Promise) -> Status,
|
|
||||||
now: (self: Promise, rejectionValue: any?) -> Promise,
|
|
||||||
tap: (self: Promise, tapHandler: (...any) -> ...any) -> Promise,
|
|
||||||
timeout: (self: Promise, seconds: number, rejectionValue: any?) -> Promise,
|
|
||||||
}
|
|
||||||
export type TypedPromise<T...> = {
|
|
||||||
andThen: (self: Promise, successHandler: (T...) -> ...any, failureHandler: ((...any) -> ...any)?) -> Promise,
|
|
||||||
andThenCall: <TArgs...>(self: Promise, callback: (TArgs...) -> ...any, TArgs...) -> Promise,
|
|
||||||
andThenReturn: (self: Promise, ...any) -> Promise,
|
|
||||||
|
|
||||||
await: (self: Promise) -> (boolean, T...),
|
|
||||||
awaitStatus: (self: Promise) -> (Status, T...),
|
|
||||||
|
|
||||||
cancel: (self: Promise) -> (),
|
|
||||||
catch: (self: Promise, failureHandler: (...any) -> ...any) -> Promise,
|
|
||||||
expect: (self: Promise) -> T...,
|
|
||||||
|
|
||||||
finally: (self: Promise, finallyHandler: (status: Status) -> ...any) -> Promise,
|
|
||||||
finallyCall: <TArgs...>(self: Promise, callback: (TArgs...) -> ...any, TArgs...) -> Promise,
|
|
||||||
finallyReturn: (self: Promise, ...any) -> Promise,
|
|
||||||
|
|
||||||
getStatus: (self: Promise) -> Status,
|
|
||||||
now: (self: Promise, rejectionValue: any?) -> Promise,
|
|
||||||
tap: (self: Promise, tapHandler: (T...) -> ...any) -> Promise,
|
|
||||||
timeout: (self: Promise, seconds: number, rejectionValue: any?) -> TypedPromise<T...>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Signal<T...> = {
|
|
||||||
Connect: (self: Signal<T...>, callback: (T...) -> ...any) -> SignalConnection,
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignalConnection = {
|
|
||||||
Disconnect: (self: SignalConnection) -> ...any,
|
|
||||||
[any]: any,
|
|
||||||
}
|
|
||||||
export type PromiseStatic = {
|
|
||||||
Error: ErrorStatic,
|
|
||||||
Status: {
|
|
||||||
Started: "Started",
|
|
||||||
Resolved: "Resolved",
|
|
||||||
Rejected: "Rejected",
|
|
||||||
Cancelled: "Cancelled",
|
|
||||||
},
|
|
||||||
|
|
||||||
all: <T>(promises: {TypedPromise<T>}) -> TypedPromise<{T}>,
|
|
||||||
allSettled: <T>(promise: {TypedPromise<T>}) -> TypedPromise<{Status}>,
|
|
||||||
any: <T>(promise: {TypedPromise<T>}) -> TypedPromise<T>,
|
|
||||||
defer: <TReturn...>(
|
|
||||||
executor: (
|
|
||||||
resolve: (TReturn...) -> (),
|
|
||||||
reject: (...any) -> (),
|
|
||||||
onCancel: (abortHandler: (() -> ())?) -> boolean
|
|
||||||
) -> ()
|
|
||||||
) -> TypedPromise<TReturn...>,
|
|
||||||
delay: (seconds: number) -> TypedPromise<number>,
|
|
||||||
each: <T, TReturn>(
|
|
||||||
list: {T | TypedPromise<T>},
|
|
||||||
predicate: (value: T, index: number) -> TReturn | TypedPromise<TReturn>
|
|
||||||
) -> TypedPromise<{TReturn}>,
|
|
||||||
fold: <T, TReturn>(
|
|
||||||
list: {T | TypedPromise<T>},
|
|
||||||
reducer: (accumulator: TReturn, value: T, index: number) -> TReturn | TypedPromise<TReturn>
|
|
||||||
) -> TypedPromise<TReturn>,
|
|
||||||
fromEvent: <TReturn...>(
|
|
||||||
event: Signal<TReturn...>,
|
|
||||||
predicate: ((TReturn...) -> boolean)?
|
|
||||||
) -> TypedPromise<TReturn...>,
|
|
||||||
is: (object: any) -> boolean,
|
|
||||||
new: <TReturn...>(
|
|
||||||
executor: (
|
|
||||||
resolve: (TReturn...) -> (),
|
|
||||||
reject: (...any) -> (),
|
|
||||||
onCancel: (abortHandler: (() -> ())?) -> boolean
|
|
||||||
) -> ()
|
|
||||||
) -> TypedPromise<TReturn...>,
|
|
||||||
onUnhandledRejection: (callback: (promise: TypedPromise<any>, ...any) -> ()) -> () -> (),
|
|
||||||
promisify: <TArgs..., TReturn...>(callback: (TArgs...) -> TReturn...) -> (TArgs...) -> TypedPromise<TReturn...>,
|
|
||||||
race: <T>(promises: {TypedPromise<T>}) -> TypedPromise<T>,
|
|
||||||
reject: (...any) -> TypedPromise<...any>,
|
|
||||||
resolve: <TReturn...>(TReturn...) -> TypedPromise<TReturn...>,
|
|
||||||
retry: <TArgs..., TReturn...>(
|
|
||||||
callback: (TArgs...) -> TypedPromise<TReturn...>,
|
|
||||||
times: number,
|
|
||||||
TArgs...
|
|
||||||
) -> TypedPromise<TReturn...>,
|
|
||||||
retryWithDelay: <TArgs..., TReturn...>(
|
|
||||||
callback: (TArgs...) -> TypedPromise<TReturn...>,
|
|
||||||
times: number,
|
|
||||||
seconds: number,
|
|
||||||
TArgs...
|
|
||||||
) -> TypedPromise<TReturn...>,
|
|
||||||
some: <T>(promise: {TypedPromise<T>}, count: number) -> TypedPromise<{T}>,
|
|
||||||
try: <TArgs..., TReturn...>(callback: (TArgs...) -> TReturn..., TArgs...) -> TypedPromise<TReturn...>,
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise :: PromiseStatic?
|
|
||||||
@ -1,14 +1,19 @@
|
|||||||
local sharedBotUtils = {}
|
local sharedBotUtils = {}
|
||||||
|
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local Assets = ReplicatedStorage.Assets
|
||||||
|
local Models = Assets.Models
|
||||||
|
local TankFolder = Models.Tanks :: Folder
|
||||||
|
|
||||||
local rData = ReplicatedStorage.Data
|
local rData = ReplicatedStorage.Data
|
||||||
|
local DataTypes = require(ReplicatedStorage.Data.DataTypes)
|
||||||
local BotData = require(rData.BotData)
|
local BotData = require(rData.BotData)
|
||||||
local GameState = require(rData.GameState)
|
local GameState = require(rData.GameState)
|
||||||
local WeaponData = require(rData.WeaponData)
|
local WeaponData = require(rData.WeaponData)
|
||||||
|
|
||||||
local sUtils = ReplicatedStorage.Shared.SharedUtils
|
local sUtils = ReplicatedStorage.Shared.SharedUtils
|
||||||
local TwoDimensionUtils = require(sUtils.TwoDimensionUtils)
|
local TwoDimensionUtils = require(sUtils.TwoDimensionUtils)
|
||||||
|
local WeldModule = require(script.Parent.WeldModule)
|
||||||
|
|
||||||
local wBots = workspace.Bots
|
local wBots = workspace.Bots
|
||||||
|
|
||||||
@ -19,32 +24,97 @@ local NO_COOLDOWN = {
|
|||||||
|
|
||||||
local COOLDOWN_ABILITY = {
|
local COOLDOWN_ABILITY = {
|
||||||
NormalAbility = 2,
|
NormalAbility = 2,
|
||||||
SpecialAbility = 3
|
SpecialAbility = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
function sharedBotUtils.GetBotData(UserId : number) : BotData.BotData
|
--Not cloned
|
||||||
|
function sharedBotUtils.GetTankBase(name): Model
|
||||||
|
name = name or "Tank"
|
||||||
|
|
||||||
|
local currentFolder = TankFolder:FindFirstChild(name)
|
||||||
|
|
||||||
|
if not currentFolder then
|
||||||
|
currentFolder = TankFolder.Tank
|
||||||
|
end
|
||||||
|
|
||||||
|
local base = currentFolder:FindFirstChild("Base")
|
||||||
|
if not base then
|
||||||
|
base = currentFolder.Base
|
||||||
|
end
|
||||||
|
|
||||||
|
return base
|
||||||
|
end
|
||||||
|
--Not cloned
|
||||||
|
function sharedBotUtils.GetTankSkin(name, skinName): Model
|
||||||
|
name = name or "Tank"
|
||||||
|
|
||||||
|
local currentFolder = TankFolder:FindFirstChild(name)
|
||||||
|
if not currentFolder then
|
||||||
|
currentFolder = TankFolder.Tank
|
||||||
|
end
|
||||||
|
|
||||||
|
skinName = skinName or "Default"
|
||||||
|
|
||||||
|
local skin = currentFolder.Skins:FindFirstChild(name)
|
||||||
|
if not skin then
|
||||||
|
skin = currentFolder.Skins.Default
|
||||||
|
end
|
||||||
|
|
||||||
|
return skin
|
||||||
|
end
|
||||||
|
|
||||||
|
function sharedBotUtils.CreateBot(loadout: DataTypes.Loadout, tankName: string?)
|
||||||
|
if not loadout then
|
||||||
|
loadout = { Name = "Whatever", Tank = "Tank" }
|
||||||
|
end
|
||||||
|
if not tankName then
|
||||||
|
tankName = loadout.Tank
|
||||||
|
end
|
||||||
|
|
||||||
|
local base = sharedBotUtils.GetTankBase(tankName):Clone()
|
||||||
|
local skin = sharedBotUtils.GetTankSkin(tankName, loadout.Skin):Clone()
|
||||||
|
|
||||||
|
skin.Name = "Skin"
|
||||||
|
base.Name = "Base"
|
||||||
|
|
||||||
|
local newTank = Instance.new("Model")
|
||||||
|
skin.Parent = newTank
|
||||||
|
base.Parent = newTank
|
||||||
|
newTank.PrimaryPart = base.PrimaryPart
|
||||||
|
|
||||||
|
WeldModule.UnWeldModel(newTank)
|
||||||
|
WeldModule.WeldModel(newTank)
|
||||||
|
|
||||||
|
return newTank
|
||||||
|
end
|
||||||
|
|
||||||
|
function sharedBotUtils.GetBotData(UserId: number): BotData.BotData
|
||||||
local model = sharedBotUtils.FindBotModel(UserId)
|
local model = sharedBotUtils.FindBotModel(UserId)
|
||||||
return BotData[model:GetAttribute("Type")]
|
return BotData[model:GetAttribute("Type")]
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.GetWeaponName(UserId : number,weaponType : string)
|
function sharedBotUtils.GetWeaponName(UserId: number, weaponType: string)
|
||||||
local bData = sharedBotUtils.GetBotData(UserId)
|
local bData = sharedBotUtils.GetBotData(UserId)
|
||||||
local name = bData.weapons[weaponType] or weaponType
|
local name = bData.weapons[weaponType] or weaponType
|
||||||
|
|
||||||
return name
|
return name
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.GetTurret(UserId : number) : Model
|
function sharedBotUtils.GetTurret(UserId: number): Model
|
||||||
local model = sharedBotUtils.FindBotModel(UserId)
|
local model = sharedBotUtils.FindBotModel(UserId)
|
||||||
return model.RotatePart
|
return model.RotatePart
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.RotateTurret(UserId : number,launchDirection)
|
function sharedBotUtils.RotateTurret(UserId: number, launchDirection)
|
||||||
local turret = sharedBotUtils.GetTurret(UserId)
|
local turret = sharedBotUtils.GetTurret(UserId)
|
||||||
if not turret then return end
|
if not turret then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local weld = turret.PrimaryPart:FindFirstChildOfClass("Weld")
|
local weld = turret.PrimaryPart:FindFirstChildOfClass("Weld")
|
||||||
if not weld then return end
|
if not weld then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local base = weld.Part0
|
local base = weld.Part0
|
||||||
local turretPart = weld.Part1
|
local turretPart = weld.Part1
|
||||||
@ -57,7 +127,7 @@ function sharedBotUtils.RotateTurret(UserId : number,launchDirection)
|
|||||||
weld.C0 = base.CFrame:Inverse() * worldCF
|
weld.C0 = base.CFrame:Inverse() * worldCF
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.GetWeaponsData(UserId : number) : {[string] : WeaponData.WeaponData}
|
function sharedBotUtils.GetWeaponsData(UserId: number): { [string]: WeaponData.WeaponData }
|
||||||
local tbl = {}
|
local tbl = {}
|
||||||
|
|
||||||
local bData = sharedBotUtils.GetBotData(UserId)
|
local bData = sharedBotUtils.GetBotData(UserId)
|
||||||
@ -65,21 +135,21 @@ function sharedBotUtils.GetWeaponsData(UserId : number) : {[string] : WeaponData
|
|||||||
tbl.Move = WeaponData.Move
|
tbl.Move = WeaponData.Move
|
||||||
tbl.Missile = WeaponData.Missile
|
tbl.Missile = WeaponData.Missile
|
||||||
|
|
||||||
for weaponType,weaponName in pairs(bData.weapons) do
|
for weaponType, weaponName in pairs(bData.weapons) do
|
||||||
local wData = WeaponData[weaponName]
|
local wData = WeaponData[weaponName]
|
||||||
tbl[weaponType] = wData
|
tbl[weaponType] = wData
|
||||||
end
|
end
|
||||||
return tbl
|
return tbl
|
||||||
end
|
end
|
||||||
function sharedBotUtils.GetBotPosition(UserId : number)
|
function sharedBotUtils.GetBotPosition(UserId: number)
|
||||||
local model = sharedBotUtils.FindBotModel(UserId)
|
local model = sharedBotUtils.FindBotModel(UserId)
|
||||||
return model.PrimaryPart.Position
|
return model.PrimaryPart.Position
|
||||||
end
|
end
|
||||||
function sharedBotUtils.CanUseAbility(UserId : number, abilityType : string)
|
function sharedBotUtils.CanUseAbility(UserId: number, abilityType: string)
|
||||||
if true then
|
if true then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local isInCooldown = sharedBotUtils.AbilityInCooldown(UserId,abilityType)
|
local isInCooldown = sharedBotUtils.AbilityInCooldown(UserId, abilityType)
|
||||||
if isInCooldown then
|
if isInCooldown then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -91,21 +161,21 @@ function sharedBotUtils.CanUseAbility(UserId : number, abilityType : string)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.GetCooldowns(UserId : number) : Folder
|
function sharedBotUtils.GetCooldowns(UserId: number): Folder
|
||||||
local model = sharedBotUtils.FindBotModel(UserId)
|
local model = sharedBotUtils.FindBotModel(UserId)
|
||||||
|
|
||||||
return model.Cooldowns
|
return model.Cooldowns
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.AbilityInCooldown(UserId,ability : string)
|
function sharedBotUtils.AbilityInCooldown(UserId, ability: string)
|
||||||
if NO_COOLDOWN[ability] then
|
if NO_COOLDOWN[ability] then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local cooldown = sharedBotUtils.GetCooldowns(UserId)
|
local cooldown = sharedBotUtils.GetCooldowns(UserId)
|
||||||
local cAbil : IntValue = cooldown:FindFirstChild(ability)
|
local cAbil: IntValue = cooldown:FindFirstChild(ability)
|
||||||
if not cAbil then
|
if not cAbil then
|
||||||
warn("Ability name " .. ability .." doesnt match with any of the cooldown values, what the hell did you do?")
|
warn("Ability name " .. ability .. " doesnt match with any of the cooldown values, what the hell did you do?")
|
||||||
print(cooldown)
|
print(cooldown)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -113,13 +183,13 @@ function sharedBotUtils.AbilityInCooldown(UserId,ability : string)
|
|||||||
return COOLDOWN_ABILITY[ability] ~= cAbil.Value
|
return COOLDOWN_ABILITY[ability] ~= cAbil.Value
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.FindBotModel(UserId : number) : Model
|
function sharedBotUtils.FindBotModel(UserId: number): Model
|
||||||
local b = wBots:WaitForChild(tostring(UserId))
|
local b = wBots:WaitForChild(tostring(UserId))
|
||||||
|
|
||||||
return b
|
return b
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.GetShootPos(UserId : number)
|
function sharedBotUtils.GetShootPos(UserId: number)
|
||||||
local turret = sharedBotUtils.GetTurret(UserId)
|
local turret = sharedBotUtils.GetTurret(UserId)
|
||||||
if not turret then
|
if not turret then
|
||||||
warn("no turret model >:(")
|
warn("no turret model >:(")
|
||||||
@ -134,17 +204,19 @@ function sharedBotUtils.GetShootPos(UserId : number)
|
|||||||
return Shoot.PrimaryPart.Position
|
return Shoot.PrimaryPart.Position
|
||||||
end
|
end
|
||||||
|
|
||||||
function sharedBotUtils.GetBotRoot(UserId : number) : Part
|
function sharedBotUtils.GetBotRoot(UserId: number): Part
|
||||||
local b = sharedBotUtils.FindBotModel(UserId)
|
local b = sharedBotUtils.FindBotModel(UserId)
|
||||||
return b.PrimaryPart
|
return b.PrimaryPart
|
||||||
end
|
end
|
||||||
function sharedBotUtils.IsObjectOnFloor(model) : boolean
|
function sharedBotUtils.IsObjectOnFloor(model): boolean
|
||||||
local root = model.PrimaryPart
|
local root = model.PrimaryPart
|
||||||
if not root then return false end
|
if not root then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- Get the model size (assumes the root's parent is the full model)
|
-- Get the model size (assumes the root's parent is the full model)
|
||||||
local model = root.Parent
|
local model = root.Parent
|
||||||
local size, cf = model:GetBoundingBox() -- size: Vector3, cf: CFrame of bounding box
|
local size, cf = model:GetBoundingBox() -- size: Vector3, cf: CFrame of bounding box
|
||||||
|
|
||||||
local origin = root.Position
|
local origin = root.Position
|
||||||
-- Raycast downward relative to half the model height + small buffer
|
-- Raycast downward relative to half the model height + small buffer
|
||||||
@ -152,7 +224,7 @@ function sharedBotUtils.IsObjectOnFloor(model) : boolean
|
|||||||
|
|
||||||
local params = RaycastParams.new()
|
local params = RaycastParams.new()
|
||||||
params.FilterType = Enum.RaycastFilterType.Exclude
|
params.FilterType = Enum.RaycastFilterType.Exclude
|
||||||
params.FilterDescendantsInstances = {model}
|
params.FilterDescendantsInstances = { model }
|
||||||
|
|
||||||
local result = workspace:Raycast(origin, direction, params)
|
local result = workspace:Raycast(origin, direction, params)
|
||||||
if not result then
|
if not result then
|
||||||
@ -166,7 +238,7 @@ function sharedBotUtils.IsObjectOnFloor(model) : boolean
|
|||||||
-- must be close to ground and not moving vertically
|
-- must be close to ground and not moving vertically
|
||||||
return distance <= (size.Y / 2 + 0.5) and math.abs(velY) < 1
|
return distance <= (size.Y / 2 + 0.5) and math.abs(velY) < 1
|
||||||
end
|
end
|
||||||
function sharedBotUtils.GetBotVelocity(UserId : number)
|
function sharedBotUtils.GetBotVelocity(UserId: number)
|
||||||
local root = sharedBotUtils.GetBotRoot(UserId)
|
local root = sharedBotUtils.GetBotRoot(UserId)
|
||||||
return root.AssemblyLinearVelocity
|
return root.AssemblyLinearVelocity
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user