mirror of
https://github.com/unixtensor/Roblox-Elevator-Game.git
synced 2025-12-14 14:51:55 +00:00
work on rope math
This commit is contained in:
@@ -105,7 +105,7 @@ HumanoidSettings:SetWalkSpeed()
|
|||||||
HumanoidSettings:SetJumpHeight()
|
HumanoidSettings:SetJumpHeight()
|
||||||
HRPSettings:DisableRobloxSounds()
|
HRPSettings:DisableRobloxSounds()
|
||||||
CameraConsturctor:EnableBobbing()
|
CameraConsturctor:EnableBobbing()
|
||||||
SpineMovement:Enable()
|
--SpineMovement:Enable()
|
||||||
|
|
||||||
ClientCharacterBinds()
|
ClientCharacterBinds()
|
||||||
Crosshair3DVelocity_Effect()
|
Crosshair3DVelocity_Effect()
|
||||||
|
|||||||
@@ -10,28 +10,20 @@ local TagsModule = require(RS:WaitForChild("Tags"))
|
|||||||
local Enums = require(Elevators:WaitForChild("Enums"))
|
local Enums = require(Elevators:WaitForChild("Enums"))
|
||||||
|
|
||||||
type Tags = TagsModule.ExportedTags
|
type Tags = TagsModule.ExportedTags
|
||||||
|
type HumanoidRootPart = BasePart
|
||||||
|
type PromptCallback = (Player: Player) -> ()
|
||||||
|
|
||||||
type GetButtons = {[string]: Instance}
|
type GetButtons = {[string]: Instance}
|
||||||
type ButtonProperties = {
|
|
||||||
Inst: Instance?,
|
|
||||||
Prompt: ProximityPrompt?
|
|
||||||
}
|
|
||||||
type ButtonsTree = {
|
|
||||||
Landing: ButtonProperties,
|
|
||||||
Car: ButtonProperties,
|
|
||||||
Special: ButtonProperties,
|
|
||||||
Relays: ButtonProperties,
|
|
||||||
Unknown: ButtonProperties
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor))
|
type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor))
|
||||||
type Impl_Constructor = {
|
type Impl_Constructor = {
|
||||||
__index: Impl_Constructor,
|
__index: Impl_Constructor,
|
||||||
constructor: Constructor_Fun,
|
constructor: Constructor_Fun,
|
||||||
--Class functions
|
--Class functions
|
||||||
|
DecodeCarTag: (self: ClassConstructor, FloorTag: string) -> number?,
|
||||||
Get: (self: ClassConstructor) -> GetButtons,
|
Get: (self: ClassConstructor) -> GetButtons,
|
||||||
CreatePromptButtons: (self: ClassConstructor) -> ButtonsTree,
|
CreatePromptButtons: (self: ClassConstructor) -> ButtonsTree,
|
||||||
HookPromptButtonsGroup: (self: ClassConstructor) -> ()
|
HookPromptButtonsGroup: (self: ClassConstructor, Prompt: ProximityPrompt, Inst: BasePart, PromptCallback: PromptCallback) -> ()
|
||||||
} & Impl_Static_Props
|
} & Impl_Static_Props
|
||||||
|
|
||||||
type Impl_Static_Props = {
|
type Impl_Static_Props = {
|
||||||
@@ -45,6 +37,19 @@ type Constructor_Return_Props = {
|
|||||||
Buttons: ButtonsTree
|
Buttons: ButtonsTree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ButtonsTree = {
|
||||||
|
Landing: ButtonProperties,
|
||||||
|
Car: ButtonProperties,
|
||||||
|
Special: ButtonProperties,
|
||||||
|
Relays: ButtonProperties
|
||||||
|
}
|
||||||
|
export type ButtonProperties = {
|
||||||
|
Inst: Instance?,
|
||||||
|
Prompt: ProximityPrompt?,
|
||||||
|
Attachment: Attachment?
|
||||||
|
}
|
||||||
|
export type ButtonsConstructor = ClassConstructor
|
||||||
|
|
||||||
local ButtonsModule = {} :: Impl_Constructor
|
local ButtonsModule = {} :: Impl_Constructor
|
||||||
ButtonsModule.__index = ButtonsModule
|
ButtonsModule.__index = ButtonsModule
|
||||||
|
|
||||||
@@ -56,14 +61,18 @@ function ButtonsModule.constructor(Tags, Model)
|
|||||||
Landing = {},
|
Landing = {},
|
||||||
Car = {},
|
Car = {},
|
||||||
Special = {},
|
Special = {},
|
||||||
Relays = {},
|
Relays = {}
|
||||||
Unknown = {}
|
|
||||||
}
|
}
|
||||||
}, ButtonsModule)
|
}, ButtonsModule)
|
||||||
end
|
end
|
||||||
|
|
||||||
--Button parsing
|
--Button parsing
|
||||||
|
|
||||||
|
function ButtonsModule:DecodeCarTag(FloorTag)
|
||||||
|
local Match = FloorTag:match('%d+$')
|
||||||
|
return Match and tonumber(Match)
|
||||||
|
end
|
||||||
|
|
||||||
function ButtonsModule:Get()
|
function ButtonsModule:Get()
|
||||||
local Buttons: GetButtons = {}
|
local Buttons: GetButtons = {}
|
||||||
|
|
||||||
@@ -94,59 +103,74 @@ function ButtonsModule:CreatePromptButtons()
|
|||||||
Attachment.Parent = Inst
|
Attachment.Parent = Inst
|
||||||
local Prompt = Instance.new("ProximityPrompt") :: ProximityPrompt
|
local Prompt = Instance.new("ProximityPrompt") :: ProximityPrompt
|
||||||
Prompt.MaxActivationDistance = 3
|
Prompt.MaxActivationDistance = 3
|
||||||
|
Prompt.HoldDuration = .30
|
||||||
Prompt.Parent = Attachment
|
Prompt.Parent = Attachment
|
||||||
|
|
||||||
local Split = TagName:split('_')
|
local Split = TagName:split('_')
|
||||||
local ButtonType = if tonumber(Split[3]) then
|
local ButtonType = if tonumber(Split[3]) then
|
||||||
Enums.Buttons.Car
|
Enums.Button.Car
|
||||||
elseif Split[3] == "Floor" and Split[4]:match('%d') then
|
elseif Split[3] == "Floor" and Split[4]:match('%d') then
|
||||||
Enums.Buttons.Landing
|
Enums.Button.Landing
|
||||||
elseif Split[2] == "ElevatorButton" then
|
elseif Split[2] == "ElevatorButton" then
|
||||||
Enums.Buttons.Special
|
Enums.Button.Special
|
||||||
elseif Split[2] == "RelayButton" then
|
elseif Split[2] == "RelayButton" then
|
||||||
Enums.Buttons.Relay
|
Enums.Button.Relay
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
|
|
||||||
if ButtonType == Enums.Buttons.Car then
|
if ButtonType == Enums.Button.Car then
|
||||||
--ElevatorButton_1
|
--ElevatorButton_1
|
||||||
|
|
||||||
|
Prompt.ActionText = tostring(Split[3])
|
||||||
|
Prompt.ObjectText = "Floor"
|
||||||
|
|
||||||
self.Buttons.Car[`{Split[2]}_{Split[3]}`] = {
|
self.Buttons.Car[`{Split[2]}_{Split[3]}`] = {
|
||||||
Inst = Inst,
|
Inst = Inst,
|
||||||
Prompt = Prompt
|
Prompt = Prompt,
|
||||||
|
Attachment = Attachment
|
||||||
}
|
}
|
||||||
Prompt.ActionText = tostring(Split[3])
|
elseif ButtonType == Enums.Button.Landing then
|
||||||
Prompt.ObjectText = "Floor"
|
|
||||||
elseif ButtonType == Enums.Buttons.Landing then
|
|
||||||
--ElevatorButton_Floor_1_Up
|
--ElevatorButton_Floor_1_Up
|
||||||
|
|
||||||
|
Prompt.ActionText = tostring(Split[5])
|
||||||
|
Prompt.ObjectText = `Floor {tostring(Split[4])}`
|
||||||
|
|
||||||
self.Buttons.Landing[`{Split[2]}_{Split[3]}_{Split[4]}_{Split[5]}`] = {
|
self.Buttons.Landing[`{Split[2]}_{Split[3]}_{Split[4]}_{Split[5]}`] = {
|
||||||
Inst = Inst,
|
Inst = Inst,
|
||||||
Prompt = Prompt
|
Prompt = Prompt,
|
||||||
|
Attachment = Attachment
|
||||||
}
|
}
|
||||||
Prompt.ActionText = tostring(Split[5])
|
elseif ButtonType == Enums.Button.Special then
|
||||||
Prompt.ObjectText = `Floor {tostring(Split[4])}`
|
|
||||||
elseif ButtonType == Enums.Buttons.Special then
|
|
||||||
--ElevatorButton_Open
|
--ElevatorButton_Open
|
||||||
|
|
||||||
|
Prompt.ActionText = tostring(Split[3])
|
||||||
|
Prompt.ObjectText = "Floor"
|
||||||
|
|
||||||
self.Buttons.Special[`{Split[2]}_{Split[3]}`] = {
|
self.Buttons.Special[`{Split[2]}_{Split[3]}`] = {
|
||||||
Inst = Inst,
|
Inst = Inst,
|
||||||
Prompt = Prompt
|
Prompt = Prompt,
|
||||||
|
Attachment = Attachment
|
||||||
}
|
}
|
||||||
Prompt.ActionText = tostring(Split[3])
|
elseif ButtonType == Enums.Button.Relay then
|
||||||
Prompt.ObjectText = "Floor"
|
|
||||||
elseif ButtonType == Enums.Buttons.Relay then
|
|
||||||
--RelayButton_F1
|
--RelayButton_F1
|
||||||
|
|
||||||
|
if self.Model == Enums.Elevator.Otis1960 then --This is bad...
|
||||||
Attachment.Position-=Vector3.new(.1,.3,0)
|
Attachment.Position-=Vector3.new(.1,.3,0)
|
||||||
|
end
|
||||||
|
|
||||||
|
Prompt.MaxActivationDistance = 4
|
||||||
|
Prompt.Exclusivity = Enum.ProximityPromptExclusivity.OneGlobally --why does this not work...
|
||||||
|
Prompt.ActionText = `Relay {tostring(Split[3])}`
|
||||||
|
Prompt.ObjectText = "Activate"
|
||||||
|
|
||||||
self.Buttons.Relays[`{Split[2]}_{Split[3]}`] = {
|
self.Buttons.Relays[`{Split[2]}_{Split[3]}`] = {
|
||||||
Inst = Inst,
|
Inst = Inst,
|
||||||
Prompt = Prompt
|
Prompt = Prompt,
|
||||||
|
Attachment = Attachment
|
||||||
}
|
}
|
||||||
Prompt.ActionText = `Relay {tostring(Split[3])}`
|
|
||||||
Prompt.ObjectText = "Activate"
|
|
||||||
else
|
else
|
||||||
|
Attachment:Destroy()
|
||||||
|
Prompt:Destroy()
|
||||||
warn(`{self.Model}: Door tag was present but couldnt specify its type for use "{TagName}"`)
|
warn(`{self.Model}: Door tag was present but couldnt specify its type for use "{TagName}"`)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -156,8 +180,19 @@ function ButtonsModule:CreatePromptButtons()
|
|||||||
return self.Buttons
|
return self.Buttons
|
||||||
end
|
end
|
||||||
|
|
||||||
function ButtonsModule:HookPromptButtonsGroup()
|
function ButtonsModule:HookPromptButtonsGroup(Prompt, Inst, PromptCallback)
|
||||||
|
Prompt.Triggered:Connect(function(Player)
|
||||||
|
local PlayerCharacter = Player.Character
|
||||||
|
local Root = PlayerCharacter and PlayerCharacter:FindFirstChild("HumanoidRootPart") :: HumanoidRootPart?
|
||||||
|
|
||||||
|
if Root then
|
||||||
|
if (Root.Position-Inst.Position).Magnitude<=Prompt.MaxActivationDistance+1 then
|
||||||
|
PromptCallback(Player)
|
||||||
|
else
|
||||||
|
warn(`{Player.Name}, {Player.UserId} activated a prompt without being in range of MaxActivationDistance.`)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ButtonsModule
|
return ButtonsModule
|
||||||
@@ -2,17 +2,30 @@
|
|||||||
--!native
|
--!native
|
||||||
--!strict
|
--!strict
|
||||||
|
|
||||||
|
|
||||||
local Enums = {}
|
local Enums = {}
|
||||||
|
|
||||||
Enums.Buttons = {
|
export type EnumValue = typeof(Enums.Button)
|
||||||
Car = "CarButton",
|
| typeof(Enums.ButtonTree)
|
||||||
Landing = "LandingButton",
|
| typeof(Enums.Elevator)
|
||||||
Special = "SpecialButton",
|
|
||||||
Relay = "RelayButton"
|
Enums.Button = {
|
||||||
|
Car = "CarButton" :: "CarButton",
|
||||||
|
Landing = "LandingButton" :: "LandingButton",
|
||||||
|
Special = "SpecialButton" :: "SpecialButton",
|
||||||
|
Relay = "RelayButton" :: "RelayButton"
|
||||||
}
|
}
|
||||||
|
|
||||||
Enums.Elevators = {
|
Enums.ButtonTree = {
|
||||||
Otis1960 = "Otis1960"
|
Car = "Car" :: "Car",
|
||||||
|
Landing = "Landing" :: "Landing",
|
||||||
|
Special = "Special" :: "Special",
|
||||||
|
Relays = "Relays" :: "Relays",
|
||||||
|
Unknown = "Unknown" :: "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
Enums.Elevator = {
|
||||||
|
Otis1960 = "Otis1960" :: "Otis1960"
|
||||||
}
|
}
|
||||||
|
|
||||||
return Enums
|
return Enums
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
--!native
|
--!native
|
||||||
--!strict
|
--!strict
|
||||||
|
|
||||||
local Leveling: {[number]: number} = {
|
local Leveling: {number} = {
|
||||||
[1] = 13.031,
|
[1] = 13.041,
|
||||||
[2] = 0,
|
[2] = 37.973,
|
||||||
[3] = 0,
|
[3] = 0,
|
||||||
[4] = 0,
|
[4] = 0,
|
||||||
[5] = 0,
|
[5] = 0,
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
local Elevators = script.Parent
|
local Elevators = script.Parent
|
||||||
|
|
||||||
local RS: ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local Storage: ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
local TagsModule = require(RS:WaitForChild("Tags"))
|
local RS: RunService = game:GetService("RunService")
|
||||||
|
|
||||||
|
local TagsModule = require(Storage:WaitForChild("Tags"))
|
||||||
|
|
||||||
local Leveling = require(script:WaitForChild("Leveling"))
|
local Leveling = require(script:WaitForChild("Leveling"))
|
||||||
local Doors = require(script:WaitForChild("Doors"))
|
local Doors = require(script:WaitForChild("Doors"))
|
||||||
@@ -21,12 +23,17 @@ type Impl_Constructor = {
|
|||||||
__index: Impl_Constructor,
|
__index: Impl_Constructor,
|
||||||
constructor: Constructor_Fun,
|
constructor: Constructor_Fun,
|
||||||
--Class functions
|
--Class functions
|
||||||
MoveFloors: (self: ClassConstructor, Level: number) -> (),
|
__MoveFloors: (self: ClassConstructor, Level: number) -> (),
|
||||||
GoToLevel: (self: ClassConstructor, RequestedLevel: number) -> ()
|
GoToLevel: (self: ClassConstructor, RequestedLevel: number) -> ()
|
||||||
|
} & Impl_Static_Props
|
||||||
|
|
||||||
|
type Impl_Static_Props = {
|
||||||
|
Moving: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type Constructor_Fun = (Tags: Tags) -> ClassConstructor
|
type Constructor_Fun = (Tags: Tags) -> ClassConstructor
|
||||||
type Constructor_Return_Props = {
|
type Constructor_Return_Props = {
|
||||||
|
Tags: Tags,
|
||||||
ElevatorBox_1960: BasePart,
|
ElevatorBox_1960: BasePart,
|
||||||
ElevatorBox: BasePart,
|
ElevatorBox: BasePart,
|
||||||
ElevatorDoor1: BasePart,
|
ElevatorDoor1: BasePart,
|
||||||
@@ -42,8 +49,69 @@ type Constructor_Return_Props = {
|
|||||||
local Otis1960 = {} :: Impl_Constructor
|
local Otis1960 = {} :: Impl_Constructor
|
||||||
Otis1960.__index = Otis1960
|
Otis1960.__index = Otis1960
|
||||||
|
|
||||||
|
Otis1960.Moving = false
|
||||||
|
|
||||||
|
local function ButtonPress(Button: BasePart, Activated: boolean)
|
||||||
|
task.spawn(function()
|
||||||
|
local Glass = Button:FindFirstChild("Glass") :: BasePart
|
||||||
|
if Glass then
|
||||||
|
Glass.Position+=Glass.CFrame.LookVector/50
|
||||||
|
|
||||||
|
if not Activated then
|
||||||
|
Glass.Material = Enum.Material.Neon
|
||||||
|
Glass.Color = Color3.fromRGB(180,0,0)
|
||||||
|
Glass.Transparency = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Button.Position+=Glass.CFrame.LookVector/50
|
||||||
|
|
||||||
|
task.wait(.30)
|
||||||
|
if Glass then
|
||||||
|
Glass.Position-=Glass.CFrame.LookVector/50
|
||||||
|
end
|
||||||
|
Button.Position-=Glass.CFrame.LookVector/50
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function HookButtons(self: ClassConstructor, ButtonsConstructor: ButtonTags.ButtonsConstructor, ButtonType: Enums.EnumValue)
|
||||||
|
for ButtonNameType, ButtonList in ButtonsConstructor.Buttons do
|
||||||
|
for ButtonName, ButtonTree in ButtonList do
|
||||||
|
if ButtonTree.Prompt then
|
||||||
|
if ButtonTree.Inst then
|
||||||
|
if ButtonNameType == Enums.ButtonTree.Car then
|
||||||
|
local DecodedFloor = ButtonsConstructor:DecodeCarTag(ButtonName)
|
||||||
|
|
||||||
|
ButtonsConstructor:HookPromptButtonsGroup(ButtonTree.Prompt, ButtonTree.Inst, function(_Player: Player)
|
||||||
|
if DecodedFloor then
|
||||||
|
ButtonTree.Prompt.Enabled = false
|
||||||
|
ButtonPress(ButtonTree.Inst, false)
|
||||||
|
|
||||||
|
self:GoToLevel(DecodedFloor)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
elseif ButtonNameType == Enums.ButtonTree.Special then
|
||||||
|
|
||||||
|
elseif ButtonNameType == Enums.ButtonTree.Landing then
|
||||||
|
ButtonsConstructor:HookPromptButtonsGroup(ButtonTree.Prompt, ButtonTree.Inst, function(_Player: Player)
|
||||||
|
ButtonTree.Prompt.Enabled = false
|
||||||
|
ButtonPress(ButtonTree.Inst, false)
|
||||||
|
|
||||||
|
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
warn(`{ButtonTree} is missing the field "Inst"`)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
warn(`{ButtonTree} is missing the field "Prompt"`)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Otis1960.constructor(Tags)
|
function Otis1960.constructor(Tags)
|
||||||
local self = {} :: Constructor_Return_Props
|
local self = {} :: Constructor_Return_Props
|
||||||
|
self.Tags = Tags
|
||||||
self.ElevatorBox_1960 = Tags.ElevatorMover_1960 :: BasePart
|
self.ElevatorBox_1960 = Tags.ElevatorMover_1960 :: BasePart
|
||||||
self.ElevatorBox = Tags.ElevatorMover_1960 :: BasePart
|
self.ElevatorBox = Tags.ElevatorMover_1960 :: BasePart
|
||||||
self.ElevatorDoor1 = Tags.ElevatorDoor_1960_1 :: BasePart
|
self.ElevatorDoor1 = Tags.ElevatorDoor_1960_1 :: BasePart
|
||||||
@@ -55,23 +123,40 @@ function Otis1960.constructor(Tags)
|
|||||||
self.ElevatorDoors = Doors.constructor(self.ElevatorBox, self.ElevatorDoor1, self.ElevatorDoor2, self.ElevatorDoorSensor)
|
self.ElevatorDoors = Doors.constructor(self.ElevatorBox, self.ElevatorDoor1, self.ElevatorDoor2, self.ElevatorDoorSensor)
|
||||||
|
|
||||||
--Buttons
|
--Buttons
|
||||||
local Buttons = ButtonTags.constructor(Tags, Enums.Elevators.Otis1960)
|
local ButtonsConstructor = ButtonTags.constructor(Tags, Enums.Elevator.Otis1960)
|
||||||
local Otis1960_Buttons = Buttons:CreatePromptButtons()
|
local Otis1960_Buttons = ButtonsConstructor:CreatePromptButtons()
|
||||||
|
|
||||||
|
local ClassConstructor = setmetatable(self, Otis1960)
|
||||||
|
HookButtons(ClassConstructor, ButtonsConstructor, Enums.ButtonTree.Car)
|
||||||
|
|
||||||
print("[DEBUG] Otis1960 Buttons=", Otis1960_Buttons)
|
print("[DEBUG] Otis1960 Buttons=", Otis1960_Buttons)
|
||||||
print("🔝 Otis1960 initialized and ready")
|
print("🔝 Otis1960 initialized and ready")
|
||||||
return setmetatable(self, Otis1960)
|
return ClassConstructor
|
||||||
end
|
end
|
||||||
|
|
||||||
function Otis1960:MoveFloors(Level)
|
local BiggestRopeLength = Leveling[#Leveling]-2
|
||||||
|
|
||||||
|
function Otis1960:__MoveFloors(Level)
|
||||||
local ElevatorBoxCurrentPos = self.ElevatorBox.Position
|
local ElevatorBoxCurrentPos = self.ElevatorBox.Position
|
||||||
|
|
||||||
|
local RopeConnection = RS.Heartbeat:Connect(function(_dt)
|
||||||
|
local Ropes = self.Tags["1960_ElevatorPulleyRope"] :: {Instance}
|
||||||
|
|
||||||
|
for i: number = 1, #Ropes do
|
||||||
|
(Ropes[i] :: RopeConstraint).Length = (BiggestRopeLength-self.ElevatorBox.Position.Y)*10
|
||||||
|
print((Ropes[i] :: RopeConstraint).Length)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
self.BoxAlignPosition.Position = Vector3.new(ElevatorBoxCurrentPos.X, Level, ElevatorBoxCurrentPos.Z)
|
self.BoxAlignPosition.Position = Vector3.new(ElevatorBoxCurrentPos.X, Level, ElevatorBoxCurrentPos.Z)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Otis1960:GoToLevel(RequestedLevel)
|
function Otis1960:GoToLevel(RequestedLevel)
|
||||||
local level: number = Leveling[RequestedLevel]
|
local level: number = Leveling[RequestedLevel]
|
||||||
if level then
|
if level and level ~= 0 then
|
||||||
self:MoveFloors(level)
|
self:__MoveFloors(level)
|
||||||
|
else
|
||||||
|
warn(`[{Enums.Elevator.Otis1960}]: landing out of range! requested landing: {tostring(RequestedLevel)}`)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user