Advertisement
ceater_nerd

mineswep

Mar 31st, 2024 (edited)
1,002
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.58 KB | None | 0 0
  1. -- ceat_ceat
  2. -- missing textures and colors LOL
  3. warn("mineswep by ceat yay")
  4.  
  5. if game:GetService("RunService"):IsStudio() then
  6.     require(game.ServerStorage.lsbenv)()
  7.     owner,printf,warnf,LoadLibrary,LoadAssets,NLS=owner,printf,warnf,LoadLibrary,LoadAssets,NLS
  8. end
  9.  
  10.  
  11. local TweenService = game:GetService("TweenService")
  12. local Debris = game:GetService("Debris")
  13.  
  14. local DEFAULT_TILE_WIDTH = 1.5
  15. local FIELD_RADIUS = 1
  16. local RESTART_TIME = 3
  17.  
  18. local UNOPENED_TEX = "rbxassetid://15144071117"
  19. local OPENED_TEX = "rbxassetid://13348346487"
  20. local MINE_TEX = "rbxassetid://13348250535"
  21. local FLAG_TEX = "rbxassetid://10720664742"
  22. local BLANK_TEX = "rbxassetid://12381187927"
  23. local NUMBER_FONT = Enum.Font.SourceSansBold
  24. local WIN_MINE_COLOR = Color3.new(0.5, 1, 0.5)
  25.  
  26. local DIG_SOUND = "rbxassetid://3498493622"
  27. local FLAG_SOUND = "rbxassetid://8388724806"
  28. local CORRECT_SOUND = "rbxassetid://3422389728"
  29. local YAY_SOUND = "rbxassetid://9068897474"
  30. local ALARM_SOUND = "rbxassetid://2778386920"
  31. local EXPLODE_SOUND = "rbxassetid://165969964"
  32.  
  33. local COLORS = {
  34.     Color3.fromRGB(0, 0, 255),
  35.     Color3.fromRGB(39, 107, 31),
  36.     Color3.fromRGB(255, 0, 0),
  37.     Color3.fromRGB(0, 0, 130),
  38.     Color3.fromRGB(157, 0, 0),
  39.     Color3.fromRGB(0, 214, 146),
  40.     Color3.fromRGB(98, 0, 168),
  41.     Color3.fromRGB(100, 100, 100),
  42. }
  43.  
  44. local FLASH_TWEENINFO = TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.In)
  45. local WIN_FLASH_TWEENINFO = TweenInfo.new(0.75, Enum.EasingStyle.Linear, Enum.EasingDirection.In)
  46.  
  47. local settings = {
  48.     tileWidth = DEFAULT_TILE_WIDTH,
  49.     use3DFlags = false,
  50.     width = 25,
  51.     height = 25,
  52.     mineCount = 90,
  53.     debug = false
  54. }
  55.  
  56. local currentGame
  57.  
  58. local function createTilePart(cf, tileWidth)
  59.     local part = Instance.new("Part")
  60.     part.Anchored = true
  61.     part.CFrame = cf
  62.     part.Size = Vector3.new(tileWidth, 0.5, tileWidth)
  63.  
  64.     local tileDecal = Instance.new("Decal")
  65.     tileDecal.Name = "TileTexture"
  66.     tileDecal.Texture = UNOPENED_TEX
  67.     tileDecal.Face = Enum.NormalId.Top
  68.     tileDecal.Parent = part
  69.  
  70.     local clickDetector = Instance.new("ClickDetector")
  71.     clickDetector.Name = "ClickDetector"
  72.     clickDetector.MaxActivationDistance = 30
  73.     clickDetector.Parent = part
  74.  
  75.     return part
  76. end
  77.  
  78. local function createFlagDecal(part)
  79.     local decal = Instance.new("Decal")
  80.     decal.Name = "FlagDecal"
  81.     decal.Texture = FLAG_TEX
  82.     decal.Face = Enum.NormalId.Top
  83.     decal.ZIndex = 5
  84.     decal.Parent = part
  85.     return decal
  86. end
  87.  
  88. local function displayNumber(tile)
  89.     local surfaceGui = Instance.new("SurfaceGui")
  90.     surfaceGui.Name = "NumberFace"
  91.     surfaceGui.Face = Enum.NormalId.Top
  92.     surfaceGui.SizingMode = Enum.SurfaceGuiSizingMode.PixelsPerStud
  93.     surfaceGui.PixelsPerStud = 25
  94.  
  95.     local label = Instance.new("TextLabel")
  96.     label.Name = "NumberLabel"
  97.     label.Text = tostring(tile.minesAround)
  98.     label.Font = NUMBER_FONT
  99.     label.TextColor3 = COLORS[tile.minesAround]
  100.     label.TextScaled = true
  101.     label.BackgroundTransparency = 1
  102.     label.AnchorPoint = Vector2.new(0.5, 0.5)
  103.     label.Position = UDim2.fromScale(0.5, 0.5)
  104.     label.Size = UDim2.fromScale(2, 2)
  105.     label.TextTransparency = 1
  106.     label.Rotation = -90
  107.  
  108.     local flashDecal = Instance.new("Decal")
  109.     flashDecal.Texture = BLANK_TEX
  110.     flashDecal.Face = Enum.NormalId.Top
  111.     flashDecal.ZIndex = 5
  112.     flashDecal.Transparency = 0
  113.     flashDecal.Parent = tile.part
  114.  
  115.     label.Parent = surfaceGui
  116.     surfaceGui.Parent = tile.part
  117.  
  118.     TweenService:Create(flashDecal, FLASH_TWEENINFO, { Transparency = 1 }):Play()
  119.     TweenService:Create(label, TweenInfo.new(0.2), {
  120.         TextTransparency = 0
  121.     }):Play()
  122.     TweenService:Create(label, TweenInfo.new(0.2 + math.random()*0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {
  123.         Size = UDim2.fromScale(1, 1)
  124.     }):Play()
  125.     Debris:AddItem(flashDecal, FLASH_TWEENINFO.Time)
  126. end
  127.  
  128. local function iterTiles(tiles)
  129.     local width = #tiles
  130.     local height = #tiles[1]
  131.     local x = 1
  132.     local y = 1
  133.     return function()
  134.         if x > width then
  135.             x = 1
  136.             y += 1
  137.             if y > height then
  138.                 return
  139.             end
  140.         end
  141.         local x1 = x
  142.         x += 1
  143.         return x1, y, tiles[x1][y]
  144.     end
  145. end
  146.  
  147. local function disableTile(tile)
  148.     tile.enabled = false
  149.     tile.leftClickConnection:Disconnect()
  150.     tile.rightClickConnection:Disconnect()
  151.     tile.leftClickConnection = nil
  152.     tile.rightClickConnection = nil
  153.     tile.clickDetector:Destroy()
  154. end
  155.  
  156. local function unflagTile(tile)
  157.     if tile.flagInstance then
  158.         tile.flagInstance:Destroy()
  159.         tile.flagInstance = nil
  160.     end
  161. end
  162.  
  163. local function getTilesToFlash(tiles, x, y, offset)
  164.     local flashyGuys = {}
  165.     -- top left -> top right
  166.     for xOff = -offset, offset do
  167.         local tile = tiles[x - xOff] and tiles[x - xOff][y - offset]
  168.         if tile then
  169.             table.insert(flashyGuys, tile)
  170.         end
  171.     end
  172.     -- bottom left -> bottom right
  173.     for xOff = -offset, offset do
  174.         local tile = tiles[x + xOff] and tiles[x + xOff][y + offset]
  175.         if tile and not table.find(flashyGuys, tile) then
  176.             table.insert(flashyGuys, tile)
  177.         end
  178.     end
  179.     -- top left -> bottom left
  180.     if tiles[x - offset] then
  181.         for yOff = -offset, offset do
  182.             local tile = tiles[x - offset][y + yOff]
  183.             if tile and not table.find(flashyGuys, tile) then
  184.                 table.insert(flashyGuys, tile)
  185.             end
  186.         end
  187.     end
  188.     -- top right -> bottom right
  189.     if tiles[x + offset] then
  190.         for yOff = -offset, offset do
  191.             local tile = tiles[x + offset][y + yOff]
  192.             if tile and not table.find(flashyGuys, tile) then
  193.                 table.insert(flashyGuys, tile)
  194.             end
  195.         end
  196.     end
  197.     return flashyGuys
  198. end
  199.  
  200. local function flashTilesWave(tiles, tile, width, height, winner, color)
  201.     local baseX = tile.x
  202.     local baseY = tile.y
  203.     for i = 0, math.max(width, height) do
  204.         for _, tile in getTilesToFlash(tiles, baseX, baseY, i) do
  205.             if tile.isFlagged then
  206.                 tile.isFlagged = false
  207.                 unflagTile(tile)
  208.             end
  209.             if winner then
  210.                 tile.tileTexture.Texture = OPENED_TEX
  211.             else
  212.                 if tile.isMine then
  213.                     tile.tileTexture.Texture = MINE_TEX
  214.                 end
  215.             end
  216.             tile.tileTexture.Color3 = color
  217.             if not tile.isMine then
  218.                 TweenService:Create(tile.tileTexture, WIN_FLASH_TWEENINFO, { Color3 = Color3.new(1, 1, 1) }):Play()
  219.             end
  220.         end
  221.         task.wait()
  222.     end
  223. end
  224.  
  225. local function playSound(part, soundId, pitch)
  226.     local sound = Instance.new("Sound")
  227.     sound.SoundId = soundId
  228.     sound.Pitch = pitch
  229.     sound.Parent = part
  230.     sound:Play()
  231.     Debris:AddItem(sound, 4)
  232.     return sound
  233. end
  234.  
  235. -- debug visuals
  236.  
  237. local function highlightTile(tile, color)
  238.     local part = Instance.new("Part")
  239.     part.Anchored = true
  240.     part.CanCollide = false
  241.     part.CanTouch = false
  242.     part.CanQuery = false
  243.     part.Material = Enum.Material.Neon
  244.     part.Color = color
  245.     part.Size = Vector3.new(settings.tileWidth, 0.7, settings.tileWidth)
  246.     part.Transparency = 0.8
  247.     part.CFrame = tile.part.CFrame
  248.     return part
  249. end
  250.  
  251. local function showNeighbors(tiles, tile)
  252.     local main = highlightTile(tile, Color3.new(1, 0, 0))
  253.     main.Parent = workspace
  254.  
  255.     local neighborParts = {}
  256.     for _, position in tile.neighbors do
  257.         local part = highlightTile(tiles[position.x][position.y], Color3.new(0, 0, 1))
  258.         part.Parent = workspace
  259.         table.insert(neighborParts, part)
  260.     end
  261.     task.wait()
  262.     main:Destroy()
  263.     for _, part in neighborParts do
  264.         part:Destroy()
  265.     end
  266. end
  267.  
  268. -- game wow
  269.  
  270. local restartTask
  271.  
  272. local function restart(spawnCF, width, height, numMines)
  273.     restartTask = task.delay(RESTART_TIME, function()
  274.         restartTask = nil
  275.         stopGame(currentGame)
  276.         currentGame = createGame(spawnCF, width, height, numMines)
  277.     end)
  278. end
  279.  
  280. function createGame(spawnCF, width, height, numMines)
  281.     local gameObject = {}
  282.  
  283.     local gameSettings = table.clone(settings)
  284.     gameObject.settings = gameSettings
  285.  
  286.     local model = Instance.new("Model")
  287.     model.Name = "Minesweeper"
  288.     gameObject.model = model
  289.  
  290.     local tiles = {}
  291.     gameObject.tiles = tiles
  292.  
  293.     gameObject.active = true
  294.     gameObject.didFirstClick = false
  295.     gameObject.players = {}
  296.  
  297.     local function layMines(clickedTile)
  298.         local validPositions = {}
  299.         -- filter out start field
  300.         for x, y, tile in iterTiles(tiles) do
  301.             if math.abs(x - clickedTile.x) <= FIELD_RADIUS and math.abs(y - clickedTile.y) <= FIELD_RADIUS then
  302.                 continue
  303.             end
  304.             table.insert(validPositions, { x = x, y = y })
  305.         end
  306.         for i = 1, math.min(numMines, #validPositions) do
  307.             local pos = table.remove(validPositions, math.random(#validPositions))
  308.             local tile = tiles[pos.x][pos.y]
  309.             tile.isMine = true
  310.             if gameSettings.debug then
  311.                 tile.tileTexture.Color3 = Color3.new(1, 0.5, 0.5)
  312.             end
  313.         end
  314.         -- count mines around tiles
  315.         for x, y, tile in iterTiles(tiles) do
  316.             for _, position in tile.neighbors do
  317.                 if tiles[position.x][position.y].isMine then
  318.                     tile.minesAround += 1
  319.                 end
  320.             end
  321.             if gameSettings.debug then
  322.                 showNeighbors(tiles, tile)
  323.             end
  324.         end
  325.     end
  326.  
  327.     local function onLose(plr, tile)
  328.         gameObject.active = false
  329.         for x, y, tile in iterTiles(tiles) do
  330.             if tile.enabled then
  331.                 disableTile(tile)
  332.             end
  333.             if tile.isMine then
  334.                 tile.tileTexture.Texture = MINE_TEX
  335.             end
  336.         end
  337.         tile.part.CFrame *= CFrame.new(0, 1, 0)
  338.         tile.part.Anchored = false
  339.         tile.part.Velocity  = Vector3.new(-3 + math.random()*6, math.random(20, 30), -3 + math.random()*6)
  340.         tile.part.RotVelocity = Vector3.new(math.random(-10, 10), math.random(-10, 10), math.random(-10, 10))
  341.         playSound(tile.part, ALARM_SOUND, 1).TimePosition = 0.35
  342.         playSound(tile.part, EXPLODE_SOUND, 1)
  343.        
  344.         local explod = Instance.new("Explosion")
  345.         explod.BlastPressure = 0
  346.         explod.BlastRadius = 0
  347.         explod.Position = tile.part.Position
  348.         explod.Parent = workspace
  349.        
  350.         flashTilesWave(tiles, tile, width, height, false, Color3.new(1, 0.5, 0.5))
  351.         restart(spawnCF, width, height, numMines)
  352.     end
  353.  
  354.     local function onWin(tile)
  355.         for x, y, tile in iterTiles(tiles) do
  356.             if tile.enabled then
  357.                 disableTile(tile)
  358.             end
  359.         end
  360.         playSound(tile.part, CORRECT_SOUND, 1)
  361.         playSound(tile.part, YAY_SOUND, 1)
  362.         flashTilesWave(tiles, tile, width, height, true, WIN_MINE_COLOR)
  363.         restart(spawnCF, width, height, numMines)
  364.     end
  365.  
  366.     local mineTile -- scream
  367.  
  368.     local function chordTile(plr, tile)
  369.         local unflaggedTiles = {}
  370.         local numFlagged = 0
  371.         for _, position in tile.neighbors do
  372.             local otherTile = tiles[position.x][position.y]
  373.             if otherTile.opened then continue end
  374.             if otherTile.isFlagged then
  375.                 numFlagged += 1
  376.             else
  377.                 table.insert(unflaggedTiles, otherTile)
  378.             end
  379.         end
  380.         if numFlagged == tile.minesAround then
  381.             for _, otherTile in unflaggedTiles do
  382.                 mineTile(plr, otherTile)
  383.             end
  384.         end
  385.     end
  386.  
  387.     function mineTile(plr, tile)
  388.         if not gameObject.active then
  389.             return
  390.         end
  391.         if tile.isMine then
  392.             onLose(plr, tile)
  393.             return
  394.         end
  395.         if tile.opened then
  396.             chordTile(plr, tile)
  397.             return
  398.         end
  399.         if not table.find(gameObject.players, plr.Name) then
  400.             table.insert(gameObject.players, plr.Name)
  401.         end
  402.         if tile.isFlagged then
  403.             tile.isFlagged = false
  404.             unflagTile(tile)
  405.         end
  406.         tile.opened = true
  407.         tile.tileTexture.Texture = OPENED_TEX
  408.         if tile.minesAround == 0 then
  409.             disableTile(tile)
  410.             for _, position in tile.neighbors do
  411.                 local otherTile = tiles[position.x][position.y]
  412.                 if otherTile.opened then continue end
  413.                 mineTile(plr, otherTile)
  414.             end
  415.         else
  416.             displayNumber(tile)
  417.         end
  418.     end
  419.  
  420.     local function checkWin()
  421.         local numNonMines = 0
  422.         local numOpened = 0
  423.         for x, y, tile in iterTiles(tiles) do
  424.             if not tile.isMine then
  425.                 numNonMines += 1
  426.             end
  427.             if tile.opened then
  428.                 numOpened += 1
  429.             end
  430.         end
  431.         return numNonMines == numOpened
  432.     end
  433.  
  434.     local function onLeftClick(tile)
  435.         return function(plr)
  436.             if tile.isFlagged then
  437.                 return
  438.             end
  439.             if not gameObject.didFirstClick then
  440.                 gameObject.didFirstClick = true
  441.                 layMines(tile)
  442.             end
  443.             playSound(tile.part, DIG_SOUND, 0.9 + math.random()*0.2)
  444.             mineTile(plr, tile)
  445.             if checkWin() then
  446.                 onWin(tile)
  447.             end
  448.         end
  449.     end
  450.  
  451.     local function onRightClick(tile)
  452.         return function(plr)
  453.             if tile.opened then
  454.                 return
  455.             end
  456.             tile.isFlagged = not tile.isFlagged
  457.             playSound(tile.part, FLAG_SOUND, 0.8 + math.random()*0.4)
  458.             if tile.isFlagged then
  459.                 if gameSettings.use3DFlags then
  460.                     -- not implemented
  461.                 else
  462.                     tile.flagInstance = createFlagDecal(tile.part)
  463.                 end
  464.             else
  465.                 unflagTile(tile)
  466.             end
  467.         end
  468.     end
  469.  
  470.     local originCF = spawnCF * CFrame.new(-width/2*gameSettings.tileWidth, 0, -height/2*gameSettings.tileWidth)
  471.     for x = 1, width do
  472.         local row = {}
  473.         for y = 1, height do
  474.             local tileCF = originCF * CFrame.new(x*gameSettings.tileWidth, 0, y*gameSettings.tileWidth)
  475.             local part = createTilePart(tileCF, gameSettings.tileWidth)
  476.  
  477.             --part.CanCollide = false
  478.             --part.Transparency = 1
  479.  
  480.             local self = {
  481.                 x = x,
  482.                 y = y,
  483.                 enabled = true,
  484.                 opened = false,
  485.                 isMine = false,
  486.                 isFlagged = false,
  487.                 neighbors = {}, -- {x = num, y = num}
  488.                 minesAround = 0, -- decided by layMines
  489.  
  490.                 part = part,
  491.                 tileTexture = part.TileTexture,
  492.                 clickDetector = part.ClickDetector,
  493.                 flagInstance = nil, -- decal or instance
  494.                 leftClickConnection = nil,
  495.                 rightClickConnection = nil,
  496.             }
  497.  
  498.             self.leftClickConnection = self.clickDetector.MouseClick:Connect(onLeftClick(self))
  499.             self.rightClickConnection = self.clickDetector.RightMouseClick:Connect(onRightClick(self))
  500.  
  501.             for xOffset = -1, 1 do
  502.                 for yOffset = -1, 1 do
  503.                     if xOffset == 0 and yOffset == 0 then continue end
  504.                     local x2 = x + xOffset
  505.                     local y2 = y + yOffset
  506.                     if x2 < 1 or x2 > width then continue end
  507.                     if y2 < 1 or y2 > height then continue end
  508.                     table.insert(self.neighbors, { x = x2, y = y2 })
  509.                 end
  510.             end
  511.             part.Parent = model
  512.  
  513.             --local delayTime = (y - 1)*(width)*0.00005 + x*0.00005
  514.  
  515.             --TweenService:Create(part, TweenInfo.new(0.15 + math.random()*0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {
  516.             --  Transparency = 0,
  517.             --  CFrame = tileCF,
  518.             --  CanCollide = true
  519.             --}):Play()
  520.  
  521.             row[y] = self
  522.         end
  523.         tiles[x] = row
  524.     end
  525.  
  526.     model.Parent = workspace
  527.     return gameObject
  528. end
  529.  
  530. function stopGame(gameObject)
  531.     for x, y, tile in iterTiles(gameObject.tiles) do
  532.         if tile.enabled then
  533.             disableTile(tile)
  534.         end
  535.     end
  536.     gameObject.model:Destroy()
  537. end
  538.  
  539. -- currentGame = createGame(CFrame.new(0, 5, 0), settings.width, settings.height, settings.mineCount)
  540.  
  541. local function getRootPos()
  542.     local humanoid = owner.Character and owner.Character:FindFirstChildOfClass("Humanoid")
  543.     if humanoid and humanoid.RootPart then
  544.         return humanoid.RootPart.CFrame.Position
  545.     end
  546. end
  547.  
  548. owner.Chatted:Connect(function(msg)
  549.     local cmdString = msg:match("ms/(.+)")
  550.     if not cmdString then return end
  551.  
  552.     local args = cmdString:split("/")
  553.     local cmdName = table.remove(args, 1)
  554.  
  555.     if cmdName == "size" then
  556.         if args[2] then
  557.             settings.width = tonumber(args[1])
  558.             settings.height = tonumber(args[2])
  559.             printf(`set size to <b>{settings.width}x{settings.height}</b>`)
  560.         else
  561.             local size = tonumber(args[1])
  562.             if not size then
  563.                 return printf("<i>pls provide size</i>")
  564.             end
  565.             settings.width = size
  566.             settings.height = size
  567.             printf(`set size to <b>{size}x{size}</b>`)
  568.         end
  569.     elseif cmdName == "mines" then
  570.         local mineCount = tonumber(args[1])
  571.         if not mineCount then
  572.             return printf("<i>pls provide minecount</i>")
  573.         end
  574.         settings.mineCount = mineCount
  575.         printf(`set mine count to <b>{settings.mineCount}</b>`)
  576.     elseif cmdName == "minefreq" then
  577.         local freq = tonumber(args[1])
  578.         if not freq then
  579.             return printf("<i>pls provide freq</i>")
  580.         end
  581.         settings.mineCount = math.floor(settings.width*settings.height*freq)
  582.         printf(`set mine count to <b>{settings.mineCount}</b>`)
  583.     elseif cmdName == "game" then
  584.         local rootPos = getRootPos()
  585.         if not rootPos then
  586.             return printf("<i>could not find rootpos</i>")
  587.         end
  588.         if currentGame then
  589.             stopGame(currentGame)
  590.         end
  591.         currentGame = createGame(CFrame.new(rootPos + Vector3.new(0, -1.75, 0)), settings.width, settings.height, settings.mineCount)
  592.         printf("<i>started game</i>")
  593.     elseif cmdName == "stop" then
  594.         if restartTask then
  595.             task.cancel(restartTask)
  596.             restartTask = nil
  597.         end
  598.         if currentGame then
  599.             stopGame(currentGame)
  600.         else
  601.             printf("<i>no game active</i>")
  602.         end
  603.     elseif cmdName == "debug" then
  604.         settings.debug = not settings.debug
  605.         printf(`<i>debug mode {settings.debug}</i>`)
  606.     elseif cmdName == "cmds" then
  607.         printf([[
  608. <b>ms/size/[width]/[height]</b> set board size to (width, height)
  609. <b>ms/size/<[sideLength]</b> set board size to (sideLength, sideLength)
  610. <b>ms/mines/[mineCount]</b> set mine count to mineCount
  611. <b>ms/minefreq/[mineFrequency]</b> set mine count to width*height*mineFrequency
  612. <b>ms/game</b> start game
  613. <b>ms/stop</b> end game
  614. <b>ms/cmds</b> this thing
  615.         ]])
  616.     else
  617.         printf("<i>invalid ms/ command</i>")
  618.     end
  619. end)
  620.  
  621. print("ms/cmds for list of commands (works with /e)")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement