turns-00057.parquet:10038
58cb269314341c07dd0299cedegenerate_repetitionAbsentFinal dense release
Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.
58cb269314341c07dd0299ceCâu hỏi có phù hợp với nội dung không (trả lời có hoặc không)? Câu hỏi: Có tính năng nào tự động tính phí dịch vụ không? Câu trả lời: Trên CMS nhà hàng bật cấu hình "Cho phép tự nhập phí dịch vụ" thì nhân viên có thê nhập phí dịch vụ vào đơn hàng. Nếu nhà hàng tạo phí dịch vụ từ CMS, phí sẽ tự động thêm vào đơn hàng nếu thỏa mãn điều kiện.
Có.
fd7c6f6ec0ceedc387399d3a#Region " Variables "
Private regionIcon As Image
Public regions As New List(Of RegionInfo)
Public SnapToFloor As Boolean
Public Property HoveredTrigger As Triggers = Nothing
Public Property TriggerData As New List(Of Triggers)
Private triggersCollection As New List(Of Triggers)
Private triggerImage2 As Image
Private triggerImage As Image
Private triggerImageSmall As Image
Private triggerImage2Small As Image
Private IsOnGate As Boolean = False
Private IsOnBaddy As Boolean = False
Private xOrigin As Integer = INDENT
Private yOrigin As Integer = INDENT
Private selectedTriggerSquare As New Point(-1, -1)
Private selectedActionSquare As New Point(-1, -1)
Private selectedItemToRemove As String = ""
Private invalidateTimer As Timer
Private draggedSelectionCellX As Integer
Private draggedSelectionCellY As Integer
Private Const MaxRecentFiles As Integer = 10
Private recentFiles As New List(Of String)()
Private recentFilesFilePath As String = Path.Combine(GetProjectDirectory(), "recent_files.txt")
Private lastMouseMoveTime As Date = Date.MinValue
Private Const DEBOUNCE_INTERVAL As Integer = 50 ' milliseconds
Public Property SelectionMode As Boolean = False
Public Property SelectionRequestedByForm As Form = Nothing
Public Property SelectionRequestedFor As String = ""
Private Const INDENT As Integer = 30
Friend SQCOUNTX As Integer = 16
Friend SQCOUNTY As Integer = 11
Private Const WALL_THICKNESS As Integer = 10
Friend wallsHatchStyle As HatchStyle = HatchStyle.LargeConfetti
Friend wallsColor1 As Color = Color.FromArgb(255, 0, 0, 0)
Friend wallsColor2 As Color = Color.FromArgb(255, 64, 0, 0)
Friend floorsHatchStyle As HatchStyle = HatchStyle.Divot
Friend floorsColor1 As Color = Color.FromArgb(255, 64, 0, 0)
Friend floorsColor2 As Color = Color.FromArgb(255, 0, 64, 0)
Friend floorsUseEdgeStyle()() As Boolean 'track edge style usage
Private SQSizeX As Integer
Private SQSizeY As Integer
Private highlightedX As Integer
Private highlightedY As Integer
Private highlightedWallX As Boolean = False
Private highlightedWallY As Boolean = False
Private highlightColor As Color = Color.Black
Private highlightTimer As Timer
Private isRestoringState As Boolean = False
Private isActionInProgress As Boolean = False
Private undoStack As New Stack(Of RoomData)
Private redoStack As New Stack(Of RoomData)
Private ReadOnly projectDir As String = GetProjectDirectory()
Private ReadOnly premadesFolder As String = Path.Combine(projectDir, "Data", "Premades")
Private ReadOnly savesFolder As String = Path.Combine(projectDir, "Data", "Saves")
Private ReadOnly musicFolder As String = Path.Combine(projectDir, "Data", "Sound/Music")
Private ReadOnly tempFilePath As String = Path.Combine(Path.GetTempPath(), "temp.room")
Private ReadOnly ImagesFolder As String = Path.Combine(projectDir, "Data", "Images")
Private ReadOnly IconsFolder As String = Path.Combine(projectDir, "Data", "Icons")
Private ReadOnly TextureFolder As String = Path.Combine(projectDir, "Data", "Textures")
Private currentFilePath As String = ""
Friend SelectedMusic As String = ""
Friend verticalWalls()() As Boolean
Friend horizontalWalls()() As Boolean
Friend placedItems()() As ItemInfo
Friend verticalWallItems()() As ItemInfo
Friend horizontalWallItems()() As ItemInfo
Private animatedImages As New List(Of Image)
Private animationTimer As Timer
Private isDraggingItem As Boolean = False
Private draggedItem As ItemInfo = Nothing
Private draggedItemIsWall As Boolean = False
Private draggedItemIsVerticalWall As Boolean = False
Private draggedItemOriginalX As Integer
Private draggedItemOriginalY As Integer
Private mouseX As Integer
Private mouseY As Integer
Private rand As New Random()
Private rightMouseDownPosition As Point
Private rightMouseDownTime As Date
Private Const CLICK_DRAG_THRESHOLD As Integer = 5 ' pixels
Private Const CLICK_DRAG_THRESHOLD_SQUARED As Integer = CLICK_DRAG_THRESHOLD * CLICK_DRAG_THRESHOLD
Public useGradient As Boolean = False
Private itemsDictionary As Dictionary(Of String, List(Of ItemInfo))
Private regionOverlayColors As New Dictionary(Of String, Color) From {
{"Region1", Color.FromArgb(128, 255, 255, 0)}, ' Yellow
{"Region2", Color.FromArgb(128, 255, 165, 0)}, ' Orange
{"Region3", Color.FromArgb(128, 173, 255, 47)}, ' Light Green
{"Region4", Color.FromArgb(128, 173, 216, 230)}, ' Light Blue
{"Region5", Color.FromArgb(128, 211, 211, 211)} ' Light Gray
}
#End Region
#Region " Constructor and Initialization "
Public Sub New()
InitializeComponent()
InitializeWalls()
InitializeTimers()
InitializeEventHandlers()
InitializeAnimationForImages()
PopulateTextureTreeView()
If Not isRestoringState Then SaveStateForUndo()
KeyPreview = True
' Load the Trigger.png image
triggerImage = Image.FromFile(Path.Combine(ImagesFolder, "Trigger.png"))
' Load the Trigger2.png image
triggerImage2 = Image.FromFile(Path.Combine(ImagesFolder, "Trigger2.png"))
' Create a smaller version of the image (70% smaller)
Dim originalWidth As Integer = triggerImage2.Width
Dim originalHeight As Integer = triggerImage2.Height
Dim newWidth As Integer = originalWidth * 0.3
Dim newHeight As Integer = originalHeight * 0.3
triggerImage2Small = New Bitmap(triggerImage2, New Size(newWidth, newHeight))
' Create a smaller version of the Trigger.png image (80% smaller)
Dim originalWidthTrigger As Integer = triggerImage.Width
Dim originalHeightTrigger As Integer = triggerImage.Height
Dim newWidthTrigger As Integer = originalWidthTrigger * 1
Dim newHeightTrigger As Integer = originalHeightTrigger * 1
triggerImageSmall = New Bitmap(triggerImage, New Size(newWidthTrigger, newHeightTrigger))
' Load the RegionIcon.png image
regionIcon = Image.FromFile(Path.Combine(IconsFolder, "RegionIcon.png"))
End Sub
Private Sub PopulateTextureTreeView()
trvTextures.Nodes.Clear() ' Clear existing nodes from the TreeView
If Directory.Exists(TextureFolder) Then ' Verify if the directory exists
' Get all directories in the specified TextureFolder
Dim directories As String() = Directory.GetDirectories(TextureFolder)
' Loop through each directory found
For Each dir As String In directories
Dim directoryName As String = Path.GetFileName(dir) ' Get the directory name
Dim parentNode As New TreeNode(directoryName) ' Create a new TreeNode for directory
' Correctly call Directory.GetFiles to fetch all .png files in the current directory
Dim files As String() = Directory.GetFiles(dir, "*.png")
For Each file As String In files
Dim fileName As String = Path.GetFileNameWithoutExtension(file) ' Get the file name without extension
Dim childNode As New TreeNode(fileName) With {
.Tag = file ' Store the full path to the file in the Tag property
}
' Add the child node to the parent node
parentNode.Nodes.Add(childNode)
Next
' Add the parent node to the TreeView
trvTextures.Nodes.Add(parentNode)
Next
End If
End Sub
Private Sub FrmDesigner_Load(sender As Object, e As EventArgs) Handles MyBase.Load
RemoveHandler cboX.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
RemoveHandler cboY.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
If cboX.Items.Contains(SQCOUNTX.ToString()) Then
cboX.SelectedItem = SQCOUNTX.ToString()
End If
If cboY.Items.Contains(SQCOUNTY.ToString()) Then
cboY.SelectedItem = SQCOUNTY.ToString()
End If
AddHandler cboX.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
AddHandler cboY.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
' Ensure one of the radio buttons is checked
rdoWalls.Checked = True
' Initialize the color pickers with the current colors
colPattern.SelectedColor = wallsColor1
colBackground.SelectedColor = wallsColor2
LoadMusic()
LoadPremades()
LoadRecentFiles()
UpdateSelections()
' Load the state from the temporary file
If File.Exists(tempFilePath) Then
Try
LoadRoomFromFile(tempFilePath)
UpdateGridSizeUI()
UpdateSelections()
Catch ex As Exception
Dim unused = MessageBox.Show("Error loading temporary file: " & ex.Message)
End Try
End If
' Reset currentFilePath to treat it as a new file
currentFilePath = ""
' Reset the window title
Text = "New Room"
' Initialize trigger colors
Dim rand As New Random()
picGame.Image = Nothing
End Sub
Friend Sub InitializeWalls()
verticalWalls = New Boolean(SQCOUNTX)() {}
verticalWallItems = New ItemInfo(SQCOUNTX)() {}
For x As Integer = 0 To SQCOUNTX
verticalWalls(x) = New Boolean(SQCOUNTY - 1) {}
verticalWallItems(x) = New ItemInfo(SQCOUNTY - 1) {}
For y As Integer = 0 To SQCOUNTY - 1
verticalWalls(x)(y) = True
verticalWallItems(x)(y) = Nothing
Next
Next
horizontalWalls = New Boolean(SQCOUNTX - 1)() {}
horizontalWallItems = New ItemInfo(SQCOUNTX - 1)() {}
For x As Integer = 0 To SQCOUNTX - 1
horizontalWalls(x) = New Boolean(SQCOUNTY) {}
horizontalWallItems(x) = New ItemInfo(SQCOUNTY) {}
For y As Integer = 0 To SQCOUNTY
horizontalWalls(x)(y) = True
horizontalWallItems(x)(y) = Nothing
Next
Next
placedItems = New ItemInfo(SQCOUNTX - 1)() {}
For x As Integer = 0 To SQCOUNTX - 1
placedItems(x) = New ItemInfo(SQCOUNTY - 1) {}
For y As Integer = 0 To SQCOUNTY - 1
placedItems(x)(y) = Nothing
Next
Next
floorsUseEdgeStyle = New Boolean(SQCOUNTX - 1)() {}
For x As Integer = 0 To SQCOUNTX - 1
floorsUseEdgeStyle(x) = New Boolean(SQCOUNTY - 1) {}
For y As Integer = 0 To SQCOUNTY - 1
floorsUseEdgeStyle(x)(y) = False
Next
Next
End Sub
Private Sub InitializeTimers()
highlightTimer = New Timer() With {.Interval = 250}
AddHandler highlightTimer.Tick, AddressOf HighlightTimer_Tick
highlightTimer.Start()
animationTimer = New Timer() With {.Interval = 100} ' Update every 100 milliseconds (10 times per second)
AddHandler animationTimer.Tick, AddressOf OnAnimationTick
animationTimer.Start()
invalidateTimer = New Timer() With {.Interval = 30} ' Update every 50 milliseconds (20 times per second)
AddHandler invalidateTimer.Tick, AddressOf InvalidateTimer_Tick
invalidateTimer.Start()
End Sub
Private Sub InitializeEventHandlers()
picGame.AllowDrop = True
For Each ctl As Control In tabFloor1.Controls
If TypeOf ctl Is PictureBox Then
AddHandler ctl.MouseEnter, AddressOf PictureBox_MouseEnter
AddHandler ctl.MouseLeave, AddressOf PictureBox_MouseLeave
End If
Next
For Each ctl As Control In tabWalls.Controls
If TypeOf ctl Is PictureBox Then
AddHandler ctl.MouseEnter, AddressOf PictureBox_MouseEnter
AddHandler ctl.MouseLeave, AddressOf PictureBox_MouseLeave
End If
Next
End Sub
Private Sub InitializeAnimationForImages()
animatedImages.Add(picBaddy1.Image)
animatedImages.Add(picBaddy2.Image)
animatedImages.Add(picBaddy3.Image)
animatedImages.Add(picBaddy4.Image)
animatedImages.Add(picLaser1.Image)
animatedImages.Add(picLaser2.Image)
animatedImages.Add(picFlipper1.Image)
animatedImages.Add(picFlipper2.Image)
animatedImages.Add(picFlipper3.Image)
animatedImages.Add(picFlipper4.Image)
animatedImages.Add(picCoin.Image)
animatedImages.Add(picGate.Image)
animatedImages.Add(picKey.Image)
animatedImages.Add(picStart.Image)
animatedImages.Add(picFinish.Image)
animatedImages.Add(picBall.Image)
animatedImages.Add(picBomb.Image)
animatedImages.Add(picWarp.Image)
animatedImages.Add(picWarp2.Image)
animatedImages.Add(picWarp3.Image)
animatedImages.Add(picVolcano.Image)
For Each img In animatedImages
If img IsNot Nothing Then
ImageAnimator.Animate(img, AddressOf OnFrameChanged)
End If
Next
End Sub
#End Region
#Region " Event Handlers "
Private Sub LoadPremades()
If Not Directory.Exists(premadesFolder) Then Dim unused1 = Directory.CreateDirectory(premadesFolder)
lstPremades.Items.Clear()
For Each file As String In Directory.GetFiles(premadesFolder, "*.Premade")
Dim unused = lstPremades.Items.Add(Path.GetFileNameWithoutExtension(file))
Next
End Sub
Private Sub LoadMusic()
If Not Directory.Exists(musicFolder) Then
Dim unused = Directory.CreateDirectory(musicFolder)
End If
Dim allowedExtensions As String() = {".mp3", ".wav"}
Dim musicFileFound As Boolean = False
Dim defaultMusicFile As String = Path.Combine(musicFolder, "The Jolly Drummer.wav")
Dim defaultVolume As Integer = 100
Dim defaultGain As Integer = 5
For Each file As String In Directory.GetFiles(musicFolder)
Dim extension As String = Path.GetExtension(file).ToLower()
If allowedExtensions.Contains(extension) Then
Dim fileNameWithoutExtension As String = Path.GetFileNameWithoutExtension(file)
Dim volume As Integer = 50
Dim gain As Integer = 10
SelectedMusic = String.Format("{0}, V:{1}, G:{2}", file, volume, gain)
lblAudio.Text = String.Format("{0}, V:{1}, G:{2}", fileNameWithoutExtension, volume, gain)
musicFileFound = True
Exit For
End If
Next
If Not musicFileFound Then
' Set default music file, volume, and gain
SelectedMusic = String.Format("{0}, V:{1}, G:{2}", defaultMusicFile, defaultVolume, defaultGain)
lblAudio.Text = String.Format("{0}, V:{1}, G:{2}", Path.GetFileNameWithoutExtension(defaultMusicFile), defaultVolume, defaultGain)
End If
End Sub
Private Sub OnAnimationTick(sender As Object, e As EventArgs)
For Each img In animatedImages
ImageAnimator.UpdateFrames(img)
Next
End Sub
Private Sub OnFrameChanged(o As Object, e As EventArgs)
End Sub
Private Sub HighlightTimer_Tick(sender As Object, e As EventArgs)
highlightColor = If(highlightColor = Color.Gray, Color.White, Color.Gray)
End Sub
Private Sub InvalidateTimer_Tick(sender As Object, e As EventArgs)
picGame.Invalidate()
End Sub
Private Function IsVerticalWallOuterBorder(x As Integer) As Boolean
Return x = 0 OrElse x = SQCOUNTX
End Function
Private Function IsHorizontalWallOuterBorder(y As Integer) As Boolean
Return y = 0 OrElse y = SQCOUNTY
End Function
Private Function GetItemName(imageKey As String) As String
Select Case imageKey
Case "picBlock1"
Return "Block"
Case "picBlock2"
Return "Block2"
Case "picBaddy1"
Return "Baddy1"
Case "picBaddy2"
Return "Baddy2"
Case "picLaser1"
Return "Laser1"
Case "picLaser2"
Return "Laser2"
Case "picFlipper1"
Return "Flipper1"
Case "picFlipper2"
Return "Flipper2"
Case "picFlipper3"
Return "Flipper3"
Case "picFlipper4"
Return "Flipper4"
Case "picBaddy3"
Return "Baddy3"
Case "picBaddy4"
Return "Baddy4"
Case "picCoin"
Return "Coin"
Case "picGate"
Return "Gate"
Case "picKey"
Return "Key"
Case "picStart"
Return "Start"
Case "picFinish"
Return "Finish"
Case "picBlockStopper1"
Return "BlockStopper"
Case "picBall"
Return "Ball"
Case "picBlockSwitch"
Return "BlockSwitch"
Case "picBomb"
Return "Bomb"
Case "picWarp"
Return "Warp"
Case "picWarp2"
Return "Warp2"
Case "picWarp3"
Return "Warp3"
Case "picVolcano"
Return "Volcano"
Case Else
Return "Unknown"
End Select
End Function
Private Sub RemoveEdgeStyleAtMousePosition(mouseX As Integer, mouseY As Integer)
UpdateHighlight(mouseX, mouseY)
If Not highlightedWallX AndAlso Not highlightedWallY Then
If highlightedX >= 0 AndAlso highlightedX < SQCOUNTX AndAlso highlightedY >= 0 AndAlso highlightedY < SQCOUNTY Then
floorsUseEdgeStyle(highlightedX)(highlightedY) = False
End If
End If
End Sub
Public Sub UpdateGridSizeUI()
RemoveHandler cboX.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
RemoveHandler cboY.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
If Not cboX.Items.Contains(SQCOUNTX.ToString()) Then
Dim unused1 = cboX.Items.Add(SQCOUNTX.ToString())
End If
cboX.SelectedItem = SQCOUNTX.ToString()
If Not cboY.Items.Contains(SQCOUNTY.ToString()) Then
Dim unused = cboY.Items.Add(SQCOUNTY.ToString())
End If
cboY.SelectedItem = SQCOUNTY.ToString()
AddHandler cboX.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
AddHandler cboY.SelectedIndexChanged, AddressOf CboX_SelectedIndexChanged
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
End Sub
Private Sub CalculateSquareSizes(clientWidth As Integer, clientHeight As Integer)
If SQCOUNTX <= 0 OrElse SQCOUNTY <= 0 Then
Throw New InvalidOperationException("Grid dimensions must be greater than zero.")
End If
SQSizeX = (clientWidth - (2 * INDENT) - ((SQCOUNTX + 1) * WALL_THICKNESS)) \ SQCOUNTX
SQSizeY = (clientHeight - (2 * INDENT) - ((SQCOUNTY + 1) * WALL_THICKNESS)) \ SQCOUNTY
End Sub
#End Region
#Region " Design "
Private Sub LstPremades_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstPremades.SelectedIndexChanged
TurnOffSelectionMode()
If lstPremades.SelectedIndex >= 0 Then
If Not isRestoringState Then SaveStateForUndo()
Dim selectedPremade As String = lstPremades.SelectedItem.ToString()
LoadSettingsFromFile(Path.Combine(premadesFolder, selectedPremade & ".Premade"))
UpdateSelections()
End If
End Sub
Private Sub BtnSavePremade_Click(sender As Object, e As EventArgs) Handles btnSavePremade.Click
TurnOffSelectionMode()
Dim saveDialog As New SaveFileDialog() With {
.InitialDirectory = premadesFolder,
.Filter = "Premade Files (*.Premade)|*.Premade",
.DefaultExt = "Premade",
.AddExtension = True,
.Title = "Save Premade"
}
If saveDialog.ShowDialog() = DialogResult.OK Then
SaveSettingsToFile(saveDialog.FileName)
LoadPremades()
End If
End Sub
Private Sub LstHatchstyles_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstHatchstyles.SelectedIndexChanged
TurnOffSelectionMode()
If lstHatchstyles.SelectedItem IsNot Nothing Then
Dim selectedHatchStyleName As String = lstHatchstyles.SelectedItem.ToString()
Dim selectedHatchStyle As HatchStyle = [Enum].Parse(GetType(HatchStyle), selectedHatchStyleName)
If rdoFloors.Checked Then
floorsHatchStyle = selectedHatchStyle
ElseIf rdoWalls.Checked Then
wallsHatchStyle = selectedHatchStyle
End If
If Not isRestoringState Then SaveStateForUndo()
End If
End Sub
Private Sub btnRandom_Click(sender As Object, e As EventArgs) Handles btnRandom.Click
If lstHatchstyles.Items.Count > 0 Then
Dim random As New Random()
Dim randomIndex As Integer = random.Next(lstHatchstyles.Items.Count)
lstHatchstyles.SelectedIndex = randomIndex
End If
If Not isRestoringState Then SaveStateForUndo()
End Sub
Private Sub BtnAll_Click(sender As Object, e As EventArgs) Handles BtnAll.Click
TurnOffSelectionMode()
If Not isRestoringState Then SaveStateForUndo()
RandomizeWalls()
RandomizeFloors()
End Sub
Private Sub BtnWalls_Click(sender As Object, e As EventArgs) Handles BtnWall.Click
TurnOffSelectionMode()
If Not isRestoringState Then SaveStateForUndo()
RandomizeWalls()
End Sub
Private Sub BtnFloors_Click(sender As Object, e As EventArgs) Handles BtnFloor.Click
TurnOffSelectionMode()
If Not isRestoringState Then SaveStateForUndo()
RandomizeFloors()
End Sub
Private Sub RandomizeWalls()
wallsColor1 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))
wallsColor2 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))
Dim hatchStyles As Array = [Enum].GetValues(GetType(HatchStyle))
wallsHatchStyle = CType(hatchStyles.GetValue(rand.Next(hatchStyles.Length)), HatchStyle)
UpdateSelections()
End Sub
Private Sub RandomizeFloors()
floorsColor1 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))
floorsColor2 = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256))
Dim hatchStyles As Array = [Enum].GetValues(GetType(HatchStyle))
floorsHatchStyle = CType(hatchStyles.GetValue(rand.Next(hatchStyles.Length)), HatchStyle)
UpdateSelections()
End Sub
Private Sub UpdateSelections()
If rdoWalls.Checked Then
lstHatchstyles.SelectedItem = wallsHatchStyle.ToString()
ElseIf rdoFloors.Checked Then
lstHatchstyles.SelectedItem = floorsHatchStyle.ToString()
ElseIf rdoEdge.Checked Then
lstHatchstyles.SelectedItem = wallsHatchStyle.ToString()
End If
cboStyleChoice.Enabled = rdoFloors.Checked
lstHatchstyles.Enabled = Not rdoFloors.Checked OrElse Not useGradient
If cboStyleChoice.Items.Count > 0 Then
cboStyleChoice.SelectedIndex = If(useGradient, cboStyleChoice.Items.IndexOf("Gradient"), cboStyleChoice.Items.IndexOf("HatchStyle"))
End If
' Update the color pickers to reflect the current colors
UpdateColorPickers()
End Sub
Private Sub RdoWalls_CheckedChanged(sender As Object, e As EventArgs) Handles rdoWalls.CheckedChanged
TurnOffSelectionMode()
If rdoWalls.Checked Then
UpdateSelections()
End If
End Sub
Private Sub RdoFloors_CheckedChanged(sender As Object, e As EventArgs) Handles rdoFloors.CheckedChanged
TurnOffSelectionMode()
If rdoFloors.Checked Then
UpdateSelections()
End If
End Sub
Private Sub RdoEdge_CheckedChanged(sender As Object, e As EventArgs) Handles rdoEdge.CheckedChanged
TurnOffSelectionMode()
If rdoEdge.Checked Then
UpdateSelections()
End If
End Sub
Private Sub CboStyleChoice_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboStyleChoice.SelectedIndexChanged
TurnOffSelectionMode()
useGradient = cboStyleChoice.SelectedItem.ToString() = "Gradient"
lstHatchstyles.Enabled = Not useGradient
' Redraw the picGame control
End Sub
Private Sub CboX_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboX.SelectedIndexChanged, cboY.SelectedIndexChanged
TurnOffSelectionMode()
UpdateGridSize()
End Sub
Private Sub UpdateGridSize()
Dim newSQCOUNTX As Integer
Dim newSQCOUNTY As Integer
If Integer.TryParse(cboX.SelectedItem?.ToString(), newSQCOUNTX) AndAlso Integer.TryParse(cboY.SelectedItem?.ToString(), newSQCOUNTY) Then
If Not isRestoringState Then SaveStateForUndo()
Dim oldSQCOUNTX As Integer = SQCOUNTX
Dim oldSQCOUNTY As Integer = SQCOUNTY
SQCOUNTX = newSQCOUNTX
SQCOUNTY = newSQCOUNTY
useGradient = cboStyleChoice.SelectedItem?.ToString() = "Gradient"
ResizeArrays(oldSQCOUNTX, oldSQCOUNTY, SQCOUNTX, SQCOUNTY)
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
highlightedX = -1
highlightedY = -1
isMouseInsideGrid = False
selectionRectangle = Rectangle.Empty
End If
End Sub
Friend Sub ResizeArrays(oldX As Integer, oldY As Integer, newX As Integer, newY As Integer)
verticalWalls = ResizeJaggedArray(verticalWalls, oldX + 1, oldY - 1, newX + 1, newY - 1, True)
verticalWallItems = ResizeJaggedArray(verticalWallItems, oldX + 1, oldY - 1, newX + 1, newY - 1, False)
horizontalWalls = ResizeJaggedArray(horizontalWalls, oldX - 1, oldY + 1, newX - 1, newY + 1, True)
horizontalWallItems = ResizeJaggedArray(horizontalWallItems, oldX - 1, oldY + 1, newX - 1, newY + 1, False)
placedItems = ResizeJaggedArray(placedItems, oldX - 1, oldY - 1, newX - 1, newY - 1, False)
floorsUseEdgeStyle = ResizeJaggedArray(floorsUseEdgeStyle, oldX - 1, oldY - 1, newX - 1, newY - 1, False)
FillBorderWalls()
End Sub
Private Function ResizeJaggedArray(Of T)(sourceArray As T()(), oldSizeX As Integer, oldSizeY As Integer, newSizeX As Integer, newSizeY As Integer, initializeValue As Boolean) As T()()
Dim newArray As T()() = New T(newSizeX)() {}
For x As Integer = 0 To newSizeX
newArray(x) = New T(newSizeY) {}
For y As Integer = 0 To newSizeY
newArray(x)(y) = If(x < sourceArray.Length AndAlso y < sourceArray(x).Length,
sourceArray(x)(y),
If(GetType(T) Is GetType(Boolean) AndAlso initializeValue, CType(Convert.ChangeType(True, GetType(T)), T), Nothing))
Next
Next
Return newArray
End Function
#End Region
#Region " Mouse Up, Down, Move "
Private Sub PicGame_MouseDown(sender As Object, e As MouseEventArgs) Handles picGame.MouseDown
If SelectionMode Then
HandleSelectionMode(e)
Return
End If
If e.Button = MouseButtons.Left Then
' Handle actions when the left mouse button is clicked
HandleGateClicked(e.X, e.Y)
HandleBaddyClicked(e.X, e.Y) ' Ensure this line is added
' Start the selection process
isSelecting = True
selectionStartPoint = e.Location
selectionEndPoint = e.Location
selectionRectangle = GetRectangle(selectionStartPoint, selectionEndPoint)
' Reset selection data only if not in copy-paste operation
If Not isCopying Then
selectionData = Nothing
selectionStartCell = New Point(-1, -1)
copiedSelectionData = Nothing
copiedSelectionType = ""
End If
' Check if selection starts from a wall or the space between walls
Dim offsetX As Integer = (selectionStartPoint.X - INDENT) Mod (SQSizeX + WALL_THICKNESS)
Dim offsetY As Integer = (selectionStartPoint.Y - INDENT) Mod (SQSizeY + WALL_THICKNESS)
selectionStartedOnWall = (offsetX < WALL_THICKNESS) OrElse (offsetY < WALL_THICKNESS)
' Adjust the selection start point to snap to the grid
selectionStartPoint = GetGridAlignedPoint(selectionStartPoint)
' Determine if the user starts the selection on a floor or a wall
Dim clickedX As Integer = (e.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim clickedY As Integer = (e.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
If clickedX >= 0 AndAlso clickedX < SQCOUNTX AndAlso clickedY >= 0 AndAlso clickedY < SQCOUNTY Then
If Not IsMouseOverWall(e.X, e.Y) Then
' The starting selection is on the floor
SnapToFloor = True
Else
' Starting on a wall
SnapToFloor = False
End If
End If
' Check if the click is on a region icon
If chkShowRegions.Checked Then
For Each region As RegionInfo In regions
Dim iconRect As New Rectangle(
INDENT + (region.Rectangle.X * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
INDENT + (region.Rectangle.Y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
regionIcon.Width,
regionIcon.Height
)
If iconRect.Contains(e.Location) Then
' Select the entire region
selectionRectangle = region.Rectangle
selectionStartCell = New Point(region.Rectangle.X, region.Rectangle.Y)
isSelectionReadyToDrag = True
ctmMenu.Show(picGame, e.Location)
Return
End If
Next
End If
ElseIf e.Button = MouseButtons.Right Then
' Hide properties displays
UcBaddyProps.Visible = False
krKeys.Visible = False
End If
If isSelectionReadyToDrag Then
If selectionRectangle.Contains(e.Location) Then
If e.Button = MouseButtons.Left Then
SaveStateForUndo()
isDraggingSelection = True
selectionOffset = New Point(e.X - selectionRectangle.Location.X, e.Y - selectionRectangle.Location.Y)
selectionStartCell = New Point(
(selectionRectangle.Location.X - INDENT) \ (SQSizeX + WALL_THICKNESS),
(selectionRectangle.Location.Y - INDENT) \ (SQSizeY + WALL_THICKNESS))
picGame.Capture = True
Cursor = Cursors.SizeAll
ElseIf e.Button = MouseButtons.Right Then
' Show context menu if right-clicking inside the selection
Dim menuPosition As Point = e.Location
ctmMenu.Show(picGame, menuPosition)
End If
End If
ElseIf isInSelectionMode Then
' Start selecting a new area
If e.Button = MouseButtons.Left Then
isSelecting = True
selectionStartPoint = e.Location
selectionEndPoint = e.Location
selectionRectangle = GetRectangle(selectionStartPoint, selectionEndPoint)
' Reset selection data only if not in copy-paste operation
If Not isCopying Then
selectionData = Nothing
selectionStartCell = New Point(-1, -1)
copiedSelectionData = Nothing
copiedSelectionType = ""
End If
' Reset the cycle
isSelectionExpandedToWalls = False
isSelectionExpandedToFloors = False
' Adjust the selection start point to snap to the grid
selectionStartPoint = GetGridAlignedPoint(selectionStartPoint)
ElseIf e.Button = MouseButtons.Right Then
If selectionRectangle.Contains(e.Location) Then
Dim menuPosition As Point = e.Location
ctmMenu.Show(picGame, menuPosition)
End If
Else
TurnOffSelectionMode()
End If
Else
' Normal mouse down processing
If e.Button = MouseButtons.Right Then
isRightMouseDown = True
rightMouseDownPosition = e.Location
rightMouseDownTime = Date.Now
If Not isActionInProgress Then
isActionInProgress = True
SaveStateForUndo()
End If
ElseIf e.Button = MouseButtons.Left Then
isLeftMouseDown = True
UpdateHighlight(e.X, e.Y)
Dim itemPickedUp As Boolean = False
If isMouseInsideGrid Then
If Not isActionInProgress Then
isActionInProgress = True
SaveStateForUndo()
End If
If highlightedWallX Then
' Handle vertical wall item pickup
If highlightedX >= 0 AndAlso highlightedX < verticalWallItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWallItems(0).Length Then
If verticalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
isDraggingItem = True
draggedItem = verticalWallItems(highlightedX)(highlightedY)
draggedItemIsWall = True
draggedItemIsVerticalWall = True
draggedItemIsVerticalWall = True
draggedItemOriginalX = highlightedX
draggedItemOriginalY = highlightedY
verticalWallItems(highlightedX)(highlightedY) = Nothing
verticalWalls(highlightedX)(highlightedY) = True
picGame.Capture = True
itemPickedUp = True
End If
End If
ElseIf highlightedWallY Then
' Handle horizontal wall item pickup
If highlightedX >= 0 AndAlso highlightedX < horizontalWallItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWallItems(0).Length Then
If horizontalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
isDraggingItem = True
draggedItem = horizontalWallItems(highlightedX)(highlightedY)
draggedItemIsWall = True
draggedItemIsVerticalWall = False
draggedItemOriginalX = highlightedX
draggedItemOriginalY = highlightedY
horizontalWallItems(highlightedX)(highlightedY) = Nothing
horizontalWalls(highlightedX)(highlightedY) = True
picGame.Capture = True
itemPickedUp = True
End If
End If
Else
' Handle floor item pickup
If highlightedX >= 0 AndAlso highlightedX < placedItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < placedItems(0).Length Then
If placedItems(highlightedX)(highlightedY) IsNot Nothing Then
isDraggingItem = True
draggedItem = placedItems(highlightedX)(highlightedY)
draggedItemIsWall = False
draggedItemOriginalX = highlightedX
draggedItemOriginalY = highlightedY
placedItems(highlightedX)(highlightedY) = Nothing
picGame.Capture = True
itemPickedUp = True
End If
End If
End If
If itemPickedUp Then
redoStack.Clear()
Else
' Add wall or edge style handling
If rdoEdge.Checked Then
isLeftMouseDown = True
SetEdgeStyleAtMousePosition(e.X, e.Y)
Else
isLeftMouseDown = True
AddWallAtMousePosition(e.X, e.Y)
End If
End If
End If
End If
End If
' Check if the krKeys control is visible and the click is outside the cell with the gate
If krKeys.Visible And IsOnGate = False Then
Dim clickedX As Integer = (e.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim clickedY As Integer = (e.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
If clickedX >= 0 AndAlso clickedX < placedItems.Length AndAlso
clickedY >= 0 AndAlso clickedY < placedItems(0).Length Then
Dim clickedItem As ItemInfo = placedItems(clickedX)(clickedY)
If clickedItem Is Nothing OrElse clickedItem.ImageKey <> "picGate" Then
krKeys.Visible = False
End If
Else
krKeys.Visible = False
End If
End If
' Check if the UcBaddyProps control is visible and the click is outside the cell with the Baddy
If UcBaddyProps.Visible AndAlso Not IsOnBaddy Then
Dim clickedX As Integer = (e.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim clickedY As Integer = (e.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
If clickedX >= 0 AndAlso clickedX < placedItems.Length AndAlso
clickedY >= 0 AndAlso clickedY < placedItems(0).Length Then
Dim clickedItem As ItemInfo = placedItems(clickedX)(clickedY)
If Not clickedItem.ImageKey.StartsWith("picBaddy") Then
UcBaddyProps.Visible = False
End If
Else
UcBaddyProps.Visible = False
End If
End If
End Sub
Private Sub PicGame_MouseMove(sender As Object, e As MouseEventArgs) Handles picGame.MouseMove
isCursorOnPicGame = True
If isDraggingSelection Then
' Existing code for dragging selection
If isCopying Then
If copiedSelectionData Is Nothing Then
Return
End If
Else
If selectionData Is Nothing Then
CaptureSelectionData()
End If
End If
' Calculate new cell positions
Dim newX As Integer = e.X - selectionOffset.X
Dim newY As Integer = e.Y - selectionOffset.Y
Dim cellX As Integer = (newX - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim cellY As Integer = (newY - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Ensure cellX and cellY are within bounds
If isCopying Then
cellX = Math.Max(0, Math.Min(SQCOUNTX - copiedSelectionData.selectionWidth, cellX))
cellY = Math.Max(0, Math.Min(SQCOUNTY - copiedSelectionData.selectionHeight, cellY))
selectionRectangle.Width = copiedSelectionData.selectionWidth * (SQSizeX + WALL_THICKNESS) ' Remove - WALL_THICKNESS
selectionRectangle.Height = copiedSelectionData.selectionHeight * (SQSizeY + WALL_THICKNESS) ' Remove - WALL_THICKNESS
Else
cellX = Math.Max(0, Math.Min(SQCOUNTX - selectionData.selectionWidth, cellX))
cellY = Math.Max(0, Math.Min(SQCOUNTY - selectionData.selectionHeight, cellY))
selectionRectangle.Width = (selectionData.selectionWidth * (SQSizeX + WALL_THICKNESS)) - WALL_THICKNESS
selectionRectangle.Height = (selectionData.selectionHeight * (SQSizeY + WALL_THICKNESS)) - WALL_THICKNESS
End If
' Update selection rectangle position
selectionRectangle.X = INDENT + (cellX * (SQSizeX + WALL_THICKNESS))
selectionRectangle.Y = INDENT + (cellY * (SQSizeY + WALL_THICKNESS))
' Store cell positions for use in MouseUp
draggedSelectionCellX = cellX
draggedSelectionCellY = cellY
ElseIf isDraggingItem Then
' Update the mouse position to the current cursor position
mouseX = e.X
mouseY = e.Y
' Snap the item to the nearest wall and center it
UpdateHighlight(e.X, e.Y)
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
mouseX = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) + 4
mouseY = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeY \ 2)
Else
mouseX = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeX \ 2)
mouseY = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) + 4
End If
Else
mouseX = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeX \ 2)
mouseY = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeY \ 2)
End If
ElseIf isInSelectionMode Then
If isSelecting Then
Dim newEndPoint = e.Location
' Adjust the snap behavior based on where we started the selection
If SnapToFloor Then
selectionStartPoint = GetGridAlignedPoint(selectionStartPoint)
newEndPoint = GetGridAlignedPoint(newEndPoint, isFloor:=True)
Else
selectionStartPoint = GetGridAlignedPoint(selectionStartPoint, isWall:=True)
newEndPoint = GetGridAlignedPoint(newEndPoint, isWall:=True)
End If
selectionRectangle = GetRectangle(selectionStartPoint, newEndPoint)
End If
Else
UpdateHighlight(e.X, e.Y)
If isRightMouseDown Then
If rdoEdge.Checked Then
If isMouseInsideGrid Then
RemoveEdgeStyleAtMousePosition(e.X, e.Y)
End If
Else
Dim deltaX As Integer = e.X - rightMouseDownPosition.X
Dim deltaY As Integer = e.Y - rightMouseDownPosition.Y
Dim distanceSquared As Integer = (deltaX * deltaX) + (deltaY * deltaY)
If distanceSquared > CLICK_DRAG_THRESHOLD_SQUARED Then
RemoveObjectAtMousePosition(e.X, e.Y, removeWalls:=True, removeItems:=False)
End If
End If
End If
If isLeftMouseDown Then
If rdoEdge.Checked Then
If isMouseInsideGrid Then
SetEdgeStyleAtMousePosition(e.X, e.Y)
End If
Else
AddWallAtMousePosition(e.X, e.Y)
End If
End If
End If
UpdateStatusBar(e.X, e.Y)
End Sub
Private Sub PicGame_MouseUp(sender As Object, e As MouseEventArgs) Handles picGame.MouseUp
If isDraggingSelection Then
' Completing selection dragging
If e.Button = MouseButtons.Left Then
' Save the state before modifying the data model
If Not isRestoringState Then
SaveStateForUndo()
End If
isDraggingSelection = False
picGame.Capture = False
Cursor = Cursors.Default
If selectionRectangle.IsEmpty Then
Return
End If
' Use the dragged selection cell coordinates calculated in MouseMove
' These represent the top-left corner where the paste should occur
If draggedSelectionCellX >= 0 AndAlso draggedSelectionCellY >= 0 Then
PasteSelectionDataTo(New Point(draggedSelectionCellX, draggedSelectionCellY), False, copiedSelectionType = "Edge")
End If
isCopying = False
isSelectionReadyToDrag = False
' Reset selection-related variables to prevent issues with future operations
selectionData = Nothing
selectionStartCell = New Point(-1, -1)
copiedSelectionData = Nothing
copiedSelectionType = ""
isCopying = False
isSelectionReadyToDrag = False
isDraggingSelection = False
' Clear the redo stack since we've made a new change
redoStack.Clear()
End If
ElseIf isInSelectionMode AndAlso isSelecting Then
If e.Button = MouseButtons.Left Then
' Finalizing the selection rectangle
isSelecting = False
selectionEndPoint = e.Location
' Always snap to the wall for both start and end points
selectionStartPoint = GetGridAlignedPoint(selectionStartPoint, isWall:=True)
selectionEndPoint = GetGridAlignedPoint(selectionEndPoint, isWall:=True)
selectionRectangle = GetRectangle(selectionStartPoint, selectionEndPoint)
' Reset selection-related variables
selectionData = Nothing
selectionStartCell = New Point(-1, -1)
copiedSelectionData = Nothing
copiedSelectionType = ""
isCopying = False
isSelectionReadyToDrag = False
isDraggingSelection = False
If selectionRectangle.IsEmpty Then
TurnOffSelectionMode()
End If
End If
Else
' Normal mouse up processing
If e.Button = MouseButtons.Left Then
If isDraggingItem Then
' Save the state before modifying the data model
If Not isRestoringState Then
SaveStateForUndo()
End If
isDraggingItem = False
picGame.Capture = False
Cursor.Current = Cursors.Default
' Snap the item to the grid position
UpdateHighlight(e.X, e.Y)
If isMouseInsideGrid Then
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
If highlightedX >= 0 AndAlso highlightedX < verticalWallItems.Length AndAlso
verticalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWallItems(0).Length Then
If Not IsVerticalWallConnectedToEdge(New Point(highlightedX, highlightedY)) OrElse IsFlipperItem(draggedItem.ImageKey) Then
verticalWallItems(highlightedX)(highlightedY) = draggedItem
verticalWalls(highlightedX)(highlightedY) = False
Else
ReturnItemToOriginalLocation()
End If
End If
Else
If highlightedX >= 0 AndAlso highlightedX < horizontalWallItems.Length AndAlso
horizontalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWallItems(0).Length Then
If Not IsHorizontalWallConnectedToEdge(New Point(highlightedX, highlightedY)) OrElse IsFlipperItem(draggedItem.ImageKey) Then
horizontalWallItems(highlightedX)(highlightedY) = draggedItem
horizontalWalls(highlightedX)(highlightedY) = False
Else
ReturnItemToOriginalLocation()
End If
End If
End If
Else
If highlightedX >= 0 AndAlso highlightedX < placedItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < placedItems(0).Length Then
placedItems(highlightedX)(highlightedY) = draggedItem
End If
End If
End If
' Clear redo stack since we've made a new change
redoStack.Clear()
' Invalidate the picGame control to refresh the display
End If
isLeftMouseDown = False
isActionInProgress = False
ElseIf e.Button = MouseButtons.Right Then
If isRightMouseDown Then
isRightMouseDown = False
If rdoEdge.Checked Then
UpdateHighlight(e.X, e.Y)
If isMouseInsideGrid Then
If Not highlightedWallX AndAlso Not highlightedWallY Then
If highlightedX >= 0 AndAlso highlightedX < SQCOUNTX AndAlso highlightedY >= 0 AndAlso highlightedY < SQCOUNTY Then
floorsUseEdgeStyle(highlightedX)(highlightedY) = False
End If
End If
End If
Else
Dim deltaX As Integer = e.X - rightMouseDownPosition.X
Dim deltaY As Integer = e.Y - rightMouseDownPosition.Y
Dim distanceSquared As Integer = (deltaX * deltaX) + (deltaY * deltaY)
If distanceSquared < CLICK_DRAG_THRESHOLD_SQUARED Then
RemoveObjectAtMousePosition(e.X, e.Y, removeWalls:=False, removeItems:=True)
End If
End If
isActionInProgress = False
End If
' Check if the right-click is outside the selected area
If isInSelectionMode AndAlso Not selectionRectangle.Contains(e.Location) Then
TurnOffSelectionMode()
End If
End If
End If
End Sub
Private Sub Form_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
Dim screenPos As Point = PointToScreen(New Point(e.X, e.Y))
Dim picGameClientPoint As Point = picGame.PointToClient(screenPos)
isCursorOnPicGame = picGame.ClientRectangle.Contains(picGameClientPoint)
If isDraggingItem Then
mouseX = picGameClientPoint.X
mouseY = picGameClientPoint.Y
If isCursorOnPicGame Then
UpdateHighlight(mouseX, mouseY)
isMouseInsideGrid = True
' Snap the item to the nearest wall and center it
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
mouseX = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) + 4
mouseY = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeY \ 2)
Else
mouseX = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeX \ 2)
mouseY = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) + 4
End If
Else
mouseX = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeX \ 2)
mouseY = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (SQSizeY \ 2)
End If
Else
isMouseInsideGrid = False
End If
' Invalidate only the picGame control
End If
' Force the highlight color to toggle based on mouse movement
Dim currentTime As Date = Date.Now
If (currentTime - lastMouseMoveTime).TotalMilliseconds >= DEBOUNCE_INTERVAL Then
highlightColor = If(highlightColor = Color.Black, Color.White, Color.Black)
lastMouseMoveTime = currentTime
End If
UpdateStatusBar(e.X, e.Y)
End Sub
Private Sub Form_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
If isDraggingItem AndAlso e.Button = MouseButtons.Left Then
' Before modifying the data model, save the state
If Not isRestoringState Then
SaveStateForUndo()
End If
isDraggingItem = False
Capture = False
Cursor.Current = Cursors.Default
Dim screenPos As Point = PointToScreen(New Point(e.X, e.Y))
Dim picGameClientPoint As Point = picGame.PointToClient(screenPos)
If picGame.ClientRectangle.Contains(picGameClientPoint) Then
mouseX = picGameClientPoint.X
mouseY = picGameClientPoint.Y
UpdateHighlight(mouseX, mouseY)
If isMouseInsideGrid Then
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
If highlightedX >= 0 AndAlso highlightedX < verticalWallItems.Length AndAlso
verticalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWallItems(0).Length Then
If Not IsVerticalWallConnectedToEdge(New Point(highlightedX, highlightedY)) OrElse IsFlipperItem(draggedItem.ImageKey) Then
verticalWallItems(highlightedX)(highlightedY) = draggedItem
verticalWalls(highlightedX)(highlightedY) = False
Else
ReturnItemToOriginalLocation()
End If
End If
Else
If highlightedX >= 0 AndAlso highlightedX < horizontalWallItems.Length AndAlso
horizontalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWallItems(0).Length Then
If Not IsHorizontalWallConnectedToEdge(New Point(highlightedX, highlightedY)) OrElse IsFlipperItem(draggedItem.ImageKey) Then
horizontalWallItems(highlightedX)(highlightedY) = draggedItem
horizontalWalls(highlightedX)(highlightedY) = False
Else
ReturnItemToOriginalLocation()
End If
End If
End If
Else
' Existing code for placing non-wall items
If highlightedX >= 0 AndAlso highlightedX < placedItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < placedItems(0).Length Then
placedItems(highlightedX)(highlightedY) = draggedItem
End If
End If
Else
ReturnItemToOriginalLocation()
End If
Else
ReturnItemToOriginalLocation()
End If
draggedItem = Nothing
If isActionInProgress Then
isActionInProgress = False
redoStack.Clear()
End If
redoStack.Clear()
End If
End Sub
Private Sub PicBlock_MouseDown(sender As Object, e As MouseEventArgs) Handles picBlock1.MouseDown, picBlock2.MouseDown, picBaddy1.MouseDown, picBaddy2.MouseDown, picLaser1.MouseDown, picLaser2.MouseDown, picFlipper1.MouseDown, picFlipper2.MouseDown, picFlipper3.MouseDown, picFlipper4.MouseDown, picBaddy3.MouseDown, picBaddy4.MouseDown, picCoin.MouseDown, picGate.MouseDown, picKey.MouseDown, picStart.MouseDown, picFinish.MouseDown, picBlockStopper1.MouseDown, picBall.MouseDown, picBlockSwitch.MouseDown, picBomb.MouseDown, picWarp.MouseDown, picWarp2.MouseDown, picWarp3.MouseDown, picVolcano.MouseDown
TurnOffSelectionMode()
Dim pic = CType(sender, PictureBox)
isDraggingItem = True
' Create a new PlacedItem with the ImageKey
draggedItem = New ItemInfo(pic.Name, New Point(0, 0), Guid.NewGuid.ToString, isDoodad:=IsDoodadItem(pic.Name))
' Determine if it's a wall item
draggedItemIsWall = IsVerticalItem(pic.Name) OrElse IsHorizontalItem(pic.Name)
draggedItemIsVerticalWall = IsVerticalItem(pic.Name)
' Since it's being dragged from the toolbox, there is no original position
draggedItemOriginalX = -1
draggedItemOriginalY = -1
' Capture the mouse events at the form level
Capture = True
Cursor.Current = Cursors.Hand
' Initialize the mouse position to the current cursor position
Dim mousePos = picGame.PointToClient(Cursor.Position)
mouseX = mousePos.X
mouseY = mousePos.Y
End Sub
#End Region
#Region " Mouse Helpers "
Private Function GetGridAlignedPoint(point As Point, Optional isFloor As Boolean = False, Optional isWall As Boolean = False) As Point
Dim cellX As Integer = (point.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim cellY As Integer = (point.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Ensure we align correctly based on the type of snapping
If isFloor Then
cellX = Math.Max(0, Math.Min(SQCOUNTX - 1, cellX))
cellY = Math.Max(0, Math.Min(SQCOUNTY - 1, cellY))
ElseIf isWall Then
' To get wall or wall intersection points, adjust this computation
cellX = Math.Max(0, Math.Min(SQCOUNTX, cellX)) ' Adjust bounds for wall snapping
cellY = Math.Max(0, Math.Min(SQCOUNTY, cellY)) ' Adjust bounds for wall snapping
End If
Dim alignedX As Integer = INDENT + (cellX * (SQSizeX + WALL_THICKNESS))
Dim alignedY As Integer = INDENT + (cellY * (SQSizeY + WALL_THICKNESS))
Return New Point(alignedX, alignedY)
End Function
Private Function IsMouseOverWall(mouseX As Integer, mouseY As Integer) As Boolean
' You can iterate over the vertical and horizontal walls to determine if the mouse is over a wall
UpdateHighlight(mouseX, mouseY)
Return highlightedWallX OrElse highlightedWallY
End Function
Private Function AdjustSelectionRectangleToWalls(rect As Rectangle) As Rectangle
' Determine starting and ending points for cell snapping
Dim startCellX As Integer = (rect.X - INDENT + (WALL_THICKNESS \ 2)) \ (SQSizeX + WALL_THICKNESS)
Dim startCellY As Integer = (rect.Y - INDENT + (WALL_THICKNESS \ 2)) \ (SQSizeY + WALL_THICKNESS)
Dim endCellX As Integer = (rect.Right - INDENT - (WALL_THICKNESS \ 2) - 1) \ (SQSizeX + WALL_THICKNESS)
Dim endCellY As Integer = (rect.Bottom - INDENT - (WALL_THICKNESS \ 2) - 1) \ (SQSizeY + WALL_THICKNESS)
' Make sure to stay within grid bounds
startCellX = Math.Max(0, Math.Min(SQCOUNTX - 1, startCellX))
startCellY = Math.Max(0, Math.Min(SQCOUNTY - 1, startCellY))
endCellX = Math.Max(0, Math.Min(SQCOUNTX - 1, endCellX))
endCellY = Math.Max(0, Math.Min(SQCOUNTY - 1, endCellY))
' Adjust rectangle to snap to walls' positions
If highlightedWallX OrElse highlightedWallY Then
' Adjust snap position for walls
Dim adjustedRect As New Rectangle(
INDENT + (startCellX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
INDENT + (startCellY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
((endCellX - startCellX + 1) * (SQSizeX + WALL_THICKNESS)) - WALL_THICKNESS,
((endCellY - startCellY + 1) * (SQSizeY + WALL_THICKNESS)) - WALL_THICKNESS
)
Return adjustedRect
Else
' Otherwise, follow the standard floor area snapping.
Dim adjustedRect As New Rectangle(
INDENT + (startCellX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
INDENT + (startCellY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
((endCellX - startCellX + 1) * (SQSizeX + WALL_THICKNESS)) - WALL_THICKNESS,
((endCellY - startCellY + 1) * (SQSizeY + WALL_THICKNESS)) - WALL_THICKNESS
)
Return adjustedRect
End If
End Function
Private Sub HandleBaddyClicked(mouseX As Integer, mouseY As Integer)
' Calculate the cell coordinates based on the mouse position
Dim clickedX As Integer = (mouseX - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim clickedY As Integer = (mouseY - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Check if the clicked cell contains a Baddy
If clickedX >= 0 AndAlso clickedX < placedItems.Length AndAlso clickedY >= 0 AndAlso clickedY < placedItems(0).Length Then
Dim clickedItem As ItemInfo = placedItems(clickedX)(clickedY)
If clickedItem IsNot Nothing AndAlso clickedItem.ImageKey.StartsWith("picBaddy") Then
IsOnBaddy = True
' Calculate the top-right corner of the clicked cell
Dim cellTopRightX As Integer = INDENT + (clickedX * (SQSizeX + WALL_THICKNESS)) + SQSizeX + 9
Dim cellTopRightY As Integer = INDENT + (clickedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS * 2) + 38
' Set the position and make the control visible
UcBaddyProps.Location = New Point(cellTopRightX, cellTopRightY)
UcBaddyProps.Visible = True
' Set properties of UcBaddyProps based on the clicked Baddy item
UcBaddyProps.ItemInfo = clickedItem
UcBaddyProps.BringToFront() ' Bring the control to the front
Else
' Hide the control if the clicked item is not a Baddy
UcBaddyProps.Visible = False
End If
End If
End Sub
Private Sub HandleGateClicked(mouseX As Integer, mouseY As Integer)
' Calculate the cell coordinates based on the mouse position
Dim clickedX As Integer = (mouseX - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim clickedY As Integer = (mouseY - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Check if the clicked cell contains a gate
If clickedX >= 0 AndAlso clickedX < placedItems.Length AndAlso
clickedY >= 0 AndAlso clickedY < placedItems(0).Length Then
Dim clickedItem As ItemInfo = placedItems(clickedX)(clickedY)
If clickedItem IsNot Nothing AndAlso clickedItem.ImageKey = "picGate" Then
IsOnGate = True
' Calculate the top-right corner of the clicked cell
Dim cellTopRightX As Integer = INDENT + (clickedX * (SQSizeX + WALL_THICKNESS)) + SQSizeX + 7
Dim cellTopRightY As Integer = INDENT + (clickedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS * 2) + 38
' Set the position and make the control visible
krKeys.Location = New Point(cellTopRightX, cellTopRightY)
krKeys.SelectedGate = clickedItem ' Set the SelectedGate property
krKeys.Grid = picGame ' Set the Grid property
krKeys.SetNumKeysValue(clickedItem.KeysRequiredToOpen) ' Set the NumKeys value to the gate's value
krKeys.Visible = True
Else
IsOnGate = False
End If
End If
End Sub
Private Sub HandleSelectionMode(e As MouseEventArgs)
' Handle selecting a square in selection mode
Dim clickedX As Integer = (e.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim clickedY As Integer = (e.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Determine if the user clicked on a wall or a floor
Dim isWall As Boolean = highlightedWallX OrElse highlightedWallY
Dim itemType As String = If(isWall, If(highlightedWallX, "VerticalWall", "HorizontalWall"), "Floor")
' Determine the item at the selected point
Dim item As String
If isWall Then
If highlightedWallX Then
' Check vertical wall items
If clickedX >= 0 AndAlso clickedX < verticalWallItems.Length AndAlso
clickedY >= 0 AndAlso clickedY < verticalWallItems(clickedX).Length Then
item = If(verticalWallItems(clickedX)(clickedY) IsNot Nothing, verticalWallItems(clickedX)(clickedY).ImageKey, "Nothing")
End If
ElseIf highlightedWallY Then
' Check horizontal wall items
If clickedX >= 0 AndAlso clickedX < horizontalWallItems.Length AndAlso
clickedY >= 0 AndAlso clickedY < horizontalWallItems(clickedX).Length Then
item = If(horizontalWallItems(clickedX)(clickedY) IsNot Nothing, horizontalWallItems(clickedX)(clickedY).ImageKey, "Nothing")
End If
End If
Else
' Check floor items
If clickedX >= 0 AndAlso clickedX < placedItems.Length AndAlso
clickedY >= 0 AndAlso clickedY < placedItems(clickedX).Length Then
item = If(placedItems(clickedX)(clickedY) IsNot Nothing, placedItems(clickedX)(clickedY).ImageKey, "Nothing")
End If
End If
' Check selection constraints
Dim triggerEditor As frmTriggerEditor = CType(SelectionRequestedByForm, frmTriggerEditor)
If SelectionRequestedFor = "TriggeringPoint" Then
If triggerEditor.AllowFloorSelectionOnly AndAlso isWall Then
Return
End If
ElseIf SelectionRequestedFor = "TriggerActionPoint" Then
' Allow clicking anything for TriggerActionPoint
ElseIf SelectionRequestedFor = "TriggerItemToRemove" Then
If triggerEditor.AllowWallSelectionOnly AndAlso Not isWall Then
Return
End If
End If
' Pass the selected point, item, and item type back to the requesting form
If TypeOf SelectionRequestedByForm Is frmTriggerEditor Then
If SelectionRequestedFor = "TriggeringPoint" Then
triggerEditor.SetTriggeringPoint(New Point(clickedX, clickedY))
ElseIf SelectionRequestedFor = "TriggerActionPoint" Then
triggerEditor.SetTriggerActionPoint(New Point(clickedX, clickedY), itemType)
End If
End If
TurnOffSelectionMode()
' Bring FrmTriggerEditor to the foreground
If TypeOf SelectionRequestedByForm Is frmTriggerEditor Then
triggerEditor.BringToFront() ' Bring FrmTriggerEditor to the front
Dim unused = triggerEditor.Focus() ' Focus on FrmTriggerEditor
End If
End Sub
' Create a new method to reset the cursor
Private Sub ResetTheCursor()
picGame.Cursor = Cursors.Default
Cursor = Cursors.Default
End Sub
' Call this method in TurnOffSelectionMode
Private Sub TurnOffSelectionMode()
isInSelectionMode = False
selectionRectangle = Rectangle.Empty
SelectionMode = False
SelectionRequestedByForm = Nothing
SelectionRequestedFor = Nothing
ResetTheCursor()
' Reset the cycle
isSelectionExpandedToWalls = False
isSelectionExpandedToFloors = False
End Sub
Private Function IsDoodadItem(imageKey As String) As Boolean
Return imageKey = "picBlockSwitch" OrElse imageKey.StartsWith("picDoodad")
End Function
Private Sub UpdateStatusBar(pixelX As Integer, pixelY As Integer)
' Calculate the square coordinates based on the mouse position
Dim squareX As Integer = (pixelX - INDENT + ((SQSizeX + WALL_THICKNESS) \ 2)) \ (SQSizeX + WALL_THICKNESS)
Dim squareY As Integer = (pixelY - INDENT + ((SQSizeY + WALL_THICKNESS) \ 2)) \ (SQSizeY + WALL_THICKNESS)
Dim triggerInfo As String = ""
' Determine if the mouse is over a wall
Dim isOverWall As Boolean = highlightedWallX OrElse highlightedWallY
' Determine the content of the square or wall
Dim content As String = "Empty"
Dim uniqueId As String = ""
If isOverWall Then
If highlightedWallX Then
' Check vertical wall items or walls
If highlightedX >= 0 AndAlso highlightedX < verticalWallItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWallItems(0).Length Then
If verticalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
content = GetItemFullName(verticalWallItems(highlightedX)(highlightedY).ImageKey)
uniqueId = verticalWallItems(highlightedX)(highlightedY).UniqueId
ElseIf verticalWalls(highlightedX)(highlightedY) Then
content = "Wall"
End If
End If
ElseIf highlightedWallY Then
' Check horizontal wall items or walls
If highlightedX >= 0 AndAlso highlightedX < horizontalWallItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWallItems(0).Length Then
If horizontalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
content = GetItemFullName(horizontalWallItems(highlightedX)(highlightedY).ImageKey)
uniqueId = horizontalWallItems(highlightedX)(highlightedY).UniqueId
ElseIf horizontalWalls(highlightedX)(highlightedY) Then
content = "Wall"
End If
End If
End If
Else
' Check floor items
If highlightedX >= 0 AndAlso highlightedX < placedItems.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < placedItems(0).Length Then
If placedItems(highlightedX)(highlightedY) IsNot Nothing Then
content = GetItemFullName(placedItems(highlightedX)(highlightedY).ImageKey)
uniqueId = placedItems(highlightedX)(highlightedY).UniqueId
ElseIf floorsUseEdgeStyle(highlightedX)(highlightedY) Then
content = "Edge"
End If
End If
End If
' Update the status bar labels
stbMouseCoords.Text = $"{pixelX}, {pixelY}"
If isOverWall Then
If highlightedWallX Then
stbGridCoords.Text = $"Vertical Wall: {highlightedX}, {highlightedY}"
ElseIf highlightedWallY Then
stbGridCoords.Text = $"Horizontal Wall: {highlightedX}, {highlightedY}"
End If
Else
stbGridCoords.Text = $"Floor: {highlightedX}, {highlightedY}"
End If
stbItemType.Text = content
stbID.Text = uniqueId
' Look for triggers associated with this point using GRID COORDINATES
For Each trigger As Triggers In TriggerData
' Check floor triggers
If trigger.TriggeringPoint.Item1 = highlightedX AndAlso trigger.TriggeringPoint.Item2 = highlightedY Then
triggerInfo = trigger.TriggerFull
Exit For
End If
' Check if the TriggerActionPoint is on a wall
If trigger.TriggerActionPoint.Item1 = highlightedX AndAlso trigger.TriggerActionPoint.Item2 = highlightedY Then
If trigger.TriggerActionIsWall Then
If trigger.TriggerActionIsVerticalWall AndAlso highlightedWallX Then
triggerInfo = trigger.TriggerFull
ElseIf trigger.TriggerActionIsHorizontalWall AndAlso highlightedWallY Then
triggerInfo = trigger.TriggerFull
End If
Else
triggerInfo = trigger.TriggerFull
End If
Exit For
End If
Next
' Only update stbTrigger if not over a wall or if the trigger action point is on the correct wall type
If Not isOverWall Then
stbTrigger.Text = triggerInfo ' Display the trigger information in the status bar
Else
For Each trigger As Triggers In TriggerData
If trigger.TriggerActionPoint.Item1 = highlightedX AndAlso trigger.TriggerActionPoint.Item2 = highlightedY Then
If trigger.TriggerActionIsWall AndAlso
((trigger.TriggerActionIsVerticalWall AndAlso highlightedWallX) OrElse
(trigger.TriggerActionIsHorizontalWall AndAlso highlightedWallY)) Then
stbTrigger.Text = triggerInfo ' Display the trigger information in the status bar
Exit For
End If
End If
Next
If stbTrigger.Text = "" Then
stbTrigger.Text = ""
End If
End If
' Apply formatting to the RichTextBox
ApplyFormatting(stbTrigger, triggerInfo)
End Sub
Private Function GetItemTypeAtPosition(x As Integer, y As Integer) As String
' Determine if the selected item is a wall, wall item, or floor item
If highlightedWallX Then
Return If(verticalWallItems(x)(y) IsNot Nothing, "VerticalWallItem", "VerticalWall")
ElseIf highlightedWallY Then
Return If(horizontalWallItems(x)(y) IsNot Nothing, "HorizontalWallItem", "HorizontalWall")
Else
Return If(placedItems(x)(y) IsNot Nothing, "FloorItem", "Floor")
End If
End Function
Private Sub HideUcBaddyProps()
UcBaddyProps.Visible = False
End Sub
Public Sub PictureBox_MouseEnter(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
pb.BackColor = Color.LightBlue
End Sub
Public Sub PictureBox_MouseLeave(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
pb.BackColor = Color.Transparent
End Sub
Private Sub AddWallAtMousePosition(mouseX As Integer, mouseY As Integer)
UpdateHighlight(mouseX, mouseY)
If highlightedWallX Then
If highlightedX >= 0 AndAlso highlightedX < verticalWalls.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWalls(0).Length Then
verticalWalls(highlightedX)(highlightedY) = True
End If
ElseIf highlightedWallY Then
If highlightedX >= 0 AndAlso highlightedX < horizontalWalls.Length AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWalls(0).Length Then
horizontalWalls(highlightedX)(highlightedY) = True
End If
End If
End Sub
Private Sub RemoveObjectAtMousePosition(mouseX As Integer, mouseY As Integer, removeWalls As Boolean, removeItems As Boolean)
UpdateHighlight(mouseX, mouseY)
If Not isMouseInsideGrid Then
Return
End If
If highlightedWallX Then
If highlightedX >= 0 AndAlso highlightedX < verticalWallItems.Length AndAlso
verticalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWallItems(0).Length Then
If removeItems AndAlso verticalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
verticalWallItems(highlightedX)(highlightedY) = Nothing
verticalWalls(highlightedX)(highlightedY) = True
If IsVerticalWallConnectedToEdge(New Point(highlightedX, highlightedY)) Then
verticalWalls(highlightedX)(highlightedY) = True
End If
ElseIf removeWalls AndAlso verticalWalls(highlightedX)(highlightedY) Then
If Not IsVerticalWallOuterBorder(highlightedX) AndAlso Not IsVerticalWallConnectedToEdge(New Point(highlightedX, highlightedY)) Then
verticalWalls(highlightedX)(highlightedY) = False
End If
End If
End If
ElseIf highlightedWallY Then
If highlightedX >= 0 AndAlso highlightedX < horizontalWallItems.Length AndAlso
horizontalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWallItems(0).Length Then
If removeItems AndAlso horizontalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
horizontalWallItems(highlightedX)(highlightedY) = Nothing
horizontalWalls(highlightedX)(highlightedY) = True
If IsHorizontalWallConnectedToEdge(New Point(highlightedX, highlightedY)) Then
horizontalWalls(highlightedX)(highlightedY) = True
End If
ElseIf removeWalls AndAlso horizontalWalls(highlightedX)(highlightedY) Then
If Not IsHorizontalWallOuterBorder(highlightedY) AndAlso Not IsHorizontalWallConnectedToEdge(New Point(highlightedX, highlightedY)) Then
horizontalWalls(highlightedX)(highlightedY) = False
End If
End If
End If
Else
If highlightedX >= 0 AndAlso highlightedX < placedItems.Length AndAlso
placedItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < placedItems(0).Length Then
If removeItems AndAlso placedItems(highlightedX)(highlightedY) IsNot Nothing Then
placedItems(highlightedX)(highlightedY) = Nothing
End If
End If
End If
End Sub
Private Sub SetEdgeStyleAtMousePosition(mouseX As Integer, mouseY As Integer)
UpdateHighlight(mouseX, mouseY)
If Not highlightedWallX AndAlso Not highlightedWallY Then
If highlightedX >= 0 AndAlso highlightedX < SQCOUNTX AndAlso highlightedY >= 0 AndAlso highlightedY < SQCOUNTY Then
floorsUseEdgeStyle(highlightedX)(highlightedY) = True
If highlightedX >= 0 AndAlso highlightedX < verticalWalls.Length AndAlso
verticalWalls(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWalls(0).Length Then
verticalWallItems(highlightedX)(highlightedY) = Nothing
verticalWalls(highlightedX)(highlightedY) = True
End If
If highlightedX + 1 >= 0 AndAlso highlightedX + 1 < verticalWalls.Length AndAlso
verticalWalls(highlightedX + 1) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWalls(0).Length Then
verticalWallItems(highlightedX + 1)(highlightedY) = Nothing
verticalWalls(highlightedX + 1)(highlightedY) = True
End If
If highlightedX >= 0 AndAlso highlightedX < horizontalWalls.Length AndAlso
horizontalWalls(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWalls(0).Length Then
horizontalWallItems(highlightedX)(highlightedY) = Nothing
horizontalWalls(highlightedX)(highlightedY) = True
End If
If highlightedX >= 0 AndAlso highlightedX < horizontalWalls.Length AndAlso
horizontalWalls(highlightedX) IsNot Nothing AndAlso
highlightedY + 1 >= 0 AndAlso highlightedY + 1 < horizontalWalls(0).Length Then
horizontalWallItems(highlightedX)(highlightedY + 1) = Nothing
horizontalWalls(highlightedX)(highlightedY + 1) = True
End If
End If
End If
End Sub
Private Function IsHorizontalWallConnectedToEdge(pt As Point) As Boolean
Dim x As Integer = pt.X
Dim y As Integer = pt.Y
If y > 0 AndAlso floorsUseEdgeStyle(x)(y - 1) Then Return True
If y < SQCOUNTY AndAlso floorsUseEdgeStyle(x)(y) Then Return True
Return False
End Function
Private Function IsVerticalWallConnectedToEdge(pt As Point) As Boolean
Dim x As Integer = pt.X
Dim y As Integer = pt.Y
If x > 0 AndAlso floorsUseEdgeStyle(x - 1)(y) Then Return True
If x < SQCOUNTX AndAlso floorsUseEdgeStyle(x)(y) Then Return True
Return False
End Function
Private Function GetRectangle(p1 As Point, p2 As Point) As Rectangle
Dim x As Integer = Math.Min(p1.X, p2.X)
Dim y As Integer = Math.Min(p1.Y, p2.Y)
Dim width As Integer = Math.Abs(p1.X - p2.X)
Dim height As Integer = Math.Abs(p1.Y - p2.Y)
Return New Rectangle(x, y, width, height)
End Function
Private Function GetCellsInRectangle(rect As Rectangle) As List(Of Point)
Dim selectedCells As New List(Of Point)
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY - 1
Dim cellRect As Rectangle = GetCellRectangle(x, y)
If rect.IntersectsWith(cellRect) Then
selectedCells.Add(New Point(x, y))
End If
Next
Next
Return selectedCells
End Function
Private Function GetCellRectangle(x As Integer, y As Integer) As Rectangle
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
Return New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
SQSizeX,
SQSizeY)
End Function
Private Function GetVerticalWallsInRectangle(rect As Rectangle) As List(Of Point)
Dim selectedWalls As New List(Of Point)
For x As Integer = 0 To SQCOUNTX
For y As Integer = 0 To SQCOUNTY - 1
Dim wallRect As Rectangle = GetVerticalWallRectangle(x, y)
If rect.IntersectsWith(wallRect) Then
selectedWalls.Add(New Point(x, y))
End If
Next
Next
Return selectedWalls
End Function
Private Function GetVerticalWallRectangle(x As Integer, y As Integer) As Rectangle
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
Return New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
WALL_THICKNESS, SQSizeY)
End Function
Private Function GetHorizontalWallsInRectangle(rect As Rectangle) As List(Of Point)
Dim selectedWalls As New List(Of Point)
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY
Dim wallRect As Rectangle = GetHorizontalWallRectangle(x, y)
If rect.IntersectsWith(wallRect) Then
selectedWalls.Add(New Point(x, y))
End If
Next
Next
Return selectedWalls
End Function
Private Function GetHorizontalWallRectangle(x As Integer, y As Integer) As Rectangle
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
Return New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2),
SQSizeX, WALL_THICKNESS)
End Function
Private Sub ReturnItemToOriginalLocation()
If draggedItemIsWall Then
If draggedItemOriginalX >= 0 AndAlso draggedItemOriginalY >= 0 Then
If draggedItemIsVerticalWall Then
verticalWallItems(draggedItemOriginalX)(draggedItemOriginalY) = draggedItem
verticalWalls(draggedItemOriginalX)(draggedItemOriginalY) = False
Else
horizontalWallItems(draggedItemOriginalX)(draggedItemOriginalY) = draggedItem
horizontalWalls(draggedItemOriginalX)(draggedItemOriginalY) = False
End If
End If
Else
If draggedItemOriginalX >= 0 AndAlso draggedItemOriginalY >= 0 Then
placedItems(draggedItemOriginalX)(draggedItemOriginalY) = draggedItem
End If
End If
End Sub
Private Function IsVerticalItem(imgKey As String) As Boolean
Return imgKey = "picLaser1" OrElse imgKey = "picFlipper1" OrElse imgKey = "picFlipper2"
End Function
Private Function IsHorizontalItem(imgKey As String) As Boolean
Return imgKey = "picLaser2" OrElse imgKey = "picFlipper3" OrElse imgKey = "picFlipper4"
End Function
Private Function IsFlipperItem(item As ItemInfo) As Boolean
If item Is Nothing Then Return False
Dim imgKey = item.ImageKey
Return imgKey = "picFlipper1" OrElse imgKey = "picFlipper2" _
OrElse imgKey = "picFlipper3" OrElse imgKey = "picFlipper4"
End Function
Private Function IsFlipperItem(imgKey As String) As Boolean
Return imgKey = "picFlipper1" OrElse imgKey = "picFlipper2" _
OrElse imgKey = "picFlipper3" OrElse imgKey = "picFlipper4"
End Function
#End Region
#Region " Draw "
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' Draw the grid
DrawGrid(e.Graphics)
' Draw any dragged item
If isDraggingItem AndAlso draggedItem IsNot Nothing Then
Dim img As Image = GetImageByKey(draggedItem.ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim drawRect As Rectangle
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
Dim wallWidth As Integer = WALL_THICKNESS
Dim wallHeight As Integer = SQSizeY
Dim xPos As Integer = mouseX - (WALL_THICKNESS \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
Dim newWidth As Integer = img.Width
Dim newHeight As Integer = wallHeight
Dim centeredX As Integer = xPos + ((wallWidth - newWidth) \ 2)
drawRect = New Rectangle(centeredX, yPos, newWidth, newHeight)
Else
Dim wallWidth As Integer = SQSizeX
Dim wallHeight As Integer = WALL_THICKNESS
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (WALL_THICKNESS \ 2)
Dim newWidth As Integer = wallWidth
Dim newHeight As Integer = img.Height
Dim centeredY As Integer = yPos + ((wallHeight - newHeight) \ 2)
drawRect = New Rectangle(xPos, centeredY, newWidth, newHeight)
End If
Else
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
drawRect = New Rectangle(xPos, yPos, SQSizeX, SQSizeY)
End If
e.Graphics.DrawImage(img, drawRect)
End If
End If
' Draw selection rectangle
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
' Draw selection data during drag
If isDraggingSelection Then
Dim baseCellX As Integer = (selectionRectangle.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim baseCellY As Integer = (selectionRectangle.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Ensure selectionData is valid before drawing
If selectionData IsNot Nothing Then
If isCopying Then
DrawSelectionData(e.Graphics, baseCellX, baseCellY, copiedSelectionData)
Else
DrawSelectionData(e.Graphics, baseCellX, baseCellY, selectionData)
End If
Else
Debug.WriteLine("selectionData is Nothing. Skipping drawing.")
End If
End If
' Ensure DrawHighlight is called
DrawHighlight(e.Graphics)
' Draw triggers
DrawTriggers(e.Graphics)
End Sub
Private Sub DrawGradientBackground(g As Graphics)
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
Dim gridWidth As Integer = SQCOUNTX * (SQSizeX + WALL_THICKNESS)
Dim gridHeight As Integer = SQCOUNTY * (SQSizeY + WALL_THICKNESS)
Dim gradientRect As New Rectangle(xOrigin, yOrigin, gridWidth, gridHeight)
Using brush As New LinearGradientBrush(gradientRect, floorsColor1, floorsColor2, LinearGradientMode.Vertical)
g.FillRectangle(brush, gradientRect)
End Using
End Sub
Private Sub DrawGrid(g As Graphics)
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
DrawGradientBackground(g)
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY - 1
Dim floorRect As New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
SQSizeX,
SQSizeY
)
If floorsUseEdgeStyle(x)(y) Then
Using floorBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
g.FillRectangle(floorBrush, floorRect)
End Using
ElseIf useGradient Then
Using hatchBrush As New HatchBrush(floorsHatchStyle, Color.Transparent, Color.Transparent)
g.FillRectangle(hatchBrush, floorRect)
End Using
Else
Using floorBrush As New HatchBrush(floorsHatchStyle, floorsColor1, floorsColor2)
g.FillRectangle(floorBrush, floorRect)
End Using
End If
Next
Next
' Draw the region icon once in the top-left corner of each region
For Each region As RegionInfo In regions
If region.Rectangle.Width > 0 And region.Rectangle.Height > 0 Then ' Ensure region has valid dimensions
g.DrawImage(regionIcon, region.Rectangle.X + 4, region.Rectangle.Y + 4, regionIcon.Width + 5, regionIcon.Height + 5)
End If
Next
For x As Integer = 0 To SQCOUNTX
For y As Integer = 0 To SQCOUNTY
Dim intersectionRect As New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2),
WALL_THICKNESS,
WALL_THICKNESS
)
Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
g.FillRectangle(wallBrush, intersectionRect)
End Using
Next
Next
For x As Integer = 0 To SQCOUNTX
For y As Integer = 0 To SQCOUNTY - 1
Dim wallRect As New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
WALL_THICKNESS, SQSizeY
)
If x >= 0 AndAlso x < verticalWalls.Length AndAlso
verticalWalls(x) IsNot Nothing AndAlso
y >= 0 AndAlso y < verticalWalls(0).Length Then
If verticalWalls(x)(y) Then
Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
g.FillRectangle(wallBrush, wallRect)
End Using
ElseIf useGradient Then
Using hatchBrush As New HatchBrush(floorsHatchStyle, Color.Transparent, Color.Transparent)
g.FillRectangle(hatchBrush, wallRect)
End Using
Else
Using floorBrush As New HatchBrush(floorsHatchStyle, floorsColor1, floorsColor2)
g.FillRectangle(floorBrush, wallRect)
End Using
End If
End If
Next
Next
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY
Dim wallRect As New Rectangle(
xOrigin + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
yOrigin + (y * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2),
SQSizeX, WALL_THICKNESS
)
If x >= 0 AndAlso x < horizontalWalls.Length AndAlso
horizontalWalls(x) IsNot Nothing AndAlso
y >= 0 AndAlso y < horizontalWalls(0).Length Then
If horizontalWalls(x)(y) Then
Using wallBrush As New HatchBrush(wallsHatchStyle, wallsColor1, wallsColor2)
g.FillRectangle(wallBrush, wallRect)
End Using
ElseIf useGradient Then
Using hatchBrush As New HatchBrush(floorsHatchStyle, Color.Transparent, Color.Transparent)
g.FillRectangle(hatchBrush, wallRect)
End Using
Else
Using floorBrush As New HatchBrush(floorsHatchStyle, floorsColor1, floorsColor2)
g.FillRectangle(floorBrush, wallRect)
End Using
End If
End If
Next
Next
DrawItems(g)
DrawWallItems(g)
DrawGridNumbers(g)
' Draw triggers
DrawTriggers(g)
End Sub
Private Sub DrawTriggers(g As Graphics)
If triggerImage Is Nothing OrElse triggerImage2Small Is Nothing Then Return ' Ensure the images are loaded
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
For Each trigger As Triggers In TriggerData
' Draw the trigger icon for the TriggeringPoint (always on floor)
If trigger.TriggeringPoint.Item1 >= 0 AndAlso trigger.TriggeringPoint.Item1 < SQCOUNTX AndAlso
trigger.TriggeringPoint.Item2 >= 0 AndAlso trigger.TriggeringPoint.Item2 < SQCOUNTY Then
' Move the TriggeringPoint icon to the top-left of the floor
Dim triggerX = xOrigin + (trigger.TriggeringPoint.Item1 * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + 4 ' Slightly right of the top-left
Dim triggerY = yOrigin + (trigger.TriggeringPoint.Item2 * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + 4 ' Slightly down from the top-left
g.DrawImage(triggerImageSmall, triggerX, triggerY)
End If
' Draw the trigger icon for the TriggerActionPoint
If trigger.TriggerActionPoint.Item1 >= 0 AndAlso trigger.TriggerActionPoint.Item1 <= SQCOUNTX AndAlso
trigger.TriggerActionPoint.Item2 >= 0 AndAlso trigger.TriggerActionPoint.Item2 <= SQCOUNTY Then
Dim actionX As Integer = 0
Dim actionY As Integer = 0
If trigger.TriggerActionIsWall Then
' Handle drawing for walls (horizontal or vertical)
If trigger.TriggerActionIsVerticalWall Then
' Move to the top of the vertical wall
actionX = xOrigin + (trigger.TriggerActionPoint.Item1 * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) - 2
actionY = yOrigin + (trigger.TriggerActionPoint.Item2 * (SQSizeY + WALL_THICKNESS)) - (triggerImage2Small.Height \ 2) + 12 ' Slightly above the center
ElseIf trigger.TriggerActionIsHorizontalWall Then
' Move to the center of the horizontal wall
actionX = xOrigin + (trigger.TriggerActionPoint.Item1 * (SQSizeX + WALL_THICKNESS)) + (SQSizeX \ 2) - 20
actionY = yOrigin + (trigger.TriggerActionPoint.Item2 * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) - (triggerImage2Small.Height \ 2) + 2
End If
Else
' Move the action point icon to the top-left of the floor
If trigger.TriggerActionPoint.Item1 >= 0 AndAlso trigger.TriggerActionPoint.Item1 < SQCOUNTX AndAlso
trigger.TriggerActionPoint.Item2 >= 0 AndAlso trigger.TriggerActionPoint.Item2 < SQCOUNTY Then
actionX = xOrigin + (trigger.TriggerActionPoint.Item1 * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + 4 ' Slightly right of the top-left
actionY = yOrigin + (trigger.TriggerActionPoint.Item2 * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + 4 ' Slightly down from the top-left
End If
End If
' Check if the trigger action is "Flip Horizontal" or "Flip Vertical"
If trigger.TriggerAction = "Flip Horizontal" OrElse trigger.TriggerAction = "Flip Vertical" Then
' Skip drawing the trigger icon for these actions
Continue For
End If
' Draw the action trigger icon using triggerImage2Small
g.DrawImage(triggerImage2Small, actionX, actionY)
' Draw a line between the triggering point and the action point if hovered
If HoveredTrigger IsNot Nothing AndAlso HoveredTrigger.Equals(trigger) Then
Dim pen As New Pen(Color.Red, 2)
' Calculate the center of the triggering point icon
Dim startX As Integer = xOrigin + (trigger.TriggeringPoint.Item1 * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (triggerImageSmall.Width \ 2)
Dim startY As Integer = yOrigin + (trigger.TriggeringPoint.Item2 * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (triggerImageSmall.Height \ 2)
' Calculate the center of the action point icon
Dim endX As Integer = actionX + (triggerImage2Small.Width \ 2)
Dim endY As Integer = actionY + (triggerImage2Small.Height \ 2)
g.DrawLine(pen, startX, startY, endX, endY)
End If
End If
Next
End Sub
Private Sub DrawGridNumbers(g As Graphics)
Dim xOrigin As Integer = INDENT
Dim yOrigin As Integer = INDENT
Dim font As New Font("Arial", 12, FontStyle.Regular)
Dim brush As New SolidBrush(Color.Black)
Dim brush2 As New SolidBrush(Color.Green)
Dim smallFont As New Font("Arial", 6, FontStyle.Regular)
Dim columnNumberOffsetY As Single = -20.0F
Dim rowNumberOffsetX As Single = -5.0F
For x As Integer = 0 To SQCOUNTX - 1
Dim xPos As Single = xOrigin + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (CSng(SQSizeX) / 2)
Dim yPos As Single = yOrigin + columnNumberOffsetY
Dim label As String = x.ToString()
Dim xLabelSize As SizeF = g.MeasureString(label, font)
g.DrawString(label, font, brush, xPos - (xLabelSize.Width / 2.0F), yPos)
Next
For y As Integer = 0 To SQCOUNTY - 1
Dim xPos As Single = xOrigin + rowNumberOffsetX
Dim yPos As Single = yOrigin + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2) + (CSng(SQSizeY) / 2)
Dim label As String = y.ToString()
Dim yLabelSize As SizeF = g.MeasureString(label, font)
g.DrawString(label, font, brush, xPos - yLabelSize.Width, yPos - (yLabelSize.Height / 2.0F))
Next
' Draw smaller numbers for vertical walls
For x As Integer = 0 To SQCOUNTX
Dim smallLabel As String = x.ToString()
Dim smallXPos As Single = xOrigin + (x * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) + 4
Dim smallYPos As Single = yOrigin + columnNumberOffsetY + 4
Dim smallXLabelSize As SizeF = g.MeasureString(smallLabel, smallFont)
g.DrawString(smallLabel, smallFont, brush2, smallXPos - (smallXLabelSize.Width / 2.0F), smallYPos)
Next
' Draw smaller numbers for horizontal walls
For y As Integer = 0 To SQCOUNTY
Dim smallLabel As String = y.ToString()
Dim smallYPos As Single = yOrigin + (y * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2) + 3
Dim smallXPos As Single = xOrigin + rowNumberOffsetX
Dim smallYLabelSize As SizeF = g.MeasureString(smallLabel, smallFont)
g.DrawString(smallLabel, smallFont, brush2, smallXPos - smallYLabelSize.Width, smallYPos - (smallYLabelSize.Height / 2.0F))
Next
font.Dispose()
brush.Dispose()
smallFont.Dispose()
End Sub
Friend Sub FillBorderWalls()
For y As Integer = 0 To SQCOUNTY - 1
verticalWalls(0)(y) = True
verticalWalls(SQCOUNTX)(y) = True
Next
For x As Integer = 0 To SQCOUNTX - 1
horizontalWalls(x)(0) = True
horizontalWalls(x)(SQCOUNTY) = True
Next
End Sub
Private Sub DrawItems(g As Graphics)
' Font and brush for key count text
Dim keyFont As New Font("Arial", 14, FontStyle.Bold) ' Text will now be white
For x As Integer = 0 To placedItems.Length - 1
If placedItems(x) IsNot Nothing Then
For y As Integer = 0 To placedItems(x).Length - 1
If placedItems(x)(y) IsNot Nothing Then
Dim img As Image = GetImageByKey(placedItems(x)(y).ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim xPos As Integer = INDENT + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim yPos As Integer = INDENT + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim destRect As New Rectangle(xPos, yPos, SQSizeX, SQSizeY)
Dim imgAttributes As New Imaging.ImageAttributes()
imgAttributes.SetWrapMode(WrapMode.TileFlipXY)
g.DrawImage(img, destRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttributes)
' Draw the key count in the center of the gate (only for gates)
If placedItems(x)(y).ImageKey = "picGate" Then
Dim keysRequired = placedItems(x)(y).KeysRequiredToOpen
Dim numKeyText As String = keysRequired.ToString()
' Center the text in the middle of the gate
Dim textSize As SizeF = g.MeasureString(numKeyText, keyFont)
Dim textX As Integer = xPos + (SQSizeX \ 2) - (textSize.Width \ 2)
Dim textY As Integer = yPos + (SQSizeY \ 2) - (textSize.Height \ 2)
' Draw the number of keys on the gate
g.DrawString(numKeyText, keyFont, Brushes.White, textX, textY)
End If
End If
End If
Next
End If
Next
' Draw region overlays if chkShowRegions is checked
If chkShowRegions.Checked Then
For Each region As RegionInfo In regions
If regionOverlayColors.ContainsKey(region.Name) Then
Dim overlayColor As Color = regionOverlayColors(region.Name)
Using brush As New SolidBrush(overlayColor)
g.FillRectangle(brush, region.Rectangle)
End Using
End If
Next
End If
End Sub
Private Sub DrawWallItems(g As Graphics)
For x As Integer = 0 To verticalWallItems.Length - 1
If verticalWallItems(x) IsNot Nothing Then
For y As Integer = 0 To verticalWallItems(x).Length - 1
If verticalWallItems(x)(y) IsNot Nothing Then
Dim img As Image = GetImageByKey(verticalWallItems(x)(y).ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim wallX As Integer = INDENT + (x * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2)
Dim wallY As Integer = INDENT + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim wallWidth As Integer = WALL_THICKNESS
Dim wallHeight As Integer = SQSizeY
Dim newWidth As Integer = img.Width
Dim newHeight As Integer = wallHeight
Dim centeredX As Integer = wallX + ((wallWidth - newWidth) \ 2)
Dim drawRect As New Rectangle(centeredX, wallY, newWidth, newHeight)
g.DrawImage(img, drawRect)
End If
End If
Next
End If
Next
For x As Integer = 0 To horizontalWallItems.Length - 1
If horizontalWallItems(x) IsNot Nothing Then
For y As Integer = 0 To horizontalWallItems(x).Length - 1
If horizontalWallItems(x)(y) IsNot Nothing Then
Dim img As Image = GetImageByKey(horizontalWallItems(x)(y).ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim wallX As Integer = INDENT + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim wallY As Integer = INDENT + (y * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2)
Dim wallWidth As Integer = SQSizeX
Dim wallHeight As Integer = WALL_THICKNESS
Dim newWidth As Integer = wallWidth
Dim newHeight As Integer = img.Height
Dim centeredY As Integer = wallY + ((wallHeight - newHeight) \ 2)
Dim drawRect As New Rectangle(wallX, centeredY, newWidth, newHeight)
g.DrawImage(img, drawRect)
End If
End If
Next
End If
Next
End Sub
Private Sub DrawHighlight(g As Graphics)
If Not isMouseInsideGrid OrElse highlightedX < 0 OrElse highlightedY < 0 OrElse Not isCursorOnPicGame Then
Return
End If
' Determine the highlight color
Dim highlightColorToUse As Color = highlightColor
If SelectionMode Then
Dim triggerEditor As frmTriggerEditor = CType(SelectionRequestedByForm, frmTriggerEditor)
If (triggerEditor.AllowFloorSelectionOnly AndAlso (highlightedWallX OrElse highlightedWallY)) OrElse
(triggerEditor.AllowWallSelectionOnly AndAlso Not (highlightedWallX OrElse highlightedWallY)) Then
highlightColorToUse = Color.Red
End If
End If
Using highlightPen As New Pen(highlightColorToUse, 2) With {.DashStyle = DashStyle.Dash}
If highlightedWallX Then
Dim x As Integer = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) - (WALL_THICKNESS \ 2)
Dim y As Integer = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim rect As New Rectangle(x, y, WALL_THICKNESS, SQSizeY)
g.DrawRectangle(highlightPen, rect)
ElseIf highlightedWallY Then
Dim x As Integer = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim y As Integer = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) - (WALL_THICKNESS \ 2)
Dim rect As New Rectangle(x, y, SQSizeX, WALL_THICKNESS)
g.DrawRectangle(highlightPen, rect)
Else
Dim x As Integer = INDENT + (highlightedX * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim y As Integer = INDENT + (highlightedY * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2)
Dim rect As New Rectangle(x, y, SQSizeX, SQSizeY)
g.DrawRectangle(highlightPen, rect)
End If
End Using
End Sub
Private Sub UpdateHighlight(mouseX As Integer, mouseY As Integer)
mouseX -= INDENT
mouseY -= INDENT
isMouseInsideGrid = False
highlightedWallX = False
highlightedWallY = False
highlightedX = -1
highlightedY = -1
Dim cellSizeX As Integer = SQSizeX + WALL_THICKNESS
Dim cellSizeY As Integer = SQSizeY + WALL_THICKNESS
Dim cellX As Integer = mouseX \ cellSizeX
Dim cellY As Integer = mouseY \ cellSizeY
If cellX >= 0 AndAlso cellX <= SQCOUNTX AndAlso
cellY >= 0 AndAlso cellY <= SQCOUNTY Then
Dim offsetX As Integer = mouseX Mod cellSizeX
Dim offsetY As Integer = mouseY Mod cellSizeY
highlightedWallX = offsetX < WALL_THICKNESS
highlightedWallY = offsetY < WALL_THICKNESS
highlightedX = cellX
highlightedY = cellY
isMouseInsideGrid = True
End If
If highlightedX < 0 Then highlightedX = 0
If highlightedX > SQCOUNTX Then highlightedX = SQCOUNTX
If highlightedY < 0 Then highlightedY = 0
If highlightedY > SQCOUNTY Then highlightedY = SQCOUNTY
If highlightedWallX AndAlso (highlightedX = 0 OrElse highlightedX = SQCOUNTX) Then
highlightedWallX = True
End If
If highlightedWallY AndAlso (highlightedY = 0 OrElse highlightedY = SQCOUNTY) Then
highlightedWallY = True
End If
Dim itemName As String
If highlightedWallX Then
If highlightedX >= 0 AndAlso highlightedX < verticalWallItems.Length AndAlso
verticalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < verticalWallItems(0).Length Then
If verticalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
itemName = GetItemName(verticalWallItems(highlightedX)(highlightedY).ImageKey)
End If
End If
ElseIf highlightedWallY Then
If highlightedX >= 0 AndAlso highlightedX < horizontalWallItems.Length AndAlso
horizontalWallItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < horizontalWallItems(0).Length Then
If horizontalWallItems(highlightedX)(highlightedY) IsNot Nothing Then
itemName = GetItemName(horizontalWallItems(highlightedX)(highlightedY).ImageKey)
End If
End If
Else
If highlightedX >= 0 AndAlso highlightedX < placedItems.Length AndAlso
placedItems(highlightedX) IsNot Nothing AndAlso
highlightedY >= 0 AndAlso highlightedY < placedItems(0).Length Then
If placedItems(highlightedX)(highlightedY) IsNot Nothing Then
itemName = GetItemName(placedItems(highlightedX)(highlightedY).ImageKey)
End If
End If
End If
' Reset hoveredTrigger
HoveredTrigger = Nothing
' Check if the mouse is over a triggering point or action point
For Each trigger As Triggers In TriggerData
If trigger.TriggeringPoint.Item1 = highlightedX AndAlso trigger.TriggeringPoint.Item2 = highlightedY Then
If Not highlightedWallX AndAlso Not highlightedWallY Then
HoveredTrigger = trigger
Exit For
End If
End If
If trigger.TriggerActionPoint.Item1 = highlightedX AndAlso trigger.TriggerActionPoint.Item2 = highlightedY Then
If trigger.TriggerActionIsWall Then
If trigger.TriggerActionIsVerticalWall AndAlso highlightedWallX Then
HoveredTrigger = trigger
Exit For
ElseIf trigger.TriggerActionIsHorizontalWall AndAlso highlightedWallY Then
HoveredTrigger = trigger
Exit For
End If
ElseIf Not highlightedWallX AndAlso Not highlightedWallY Then
HoveredTrigger = trigger
Exit For
End If
End If
Next
End Sub
Private Function GetImageByKey(imageKey As String) As Image
Select Case imageKey
Case "picBlock1"
Return picBlock1.Image
Case "picBlock2"
Return picBlock2.Image
Case "picBaddy1"
Return picBaddy1.Image
Case "picBaddy2"
Return picBaddy2.Image
Case "picBaddy3"
Return picBaddy3.Image
Case "picBaddy4"
Return picBaddy4.Image
Case "picLaser1"
Return picLaser1.Image
Case "picLaser2"
Return picLaser2.Image
Case "picFlipper1"
Return picFlipper1.Image
Case "picFlipper2"
Return picFlipper2.Image
Case "picFlipper3"
Return picFlipper3.Image
Case "picFlipper4"
Return picFlipper4.Image
Case "picCoin"
Return picCoin.Image
Case "picGate"
Return picGate.Image
Case "picKey"
Return picKey.Image
Case "picStart"
Return picStart.Image
Case "picFinish"
Return picFinish.Image
Case "picBlockStopper1"
Return picBlockStopper1.Image
Case "picBall"
Return picBall.Image
Case "picBlockSwitch"
Return picBlockSwitch.Image
Case "picBomb"
Return picBomb.Image
Case "picWarp"
Return picWarp.Image
Case "picWarp2"
Return picWarp2.Image
Case "picWarp3"
Return picWarp3.Image
Case "picVolcano"
Return picVolcano.Image
Case Else
Return Nothing
End Select
End Function
#End Region
#Region " Colours "
Private Sub UpdateColorPickers()
If rdoWalls.Checked Then
' Set color pickers to wall colors
colPattern.SelectedColor = wallsColor1
colBackground.SelectedColor = wallsColor2
ElseIf rdoFloors.Checked Then
' Set color pickers to floor colors
colPattern.SelectedColor = floorsColor1
colBackground.SelectedColor = floorsColor2
End If
End Sub
Public Sub UpdateGameColors(senderObject As Object, newColor As Color)
If rdoWalls.Checked Then
' Update wall colors
If senderObject Is colPattern Then
wallsColor1 = newColor
ElseIf senderObject Is colBackground Then
wallsColor2 = newColor
End If
ElseIf rdoFloors.Checked Then
' Update floor colors
If senderObject Is colPattern Then
floorsColor1 = newColor
ElseIf senderObject Is colBackground Then
floorsColor2 = newColor
End If
End If
' Redraw the game area to reflect changes
End Sub
Private Sub ColPattern_ColorChanged(sender As Object, e As EventArgs) Handles colPattern.ColorChanged
TurnOffSelectionMode()
UpdateGameColors(colPattern, colPattern.SelectedColor)
End Sub
Private Sub ColBackground_ColorChanged(sender As Object, e As EventArgs) Handles colBackground.ColorChanged
TurnOffSelectionMode()
UpdateGameColors(colBackground, colBackground.SelectedColor)
End Sub
#End Region
Can you make it so when I click a chld node in trvTextures. The Floor changes to the image file the node displays? To implement the functionality where clicking a child node in the `trvTextures` TreeView changes the floor image to the image file represented by that node, you can follow these steps:
1. **Add Event Handler**: Create a handler for the `AfterSelect` event of the `trvTextures` TreeView. This event will trigger when a node is selected (clicked).
2. **Change the Floor Image**: In the event handler, check if the selected node is a child node (which represents an image file), and if so, update the floor image accordingly.
Here is how you can implement this:
### Step 1: Create the Event Handler
In your code, add a handler for the `AfterSelect` event of `trvTextures`. You can do this in the `InitializeEventHandlers` method.
### Step 2: Implement the Event Handler Logic
In the event handler, check if the selected node represents a valid image file and then change the floor image.
```vb
Private Sub InitializeEventHandlers()
picGame.AllowDrop = True
' Previous handlers
For Each ctl As Control In tabFloor1.Controls
If TypeOf ctl Is PictureBox Then
AddHandler ctl.MouseEnter, AddressOf PictureBox_MouseEnter
AddHandler ctl.MouseLeave, AddressOf PictureBox_MouseLeave
End If
Next
For Each ctl As Control In tabWalls.Controls
If TypeOf ctl Is PictureBox Then
AddHandler ctl.MouseEnter, AddressOf PictureBox_MouseEnter
AddHandler ctl.MouseLeave, AddressOf PictureBox_MouseLeave
End If
Next
' Add handler for the TreeView selection
AddHandler trvTextures.AfterSelect, AddressOf TrvTextures_AfterSelect
End Sub
Private Sub TrvTextures_AfterSelect(sender As Object, e As TreeViewEventArgs)
If e.Node IsNot Nothing AndAlso e.Node.Tag IsNot Nothing Then
Dim selectedFilePath As String = e.Node.Tag.ToString()
' Check if the file exists and is a valid image file
If File.Exists(selectedFilePath) AndAlso (Path.GetExtension(selectedFilePath).ToLower() = ".png" OrElse _
Path.GetExtension(selectedFilePath).ToLower() = ".jpg" OrElse _
Path.GetExtension(selectedFilePath).ToLower() = ".jpeg") Then
' Load the image as the floor
Dim newFloorImage As Image = Image.FromFile(selectedFilePath)
' Assuming you have a method to update the floor's background/image, call it here
UpdateFloorImage(newFloorImage)
' Invalidate the picGame control to refresh the display
picGame.Invalidate()
End If
End If
End Sub
Private Sub UpdateFloorImage(newImage As Image)
' Assuming you store the floor image in a variable or a property
' You can add logic to set the image to whatever floor control you are using
' For example:
' selectedFloorImage = newImage
' This is where you would handle the visual change of the floor
' You may need to draw or render the new floor image in your painting logic
' You could also use a PictureBox or directly change the background of the grid
End Sub
```
### Step 3: Update the Floor Drawing Logic
You probably have existing drawing logic for the floors. You need to update that logic to respect the new floor images. Ensure you're using the `selectedFloorImage` or however you've chosen to store your current floor image when you paint your grid.
By setting up your TreeView's selection and image loading logic as shown, clicking a child node would change the floor visual accordingly based on the selected image file.0d5c453b80b101ea6718991cCan you write this?
Private Sub UpdateFloorImage(newImage As Image)
' Assuming you store the floor image in a variable or a property
' You can add logic to set the image to whatever floor control you are using
' For example:
' selectedFloorImage = newImage
' This is where you would handle the visual change of the floor
' You may need to draw or render the new floor image in your painting logic
' You could also use a PictureBox or directly change the background of the grid
End Sub
Certainly! Below is a complete implementation of the `UpdateFloorImage` method that integrates the new floor image into your existing drawing logic for the game grid. This example assumes you have a way to set a floor image, and you will modify the painting logic to use that image.
### Implementation of `UpdateFloorImage`
```vb
' Declare a variable to store the selected floor image
Private selectedFloorImage As Image = Nothing ' Initialize as Nothing or set a default image
Private Sub UpdateFloorImage(newImage As Image)
' Store the new floor image
selectedFloorImage = newImage
' Invalidate the game panel to trigger a redraw
picGame.Invalidate()
End Sub
```
### Update the Drawing Logic
You will also need to update the `Paint` event handler of the `picGame` control to actually draw the `selectedFloorImage` instead of just using a fill style.
Here’s a modified version of your `PicGame_Paint` method to incorporate the floor image:
```vb
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' Draw the grid
DrawGrid(e.Graphics)
' Draw the floor image if available
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY - 1
If selectedFloorImage IsNot Nothing Then
Dim floorRect As New Rectangle(
INDENT + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
INDENT + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
SQSizeX,
SQSizeY)
e.Graphics.DrawImage(selectedFloorImage, floorRect)
End If
Next
Next
' Additional drawing logic for walls, items, etc.
' ...
End Sub
```
### Explanation:
1. **`selectedFloorImage` Variable**: This variable holds the image that will be used for the floor. It should be defined at the class level.
2. **`UpdateFloorImage` Method**: This method updates `selectedFloorImage` and triggers a repaint of `picGame`. This causes the new floor image to be drawn in the next `Paint` event of the `picGame`.
3. **Drawing the Floor Image**: In the `PicGame_Paint` method, the new code iterates through the grid and draws the `selectedFloorImage` over each cell. Depending on your design, you might want to customize how the image is applied to accommodate any needs for alignment or scaling.
Ensure that you handle cases where no image has been selected and provide some fallback visuals (like a default pattern or color) if needed.fa448a52aa1a8d04fe762b02Not drawing?
If the floor image is not being drawn as expected, there may be several reasons why it's not appearing. Below are the steps to ensure the floor image is rendered correctly, as well as some troubleshooting tips:
### Complete Implementation Plan
1. **Ensure the Image is Assigned**: Verify that the `UpdateFloorImage` method is called with a valid image. Ensure you are indeed selecting an image in the `trvTextures` and that it gets passed to `UpdateFloorImage`.
2. **Check the `PicGame_Paint` Method**: Make sure that the logic in the `PicGame_Paint` is correctly implemented to draw the floor image, as shown below. The drawing should ideally take place after clearing the previous frame and setting up the base grid.
Here's how you could finalize your drawing code:
### Updated `PicGame_Paint` Method
```vb
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' Draw the grid
DrawGrid(e.Graphics)
' Draw the floor image if available
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY - 1
If selectedFloorImage IsNot Nothing Then
Dim floorRect As New Rectangle(
INDENT + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
INDENT + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
SQSizeX,
SQSizeY)
e.Graphics.DrawImage(selectedFloorImage, floorRect)
End If
Next
Next
' Additional drawing logic for walls, items, etc.
DrawItems(e.Graphics)
DrawWallItems(e.Graphics)
' Draw triggers if needed
DrawTriggers(e.Graphics)
' Draw the selection rectangle if applicable
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
End Sub
```
### Troubleshooting Tips
1. **Check Image Validity**:
- Make sure the image path is correct and that it points to a valid image file (e.g., PNG, JPG).
- Confirm that the image loads correctly in the `UpdateFloorImage` method.
2. **Debug the Drawing Code**:
- You can add debug prints to ensure that the `selectedFloorImage` is not `Nothing` when the `PicGame_Paint` method runs.
```vb
Debug.WriteLine("Selected Floor Image Is Nothing: " & (selectedFloorImage Is Nothing).ToString())
```
3. **Z-order of Drawing**:
- Ensure the drawing order is correct: Draw the background first, then the floors, then the walls, and finally any items or overlays.
- Revisit where you call the `Invalidate` method. If `picGame` does not refresh properly after an image is set, you may still see an old state.
4. **Check Image Dimensions**:
- Ensure `SQSizeX` and `SQSizeY` values are greater than zero, so you have a valid rectangle to draw on.
- If the image dimensions are larger than the cell size, it may not fit properly.
5. **Test with a Known Good Image**:
- You may want to hardcode a known-good image in the `UpdateFloorImage` method to verify that your drawing logic is working:
```vb
selectedFloorImage = Image.FromFile("path_to_a_known_image.png")
```
6. **Invalidate and Refresh**:
- Confirm that after changing `selectedFloorImage`, you’re calling `Invalidate()` on `picGame` to trigger a redraw.
By following these guidelines and troubleshooting steps, you should be able to successfully implement the functionality that changes the floor image based on the selected texture from your `trvTextures` TreeView. If issues persist, you might need to inspect the surrounding logic that interacts with the grid and floor images.1e7e5f429a3f5dfdadfdc70fIt's drawing. But it's EXTREMELY laggy. Are you tiling them? We need to draw them in 1 image. Not tiled.
If you want to draw a single image for the floor rather than tiling it for each cell, you can modify the drawing logic accordingly. Instead of drawing the same image for every grid cell, you'll want to draw the floor image once, filling the entire space of your grid.
Here's how to implement drawing the floor as a single image:
### Step 1: Update `UpdateFloorImage`
Make sure you keep the full image for your floor without worrying about tiling within the `PicGame_Paint` method.
### Step 2: Update `PicGame_Paint` Method
Instead of looping through each cell in the grid to draw the image, you can set up the `PicGame_Paint` method to draw the image over the entire grid area.
Here’s how you can do that:
### Updated `PicGame_Paint` Method
```vb
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' Draw the grid only if needed (for walls or items)
DrawGrid(e.Graphics)
' Draw the floor image once, spanning the entire area
If selectedFloorImage IsNot Nothing Then
Dim floorWidth As Integer = SQCOUNTX * (SQSizeX + WALL_THICKNESS) - WALL_THICKNESS
Dim floorHeight As Integer = SQCOUNTY * (SQSizeY + WALL_THICKNESS) - WALL_THICKNESS
Dim floorRect As New Rectangle(
INDENT,
INDENT,
floorWidth,
floorHeight
)
e.Graphics.DrawImage(selectedFloorImage, floorRect);
End If
' Draw items on top
DrawItems(e.Graphics)
DrawWallItems(e.Graphics)
' Highlight and selection logic
DrawHighlight(e.Graphics)
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
' Draw triggers if needed
DrawTriggers(e.Graphics)
End Sub
```
### Explanation:
1. **One Image**: This code draws the selected floor image once as a single rectangle that covers the entire area. You calculate the width and height based on the number of squares and the dimensions of each square, minus the wall thickness.
2. **Avoid Loops**: By removing the loop that draws the image per cell, you're reducing the number of drawing calls, which should help improve performance.
3. **Drawing Order**: Make sure to draw the floor first, followed by walls, items, and any highlights or selections, ensuring they stack correctly.
### Step 3: Optimize Image Loading
1. **Single Image**: Ensure that your floor image is a single, well-optimized image. If drawing multiple smaller textures is causing performance issues, a single larger image would help avoid that.
2. **Image Size**: Make sure the size of your selected image is appropriate for your game. Large images that need to be constantly redrawn can lead to lag, especially if they are not properly sized.
3. **Graphics Optimization**: Ensure that you set up the graphics environment to best suit the drawing by considering `e.Graphics.PixelOffsetMode`.
If there are still performance issues, profiling what takes the most time in your drawing routine (like measuring the execution time of the painting code and calls) can help you identify bottlenecks you may need to address.7a948e024ce0602e2d06bb3eYour picPaint is missig tons of code...
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' Draw the grid
DrawGrid(e.Graphics)
' Draw the floor image if available
For x As Integer = 0 To SQCOUNTX - 1
For y As Integer = 0 To SQCOUNTY - 1
If selectedFloorImage IsNot Nothing Then
Dim floorRect As New Rectangle(
INDENT + (x * (SQSizeX + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
INDENT + (y * (SQSizeY + WALL_THICKNESS)) + (WALL_THICKNESS \ 2),
SQSizeX,
SQSizeY)
e.Graphics.DrawImage(selectedFloorImage, floorRect)
End If
Next
Next
' Draw any dragged item
If isDraggingItem AndAlso draggedItem IsNot Nothing Then
Dim img As Image = GetImageByKey(draggedItem.ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim drawRect As Rectangle
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
Dim wallWidth As Integer = WALL_THICKNESS
Dim wallHeight As Integer = SQSizeY
Dim xPos As Integer = mouseX - (WALL_THICKNESS \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
Dim newWidth As Integer = img.Width
Dim newHeight As Integer = wallHeight
Dim centeredX As Integer = xPos + ((wallWidth - newWidth) \ 2)
drawRect = New Rectangle(centeredX, yPos, newWidth, newHeight)
Else
Dim wallWidth As Integer = SQSizeX
Dim wallHeight As Integer = WALL_THICKNESS
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (WALL_THICKNESS \ 2)
Dim newWidth As Integer = wallWidth
Dim newHeight As Integer = img.Height
Dim centeredY As Integer = yPos + ((wallHeight - newHeight) \ 2)
drawRect = New Rectangle(xPos, centeredY, newWidth, newHeight)
End If
Else
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
drawRect = New Rectangle(xPos, yPos, SQSizeX, SQSizeY)
End If
e.Graphics.DrawImage(img, drawRect)
End If
End If
' Draw selection rectangle
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
' Draw selection data during drag
If isDraggingSelection Then
Dim baseCellX As Integer = (selectionRectangle.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim baseCellY As Integer = (selectionRectangle.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Ensure selectionData is valid before drawing
If selectionData IsNot Nothing Then
If isCopying Then
DrawSelectionData(e.Graphics, baseCellX, baseCellY, copiedSelectionData)
Else
DrawSelectionData(e.Graphics, baseCellX, baseCellY, selectionData)
End If
Else
Debug.WriteLine("selectionData is Nothing. Skipping drawing.")
End If
End If
' Ensure DrawHighlight is called
DrawHighlight(e.Graphics)
' Draw triggers
DrawTriggers(e.Graphics)
End Sub
Thank you for your patience! If you want to optimize the drawing routine while still incorporating all the necessary elements in your `PicGame_Paint` method, here's a modified version that draws a single floor image instead of tiling it across the grid while keeping all other drawing logic intact.
### Complete and Optimized `PicGame_Paint` Method
Here’s how you can modify the method to draw the entire floor as one image while keeping the existing functionality:
```vb
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' Draw the grid
DrawGrid(e.Graphics)
' Draw the floor image if available, span the entire grid area
If selectedFloorImage IsNot Nothing Then
Dim floorWidth As Integer = SQCOUNTX * (SQSizeX + WALL_THICKNESS) - WALL_THICKNESS
Dim floorHeight As Integer = SQCOUNTY * (SQSizeY + WALL_THICKNESS) - WALL_THICKNESS
Dim floorRect As New Rectangle(
INDENT,
INDENT,
floorWidth,
floorHeight
)
e.Graphics.DrawImage(selectedFloorImage, floorRect)
End If
' Draw any dragged item
If isDraggingItem AndAlso draggedItem IsNot Nothing Then
Dim img As Image = GetImageByKey(draggedItem.ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim drawRect As Rectangle
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
Dim wallWidth As Integer = WALL_THICKNESS
Dim wallHeight As Integer = SQSizeY
Dim xPos As Integer = mouseX - (WALL_THICKNESS \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
Dim newWidth As Integer = img.Width
Dim newHeight As Integer = wallHeight
Dim centeredX As Integer = xPos + ((wallWidth - newWidth) \ 2)
drawRect = New Rectangle(centeredX, yPos, newWidth, newHeight)
Else
Dim wallWidth As Integer = SQSizeX
Dim wallHeight As Integer = WALL_THICKNESS
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (WALL_THICKNESS \ 2)
Dim newWidth As Integer = wallWidth
Dim newHeight As Integer = img.Height
Dim centeredY As Integer = yPos + ((wallHeight - newHeight) \ 2)
drawRect = New Rectangle(xPos, centeredY, newWidth, newHeight)
End If
Else
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
drawRect = New Rectangle(xPos, yPos, SQSizeX, SQSizeY)
End If
e.Graphics.DrawImage(img, drawRect)
End If
End If
' Draw selection rectangle
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
' Draw selection data during drag
If isDraggingSelection Then
Dim baseCellX As Integer = (selectionRectangle.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim baseCellY As Integer = (selectionRectangle.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Ensure selectionData is valid before drawing
If selectionData IsNot Nothing Then
If isCopying Then
DrawSelectionData(e.Graphics, baseCellX, baseCellY, copiedSelectionData)
Else
DrawSelectionData(e.Graphics, baseCellX, baseCellY, selectionData)
End If
Else
Debug.WriteLine("selectionData is Nothing. Skipping drawing.")
End If
End If
' Ensure DrawHighlight is called
DrawHighlight(e.Graphics)
' Draw triggers
DrawTriggers(e.Graphics)
End Sub
```
### Key Changes and Considerations
1. **Single Drawing of Floor Image**: The floor image is drawn once to cover the entire grid area. This should improve performance significantly, especially if the original implementation caused lag due to multiple draw calls for each grid cell.
2. **Keep Existing Logic**: The remaining logic for drawing dragged items, selection rectangles, and triggers is preserved and will function normally.
3. **Potential Image Sizing**: Ensure the `selectedFloorImage` you want to use is appropriately sized or designed to fit within the grid dimensions without excessive scaling or shifting, as the bounds calculated may be larger than the image.
4. **Performance Improvements**: Check if the `selectedFloorImage` is being loaded only when necessary, perhaps in the `UpdateFloorImage` method, and that any redundant image processing isn't causing performance drops.
This should address the lag issue by minimizing the number of drawing operations while still achieving the desired result in your game grid. If you continue to experience lag, it may be beneficial to profile the drawing process or consider optimizing image handling further.5571a7228363f4ee86fc7700It shouldn't stretch. Also. It's the floor. It should be drawn first. and everything else drawn on top
To properly handle the floor image drawing while ensuring that it is drawn without stretching, and to maintain the proper stacking order (drawing the floor first and everything else on top), let’s revise the `PicGame_Paint` method.
### Key Points:
1. **Draw the Floor First**: The floor should be the first thing drawn onto the Graphics object.
2. **Do Not Stretch the Floor Image**: Ensure the image retains its original size.
3. **Layering**: After drawing the floor, you can draw walls, items, and any other dynamic elements.
### Updated `PicGame_Paint` Method
Here's how the `PicGame_Paint` method can be structured to meet these requirements:
```vb
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' Draw the gradient background if useGradient is true
If useGradient Then
DrawGradientBackground(e.Graphics)
End If
' --------------------------------------------------
' Draw the floor image if available, centered in the grid
' --------------------------------------------------
If selectedFloorImage IsNot Nothing Then
' Calculate the total width and height of the grid area
Dim floorWidth As Integer = SQCOUNTX * (SQSizeX + WALL_THICKNESS) ' Total width including walls
Dim floorHeight As Integer = SQCOUNTY * (SQSizeY + WALL_THICKNESS) ' Total height including walls
' Calculate the position to center the floor image
Dim floorX As Integer = INDENT + (floorWidth - selectedFloorImage.Width) \ 2
Dim floorY As Integer = INDENT + (floorHeight - selectedFloorImage.Height) \ 2
' Create a rectangle for the floor image
Dim floorRect As New Rectangle(floorX, floorY, selectedFloorImage.Width, selectedFloorImage.Height)
' Draw the floor image
e.Graphics.DrawImage(selectedFloorImage, floorRect)
End If
' --------------------------------------------------
' Draw the grid
' --------------------------------------------------
DrawGrid(e.Graphics)
' --------------------------------------------------
' Draw walls, items, and selections over the floor
' --------------------------------------------------
' Draw any dragged item
If isDraggingItem AndAlso draggedItem IsNot Nothing Then
Dim img As Image = GetImageByKey(draggedItem.ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim drawRect As Rectangle
' Positioning logic based on dragged item's type (wall vs. regular item)
If draggedItemIsWall Then
If draggedItemIsVerticalWall Then
Dim wallWidth As Integer = WALL_THICKNESS
Dim wallHeight As Integer = SQSizeY
Dim xPos As Integer = mouseX - (WALL_THICKNESS \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
Dim newWidth As Integer = img.Width
Dim newHeight As Integer = wallHeight
Dim centeredX As Integer = xPos + ((wallWidth - newWidth) \ 2)
drawRect = New Rectangle(centeredX, yPos, newWidth, newHeight)
Else
Dim wallWidth As Integer = SQSizeX
Dim wallHeight As Integer = WALL_THICKNESS
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (WALL_THICKNESS \ 2)
Dim newWidth As Integer = wallWidth
Dim newHeight As Integer = img.Height
Dim centeredY As Integer = yPos + ((wallHeight - newHeight) \ 2)
drawRect = New Rectangle(xPos, centeredY, newWidth, newHeight)
End If
Else
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
drawRect = New Rectangle(xPos, yPos, SQSizeX, SQSizeY)
End If
e.Graphics.DrawImage(img, drawRect)
End If
End If
' Draw selection rectangle
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
' Draw selection data during drag
If isDraggingSelection Then
Dim baseCellX As Integer = (selectionRectangle.X - INDENT) \ (SQSizeX + WALL_THICKNESS)
Dim baseCellY As Integer = (selectionRectangle.Y - INDENT) \ (SQSizeY + WALL_THICKNESS)
' Ensure selectionData is valid before drawing
If selectionData IsNot Nothing Then
If isCopying Then
DrawSelectionData(e.Graphics, baseCellX, baseCellY, copiedSelectionData)
Else
DrawSelectionData(e.Graphics, baseCellX, baseCellY, selectionData)
End If
Else
Debug.WriteLine("selectionData is Nothing. Skipping drawing.")
End If
End If
' Draw highlights
DrawHighlight(e.Graphics)
' Draw triggers
DrawTriggers(e.Graphics)
End Sub
```
### Key Improvements:
1. **Floor Image Drawing**: The floor image is drawn once at a calculated center position, which ensures it is not stretched or tiled erroneously across the grid. This is done using the dimensions of the grid to determine where to place the image.
2. **Order of Drawing**: The floor is the first thing drawn. The grid, walls, items, and selections are drawn on top of the floor, ensuring proper layering.
3. **Image Size**: The image maintains its size and aspect ratio by directly using its width and height to create the drawing rectangle.
### Summary
This code ensures that the desired floor image is drawn correctly at a specific central position on the grid without stretching, and that all relevant elements are layered appropriately during the painting process. If you encounter any further issues or require additional modifications, feel free to ask!1503691efeef918d605e9b98It should replace the gradient floor and hatchstyle floor. And Not be drawn outside of the grid.
To ensure that the floor image replaces the gradient and hatch style fill, while ensuring it is only drawn within the confines of the grid and not outside the grid boundary, we will modify the `PicGame_Paint` method accordingly.
Here’s the updated approach:
1. **Remove Existing Gradient and Hatch Style Drawing**: Ensure that once a floor image is selected, it overrides previous floor styles.
2. **Calculate Proper Bounds**: The drawing of the image will respect the grid bounds, ensuring it does not extend beyond the grid.
3. **Maintain Layering**: The floor image will still be drawn first, followed by any walls, items, and selections.
### Updated `PicGame_Paint` Method
Here's how the method should look:
```vb
Private Sub PicGame_Paint(sender As Object, e As PaintEventArgs) Handles picGame.Paint
' Calculate the sizes of the squares based on the client size of picGame
CalculateSquareSizes(picGame.ClientSize.Width, picGame.ClientSize.Height)
' Set the smoothing mode to None for pixel-perfect drawing
e.Graphics.SmoothingMode = SmoothingMode.None
' --------------------------------------------------
' Draw the grid (this will be the outline; no fill)
' --------------------------------------------------
DrawGrid(e.Graphics)
' --------------------------------------------------
' Draw the floor image if available
' --------------------------------------------------
If selectedFloorImage IsNot Nothing Then
Dim floorWidth As Integer = SQCOUNTX * SQSizeX + (SQCOUNTX + 1) * WALL_THICKNESS ' total grid width, including walls
Dim floorHeight As Integer = SQCOUNTY * SQSizeY + (SQCOUNTY + 1) * WALL_THICKNESS ' total grid height, including walls
' Create a rectangle for the floor image that matches grid bounds
Dim floorRect As New Rectangle(
INDENT,
INDENT,
floorWidth,
floorHeight
)
' Draw the floor image within the calculated bounds
e.Graphics.DrawImage(selectedFloorImage, floorRect)
End If
' Now we draw any dragged item
If isDraggingItem AndAlso draggedItem IsNot Nothing Then
Dim img As Image = GetImageByKey(draggedItem.ImageKey)
If img IsNot Nothing Then
ImageAnimator.UpdateFrames(img)
Dim drawRect As Rectangle
If draggedItemIsWall Then
' Wall item handling
If draggedItemIsVerticalWall Then
Dim wallWidth As Integer = WALL_THICKNESS
Dim wallHeight As Integer = SQSizeY
Dim xPos As Integer = mouseX - (WALL_THICKNESS \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
Dim newWidth As Integer = img.Width
Dim newHeight As Integer = wallHeight
Dim centeredX As Integer = xPos + ((wallWidth - newWidth) \ 2)
drawRect = New Rectangle(centeredX, yPos, newWidth, newHeight)
Else
Dim wallWidth As Integer = SQSizeX
Dim wallHeight As Integer = WALL_THICKNESS
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (WALL_THICKNESS \ 2)
Dim newWidth As Integer = wallWidth
Dim newHeight As Integer = img.Height
Dim centeredY As Integer = yPos + ((wallHeight - newHeight) \ 2)
drawRect = New Rectangle(xPos, centeredY, newWidth, newHeight)
End If
Else
' Regular item handling
Dim xPos As Integer = mouseX - (SQSizeX \ 2)
Dim yPos As Integer = mouseY - (SQSizeY \ 2)
drawRect = New Rectangle(xPos, yPos, SQSizeX, SQSizeY)
End If
e.Graphics.DrawImage(img, drawRect)
End If
End If
' --------------------------------------------------
' Draw selection rectangle if in selection mode
' --------------------------------------------------
If (isInSelectionMode OrElse isSelectionReadyToDrag OrElse isDraggingSelection) AndAlso Not selectionRectangle.IsEmpty Then
Using selectionBrush As New SolidBrush(Color.FromArgb(64, Color.Blue))
e.Graphics.FillRectangle(selectionBrush, selectionRectangle)
End Using
Using selectionPen As New Pen(Color.Blue, 2) With {.DashStyle = DashStyle.Dash}
e.Graphics.DrawRectangle(selectionPen, selectionRectangle)
End Using
End If
' --------------------------------------------------
' Draw additional logic pertaining to well items, highlights, and triggers.
' --------------------------------------------------
DrawHighlight(e.Graphics)
DrawTriggers(e.Graphics)
End Sub
```
### Key Modifications Explained:
1. **Grid Drawing**: The `DrawGrid` method is called without filled-in drawing. It should only draw outlines or separators between the areas.
2. **Floor Image Bounds**: A rectangle (`floorRect`) is created that spans the entire grid area, ensuring the floor image does not stretch but is centered and respects the overall grid size.
3. **Layering**: The order of drawing ensures that the floor is drawn first, followed by other components (dragged items, selection rectangles, and triggers).
4. **Selection**: A selection rectangle is drawn on top of all components if currently selecting with sufficient visibility.
### Notes for Implementation:
- **Update Logic for Selected Floor Image**: Ensure that your `UpdateFloorImage` method captures the image correctly, and if you want to replace hatch styles or gradient fills, make sure those operations are consistent throughout your grid-drawing logic.
- **Grid Bounds**: Adjust accordingly if you have a specific way of measuring grid bounds to avoid going out of bounds.
By implementing these changes, the selected floor image should replace all previous fill styles and behave as expected within the grid. If you have any further tweaks or issues, let me know!d57cd099a543f484d6bed2a7Câu hỏi có phù hợp với nội dung không (trả lời có hoặc không)? Câu hỏi: Mình cần làm gì để xem lịch sử phí dịch vụ đã nhập trên Fabi? Câu trả lời: Trên CMS nhà hàng bật cấu hình "Cho phép tự nhập phí dịch vụ" thì nhân viên có thê nhập phí dịch vụ vào đơn hàng. Nếu nhà hàng tạo phí dịch vụ từ CMS, phí sẽ tự động thêm vào đơn hàng nếu thỏa mãn điều kiện.
Không.
d2cb7b1c82fa78175cc1c904Câu hỏi có phù hợp với nội dung không (trả lời có hoặc không)? Câu hỏi: Có bước nào quan trọng khi nhập phí dịch vụ trên Fabi không? Câu trả lời: Trên CMS nhà hàng bật cấu hình "Cho phép tự nhập phí dịch vụ" thì nhân viên có thê nhập phí dịch vụ vào đơn hàng. Nếu nhà hàng tạo phí dịch vụ từ CMS, phí sẽ tự động thêm vào đơn hàng nếu thỏa mãn điều kiện.
Có.