--!optimize 2 --!native --!strict local Elevators = script.Parent local RS: ReplicatedStorage = game:GetService("ReplicatedStorage") local TagsModule = require(RS:WaitForChild("Tags")) local Enums = require(Elevators:WaitForChild("Enums")) type Tags = TagsModule.ExportedTags type HumanoidRootPart = BasePart type PromptCallback = (Player: Player) -> () type GetButtons = {[string]: Instance} type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor)) type Impl_Constructor = { __index: Impl_Constructor, constructor: Constructor_Fun, --Class functions DecodeCarTag: (self: ClassConstructor, FloorTag: string) -> number?, Get: (self: ClassConstructor) -> GetButtons, CreatePromptButtons: (self: ClassConstructor) -> ButtonsTree, HookPromptButtonsGroup: (self: ClassConstructor, Prompt: ProximityPrompt, Inst: BasePart, PromptCallback: PromptCallback) -> () } & Impl_Static_Props type Impl_Static_Props = { ButtonEnum: any } type Constructor_Fun = (Tags: Tags, Model: string) -> ClassConstructor type Constructor_Return_Props = { Tags: Tags, Model: string, 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 ButtonsModule.__index = ButtonsModule function ButtonsModule.constructor(Tags, Model) return setmetatable({ Tags = Tags, Model = Model, Buttons = { Landing = {}, Car = {}, Special = {}, Relays = {} } }, ButtonsModule) end --Button parsing function ButtonsModule:DecodeCarTag(FloorTag) local Match = FloorTag:match('%d+$') return Match and tonumber(Match) end function ButtonsModule:Get() local Buttons: GetButtons = {} for TagName: string, Inst: Instance | {Instance} in self.Tags do local Split = TagName:split('_') if Split[1] == self.Model and (Split[2] == "ElevatorButton" or Split[2] == "RelayButton") then if typeof(Inst) == "Instance" then Buttons[TagName] = Inst else end end end return Buttons end --[[ CarButton = Model_ElevatorButton_1 LandingButton = Model_ElevatorButton_Floor_1_Up SpecialButton = Model_ElevatorButton_Open RelayButton = Model_RelayButton_F1 ]] function ButtonsModule:CreatePromptButtons() local ModelButtons = self:Get() for TagName: string, Inst: Instance in ModelButtons do local Attachment = Instance.new("Attachment") :: Attachment Attachment.Parent = Inst local Prompt = Instance.new("ProximityPrompt") :: ProximityPrompt Prompt.MaxActivationDistance = 3 Prompt.HoldDuration = .30 Prompt.Parent = Attachment local Split = TagName:split('_') local ButtonType = if tonumber(Split[3]) then Enums.Button.Car elseif Split[3] == "Floor" and Split[4]:match('%d') then Enums.Button.Landing elseif Split[2] == "ElevatorButton" then Enums.Button.Special elseif Split[2] == "RelayButton" then Enums.Button.Relay else nil if ButtonType == Enums.Button.Car then --ElevatorButton_1 Prompt.ActionText = tostring(Split[3]) Prompt.ObjectText = "Floor" self.Buttons.Car[`{Split[2]}_{Split[3]}`] = { Inst = Inst, Prompt = Prompt, Attachment = Attachment } elseif ButtonType == Enums.Button.Landing then --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]}`] = { Inst = Inst, Prompt = Prompt, Attachment = Attachment } elseif ButtonType == Enums.Button.Special then --ElevatorButton_Open Prompt.ActionText = tostring(Split[3]) Prompt.ObjectText = "Floor" self.Buttons.Special[`{Split[2]}_{Split[3]}`] = { Inst = Inst, Prompt = Prompt, Attachment = Attachment } elseif ButtonType == Enums.Button.Relay then --RelayButton_F1 if self.Model == Enums.Elevator.Otis1960 then --This is bad... 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]}`] = { Inst = Inst, Prompt = Prompt, Attachment = Attachment } else Attachment:Destroy() Prompt:Destroy() warn(`{self.Model}: Door tag was present but couldnt specify its type for use "{TagName}"`) end print(`[{tostring(ButtonType)}] {self.Model}: created a ProximityPrompt @ "{Inst:GetFullName()}"`) end return self.Buttons end 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 return ButtonsModule