#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseUpx=y #AutoIt3Wrapper_Res_Fileversion=1.0.0.0 #AutoIt3Wrapper_Res_Language=1033 #AutoIt3Wrapper_Res_requestedExecutionLevel=None #AutoIt3Wrapper_Add_Includes=n #AutoIt3Wrapper_AU3Check_Stop_OnWarning=y #AutoIt3Wrapper_AU3Check_Parameters=-w 1 -w 2 -w- 4 -w 6 #AutoIt3Wrapper_Run_Stop_OnError=y #AutoIt3Wrapper_Run_Tidy=y #Tidy_Parameters=/rel #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/so /rm #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include-once #include #include #include #include #include ; ================================================================ ; REVERSE PAC-MAN ; You are the ghost. Eat everything on the screen. ; Pacs kill you when they touch you from the side or from behind. ; Head-on contact (you are in front of the pac's mouth) destroys the pac. ; Controls: Arrow keys / WASD, ESC = quit, SPACE = start / retry ; ================================================================ Global $sText = @UserName ; --- Game settings --- Global Const $GHOST_R = 22 ; ghost radius Global Const $GHOST_SPEED = 6 ; pixels per frame Global Const $FRONT_HALF_ANGLE = 55 ; degrees: contact inside this cone in front of a pac counts as "head-on" Global Const $FRONT_KILLS_PAC = True ; True = head-on contact destroys the pac, False = head-on contact is harmless Global Const $WIN_PERCENT = 92 ; screen percentage that must be eaten to win Global Const $CELL = 24 ; size of one coverage cell (pixels) Global Const $PAC_MAX = 8 ; max number of pacs from the timed spawn Global Const $PAC_SPAWN_MS = 15000 ; a new pac appears every x ms Global Const $HUD_W = 520, $HUD_H = 44 ; --- Pac settings --- ; Pac: [x, y, r, colorIdx, vx, vy, mouthOpen, mouthDir] Global $aPac[1][8], $iPac = 0 Global Const $PAC_R_START_MIN = 16, $PAC_R_START_MAX = 26 Global Const $PAC_R_SPLIT = 55 ; a pac splits once it reaches this size Global Const $PAC_R_MIN = 14 ; size after splitting Global Const $PAC_GROW_MIN = 3, $PAC_GROW_MAX = 6 ; growth per eaten pellet Global Const $PAC_SPEED_FAST = 4.5 ; base speed (freshly spawned / after split) Global Const $PAC_SPEED_MIN = 1.2 ; never gets slower than this Global Const $PAC_SLOWDOWN = 0.93 ; speed factor per eaten pellet Global Const $PAC_SPRITE_PAD = 3 Global Const $PAC_ALPHA = 0xE8 Global Const $BLUR_RADIUS = 3 Global Const $BLUR_PAD = 4 Global Const $TRAIL_TINT = 0x0C Global Const $BLUR_MARGIN = 12 Global Const $EAT_PAD = 3 Global Const $TEXT_GLOW = 0x18 ; --- Layers --- ; Shot = screenshot layer (opaque), blurred by the pacs, blacked out by the ghost ; Neon = neon layer (transparent), erased by pacs and ghost ; Comp = finished picture: Shot + Neon + sprites + HUD. Only this goes to the window. Global $g_hBuf = 0, $g_hCtx = 0 Global $g_hNeon = 0, $g_hNeonCtx = 0 Global $g_hComp = 0, $g_hCompCtx = 0 Global $g_iBufW = 0, $g_iBufH = 0 Global $g_hBlur = 0, $g_hClear = 0, $g_hBlack = 0, $g_aTint[6] Global $g_hShotImg = 0 Global $g_hHudFam = 0, $g_hHudFnt = 0, $g_hHudFmt = 0, $g_hHudBrush = 0, $g_hHudBg = 0 ; Dirty rects Global Const $DIRTY_MAX = 256 Global $aDirty[$DIRTY_MAX][4], $iDirty = 0, $bDirtyAll = False ; Food pellets: [x, y, r, colorIdx], r <= 0 means empty / eaten Global Const $FOOD_MAX = 70 Global $aFood[$FOOD_MAX][4], $iFoodPtr = 0 ; Bite spots: neon effects preferably spawn where pacs have been Global Const $BITE_MAX = 30 Global $aBites[$BITE_MAX][2], $iBitePtr = 0, $iBiteCount = 0 ; --- Ghost / game state --- Global $g_fGX = 0, $g_fGY = 0 ; ghost position Global $g_fFX = 1, $g_fFY = 0 ; ghost facing direction (for the eyes) Global $g_iAnim = 0 ; frame counter (skirt animation) Global $g_bGhostDead = False Global $g_iScore = 0 Global $g_hTimer = 0 Global $g_iCols = 0, $g_iRows = 0, $g_iCellsTotal = 1, $g_iCellsEaten = 0 Global $g_aCell[1] _Game() ; ================================================================ ; Main ; ================================================================ Func _Game() ; Per-monitor DPI aware (must happen before any window exists) DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", -4) Local $iSW = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 0)[0] ; primary monitor width Local $iSH = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 1)[0] ; primary monitor height ; Capture the desktop BEFORE our own window exists Local $hShotBMP = _ScreenCapture_Capture("", 0, 0, $iSW, $iSH, False) Local $hGUI = GUICreate("Reverse Pac-Man", $iSW, $iSH, 0, 0, $WS_POPUP, $WS_EX_TOPMOST) GUISetBkColor(0x000000) GUISetCursor(16, 1, $hGUI) ; hide mouse cursor GUISetState() _GDIPlus_Startup() Local $hGfx = _GDIPlus_GraphicsCreateFromHWND($hGUI) _GDIPlus_GraphicsSetInterpolationMode($hGfx, 5) _GDIPlus_GraphicsClear($hGfx, 0xFF000000) $g_iBufW = $iSW $g_iBufH = $iSH ; Layer 1: screenshot (opaque) $g_hBuf = _GDIPlus_BitmapCreateFromScan0($iSW, $iSH) $g_hCtx = _GDIPlus_ImageGetGraphicsContext($g_hBuf) _GDIPlus_GraphicsSetInterpolationMode($g_hCtx, 5) _GDIPlus_GraphicsSetSmoothingMode($g_hCtx, 2) _GDIPlus_GraphicsClear($g_hCtx, 0xFF000000) ; Layer 2: neon (transparent) $g_hNeon = _GDIPlus_BitmapCreateFromScan0($iSW, $iSH) $g_hNeonCtx = _GDIPlus_ImageGetGraphicsContext($g_hNeon) _GDIPlus_GraphicsSetTextRenderingHint($g_hNeonCtx, 4) ; Finished picture $g_hComp = _GDIPlus_BitmapCreateFromScan0($iSW, $iSH) $g_hCompCtx = _GDIPlus_ImageGetGraphicsContext($g_hComp) _GDIPlus_GraphicsSetInterpolationMode($g_hCompCtx, 5) _GDIPlus_GraphicsSetSmoothingMode($g_hCompCtx, 2) _GDIPlus_GraphicsSetTextRenderingHint($g_hCompCtx, 4) ; Effects + brushes $g_hBlur = _GDIPlus_EffectCreateBlur($BLUR_RADIUS, False) For $t = 0 To 5 $g_aTint[$t] = _GDIPlus_BrushCreateSolid(_NeonIdx($t, $TRAIL_TINT)) Next $g_hClear = _GDIPlus_BrushCreateSolid(0x00000000) $g_hBlack = _GDIPlus_BrushCreateSolid(0xFF000000) ; HUD resources $g_hHudFam = _GDIPlus_FontFamilyCreate("Consolas") $g_hHudFnt = _GDIPlus_FontCreate($g_hHudFam, 18, 1) $g_hHudFmt = _GDIPlus_StringFormatCreate() $g_hHudBrush = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) $g_hHudBg = _GDIPlus_BrushCreateSolid(0xB0000000) ; Keep the screenshot, so every new round can start with a fresh desktop If $hShotBMP <> 0 Then $g_hShotImg = _GDIPlus_BitmapCreateFromHBITMAP($hShotBMP) ; Title screen Local $iResult, $bRun _ResetGame($iSW, $iSH) _Compose($hGfx) _Banner($hGfx, $iSW, $iSH, "REVERSE PAC-MAN", "You are the ghost - eat everything!" & @LF & "Arrows / WASD = move" & @LF & "Pacs kill you from the side or from behind." & @LF & "Head-on contact destroys them." & @LF & @LF & "SPACE = start ESC = quit", 1) $bRun = _WaitSpace() While $bRun _ResetGame($iSW, $iSH) $iResult = _PlayRound($hGfx, $iSW, $iSH) If $iResult = 0 Then ExitLoop Local $sStats = "Score " & $g_iScore & " Eaten " & _EatenPct() & "%" & @LF & @LF & "SPACE = play again ESC = quit" If $iResult = 1 Then _Banner($hGfx, $iSW, $iSH, "GAME OVER", $sStats, 0) Else _Banner($hGfx, $iSW, $iSH, "YOU ATE EVERYTHING!", $sStats, 2) EndIf $bRun = _WaitSpace() WEnd ; Cleanup For $t = 0 To 5 _GDIPlus_BrushDispose($g_aTint[$t]) Next _GDIPlus_BrushDispose($g_hClear) _GDIPlus_BrushDispose($g_hBlack) _GDIPlus_BrushDispose($g_hHudBrush) _GDIPlus_BrushDispose($g_hHudBg) _GDIPlus_StringFormatDispose($g_hHudFmt) _GDIPlus_FontDispose($g_hHudFnt) _GDIPlus_FontFamilyDispose($g_hHudFam) If $g_hBlur <> 0 Then _GDIPlus_EffectDispose($g_hBlur) _GDIPlus_GraphicsDispose($g_hCompCtx) _GDIPlus_BitmapDispose($g_hComp) _GDIPlus_GraphicsDispose($g_hNeonCtx) _GDIPlus_BitmapDispose($g_hNeon) _GDIPlus_GraphicsDispose($g_hCtx) _GDIPlus_BitmapDispose($g_hBuf) If $g_hShotImg <> 0 Then _GDIPlus_ImageDispose($g_hShotImg) If $hShotBMP <> 0 Then DllCall("gdi32.dll", "bool", "DeleteObject", "handle", $hShotBMP) _GDIPlus_GraphicsDispose($hGfx) _GDIPlus_Shutdown() GUIDelete($hGUI) EndFunc ;==>_Game ; Plays one round. Returns 0 = quit, 1 = ghost died, 2 = won Func _PlayRound($hGfx, $iSW, $iSH) Local $hFrame, $hSpawn = TimerInit() Local $bx, $by, $pick, $iType, $iWait While 1 $hFrame = TimerInit() If _IsPressed("1B") Then Return 0 ; 1) ghost: move + eat _MoveGhost($iSW, $iSH) _EatWithGhost() ; 2) pacs: move, eat, collide (also decides if the ghost dies) _UpdatePac($iSW, $iSH) ; 3) timed extra pac If TimerDiff($hSpawn) > $PAC_SPAWN_MS Then $hSpawn = TimerInit() If $iPac < $PAC_MAX Then _SpawnPac($iSW, $iSH) EndIf ; 4) random neon effect (= food for pacs and for the ghost) $bx = -1 $by = -1 If $iBiteCount > 0 And Random(1, 100, 1) <= 55 Then $pick = Random(0, $iBiteCount - 1, 1) $bx = $aBites[$pick][0] $by = $aBites[$pick][1] EndIf $iType = Random(1, 60, 1) Switch $iType Case 1 _DrawNeonLine($g_hNeonCtx, $iSW, $iSH) Case 2 _DrawNeonText($g_hNeonCtx, $iSW, $iSH) Case 3 _DrawNeonClock($g_hNeonCtx, $iSW, $iSH) Case 4 _DrawNeonStar($g_hNeonCtx, $iSW, $iSH, $bx, $by) Case 5 _DrawNeonTriangle($g_hNeonCtx, $iSW, $iSH, $bx, $by) Case 6 _DrawBgBlob($g_hNeonCtx, $iSW, $iSH, $bx, $by) Case Else _DrawNeonParticle($g_hNeonCtx, $iSW, $iSH, $bx, $by) EndSwitch ; 5) draw everything (the HUD area is redone every frame) _MarkDirty(0, 0, $HUD_W, $HUD_H) _Compose($hGfx) If $g_bGhostDead Then Return 1 If $g_iCellsEaten * 100 >= $g_iCellsTotal * $WIN_PERCENT Then Return 2 ; ~35 fps $iWait = 28 - TimerDiff($hFrame) If $iWait > 1 Then Sleep($iWait) WEnd EndFunc ;==>_PlayRound ; Resets everything for a new round Func _ResetGame($iSW, $iSH) ; Fresh desktop on the screenshot layer _GDIPlus_GraphicsClear($g_hCtx, 0xFF000000) If $g_hShotImg <> 0 Then _GDIPlus_GraphicsDrawImageRect($g_hCtx, $g_hShotImg, 0, 0, $iSW, $iSH) ; Empty neon layer _GDIPlus_GraphicsSetCompositingMode($g_hNeonCtx, 1) _GDIPlus_GraphicsFillRect($g_hNeonCtx, 0, 0, $iSW, $iSH, $g_hClear) _GDIPlus_GraphicsSetCompositingMode($g_hNeonCtx, 0) ; Food, bites For $f = 0 To $FOOD_MAX - 1 $aFood[$f][2] = 0 Next $iFoodPtr = 0 $iBitePtr = 0 $iBiteCount = 0 ; Coverage grid $g_iCols = Ceiling($iSW / $CELL) $g_iRows = Ceiling($iSH / $CELL) $g_iCellsTotal = $g_iCols * $g_iRows $g_iCellsEaten = 0 ReDim $g_aCell[$g_iCellsTotal] For $i = 0 To $g_iCellsTotal - 1 $g_aCell[$i] = 0 Next ; Ghost $g_fGX = $iSW / 2 $g_fGY = $iSH / 2 $g_fFX = 1 $g_fFY = 0 $g_iAnim = 0 $g_bGhostDead = False $g_iScore = 0 $g_hTimer = TimerInit() ; Pacs (spawned away from the ghost) ReDim $aPac[1][8] $iPac = 0 _SpawnPac($iSW, $iSH) _SpawnPac($iSW, $iSH) $iDirty = 0 $bDirtyAll = True EndFunc ;==>_ResetGame ; Waits for SPACE (True) or ESC (False) Func _WaitSpace() Sleep(600) ; so a key that is still pressed from the game doesn't skip the screen While 1 If _IsPressed("1B") Then Return False If _IsPressed("20") Then Return True Sleep(30) WEnd EndFunc ;==>_WaitSpace Func _EatenPct() Return Int($g_iCellsEaten * 100 / $g_iCellsTotal) EndFunc ;==>_EatenPct ; Dark box with a big title and some text, drawn straight onto the window Func _Banner($hGfx, $iSW, $iSH, $sTitle, $sSub, $iCi) Local $cx = $iSW / 2, $cy = $iSH / 2 Local $hBg = _GDIPlus_BrushCreateSolid(0xD8000000) _GDIPlus_GraphicsFillRect($hGfx, $cx - 460, $cy - 190, 920, 380, $hBg) _GDIPlus_BrushDispose($hBg) Local $hFam = _GDIPlus_FontFamilyCreate("Segoe UI") Local $hFmt = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFmt, 1) ; centered Local $hFntT = _GDIPlus_FontCreate($hFam, 48, 1) Local $hFntS = _GDIPlus_FontCreate($hFam, 20) Local $hBrT = _GDIPlus_BrushCreateSolid(_NeonIdx($iCi, 0xFF)) Local $hBrS = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) Local $tT = _GDIPlus_RectFCreate($cx - 450, $cy - 165, 900, 80) Local $tS = _GDIPlus_RectFCreate($cx - 450, $cy - 70, 900, 250) _GDIPlus_GraphicsDrawStringEx($hGfx, $sTitle, $hFntT, $tT, $hFmt, $hBrT) _GDIPlus_GraphicsDrawStringEx($hGfx, $sSub, $hFntS, $tS, $hFmt, $hBrS) _GDIPlus_BrushDispose($hBrT) _GDIPlus_BrushDispose($hBrS) _GDIPlus_FontDispose($hFntT) _GDIPlus_FontDispose($hFntS) _GDIPlus_StringFormatDispose($hFmt) _GDIPlus_FontFamilyDispose($hFam) EndFunc ;==>_Banner ; ================================================================ ; Ghost ; ================================================================ Func _MoveGhost($iSW, $iSH) Local $dx = 0, $dy = 0 If _IsPressed("25") Or _IsPressed("41") Then $dx -= 1 ; left / A If _IsPressed("27") Or _IsPressed("44") Then $dx += 1 ; right / D If _IsPressed("26") Or _IsPressed("57") Then $dy -= 1 ; up / W If _IsPressed("28") Or _IsPressed("53") Then $dy += 1 ; down / S Local $ox = $g_fGX, $oy = $g_fGY If $dx <> 0 Or $dy <> 0 Then Local $len = Sqrt($dx * $dx + $dy * $dy) $g_fFX = $dx / $len $g_fFY = $dy / $len $g_fGX += $g_fFX * $GHOST_SPEED $g_fGY += $g_fFY * $GHOST_SPEED EndIf $g_fGX = _Max($GHOST_R, _Min($iSW - $GHOST_R, $g_fGX)) $g_fGY = _Max($GHOST_R, _Min($iSH - $GHOST_R, $g_fGY)) $g_iAnim += 1 ; Old + new sprite area (the skirt wiggles, so it is redrawn every frame) Local $m = $GHOST_R + 6 _MarkDirty($ox - $m, $oy - $m, $m * 2, $m * 2) _MarkDirty($g_fGX - $m, $g_fGY - $m, $m * 2, $m * 2) EndFunc ;==>_MoveGhost ; The ghost eats everything under it: drawn stuff, pellets, and it blacks out the screenshot Func _EatWithGhost() Local $x = $g_fGX, $y = $g_fGY, $r = $GHOST_R _EraseNeon($x, $y, $r + $EAT_PAD, False) _GDIPlus_GraphicsFillEllipse($g_hCtx, $x - $r - 1, $y - $r - 1, ($r + 1) * 2, ($r + 1) * 2, $g_hBlack) ; Pellets of every color For $f = 0 To $FOOD_MAX - 1 If $aFood[$f][2] <= 0 Then ContinueLoop Local $fdx = $aFood[$f][0] - $x Local $fdy = $aFood[$f][1] - $y If Sqrt($fdx * $fdx + $fdy * $fdy) > $r + $aFood[$f][2] Then ContinueLoop _EraseNeon($aFood[$f][0], $aFood[$f][1], $aFood[$f][2] + 3) $aFood[$f][2] = 0 $g_iScore += 10 Next ; Coverage cells (a cell is eaten when the ghost reaches its center) Local $c0 = _Max(0, Int(($x - $r) / $CELL)), $c1 = _Min($g_iCols - 1, Int(($x + $r) / $CELL)) Local $r0 = _Max(0, Int(($y - $r) / $CELL)), $r1 = _Min($g_iRows - 1, Int(($y + $r) / $CELL)) For $cy = $r0 To $r1 For $cx = $c0 To $c1 Local $idx = $cy * $g_iCols + $cx If $g_aCell[$idx] = 1 Then ContinueLoop Local $mx = $cx * $CELL + $CELL / 2 - $x Local $my = $cy * $CELL + $CELL / 2 - $y If $mx * $mx + $my * $my > $r * $r Then ContinueLoop $g_aCell[$idx] = 1 $g_iCellsEaten += 1 $g_iScore += 1 Next Next EndFunc ;==>_EatWithGhost Func _DrawGhost(ByRef $hGfx) Local $x = $g_fGX, $y = $g_fGY, $r = $GHOST_R Local $iBody = 0xFFF2F2F2 If $g_bGhostDead Then $iBody = 0xFFFF3030 Local $hBody = _GDIPlus_BrushCreateSolid($iBody) ; Head: upper half circle _GDIPlus_GraphicsFillPie($hGfx, $x - $r, $y - $r, $r * 2, $r * 2, 180, 180, $hBody) ; Body with a wiggling skirt (7 bottom points, alternating down/up, swapping every 4 frames) Local $aPts[10][2] $aPts[0][0] = 9 $aPts[1][0] = $x - $r $aPts[1][1] = $y Local $s = Mod(Int($g_iAnim / 4), 2) For $j = 0 To 6 $aPts[$j + 2][0] = $x - $r + $j * ($r * 2 / 6) If Mod($j + $s, 2) = 0 Then $aPts[$j + 2][1] = $y + $r Else $aPts[$j + 2][1] = $y + $r * 0.72 EndIf Next $aPts[9][0] = $x + $r $aPts[9][1] = $y _GDIPlus_GraphicsFillPolygon($hGfx, $aPts, $hBody) _GDIPlus_BrushDispose($hBody) ; Eyes look in the moving direction Local $hWhite = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) Local $hPupil = _GDIPlus_BrushCreateSolid(0xFF2030FF) Local $er = $r * 0.3, $pr = $r * 0.16 Local $e, $ex, $ey For $e = -1 To 1 Step 2 $ex = $x + $e * $r * 0.4 $ey = $y - $r * 0.15 If $g_bGhostDead Then _GDIPlus_GraphicsFillEllipse($hGfx, $ex - $er, $ey - $er, $er * 2, $er * 2, $hWhite) _GDIPlus_GraphicsFillEllipse($hGfx, $ex - $pr, $ey - $pr, $pr * 2, $pr * 2, $hPupil) Else _GDIPlus_GraphicsFillEllipse($hGfx, $ex - $er, $ey - $er, $er * 2, $er * 2, $hWhite) _GDIPlus_GraphicsFillEllipse($hGfx, $ex + $g_fFX * $r * 0.14 - $pr, $ey + $g_fFY * $r * 0.14 - $pr, $pr * 2, $pr * 2, $hPupil) EndIf Next _GDIPlus_BrushDispose($hWhite) _GDIPlus_BrushDispose($hPupil) EndFunc ;==>_DrawGhost Func _DrawHud(ByRef $hGfx) Local $iSec = Int(TimerDiff($g_hTimer) / 1000) Local $sHud = "SCORE " & $g_iScore & " EATEN " & _EatenPct() & "% TIME " & StringFormat("%02d:%02d", Int($iSec / 60), Mod($iSec, 60)) Local $tLay = _GDIPlus_RectFCreate(14, 8, $HUD_W - 20, $HUD_H - 8) _GDIPlus_GraphicsFillRect($hGfx, 0, 0, $HUD_W, $HUD_H, $g_hHudBg) _GDIPlus_GraphicsDrawStringEx($hGfx, $sHud, $g_hHudFnt, $tLay, $g_hHudFmt, $g_hHudBrush) EndFunc ;==>_DrawHud ; ================================================================ ; Layer helpers ; ================================================================ Func _MarkDirty($x, $y, $w, $h) Local $x0 = _Max(0, Int($x)) Local $y0 = _Max(0, Int($y)) Local $x1 = _Min($g_iBufW, Int($x + $w) + 1) Local $y1 = _Min($g_iBufH, Int($y + $h) + 1) If $x1 <= $x0 Or $y1 <= $y0 Then Return If $iDirty >= $DIRTY_MAX Then $bDirtyAll = True Return EndIf $aDirty[$iDirty][0] = $x0 $aDirty[$iDirty][1] = $y0 $aDirty[$iDirty][2] = $x1 - $x0 $aDirty[$iDirty][3] = $y1 - $y0 $iDirty += 1 EndFunc ;==>_MarkDirty ; Builds the finished picture in the compose buffer and copies it to the window in one go Func _Compose(ByRef $hGfx) Local $n = $iDirty Local $rx, $ry, $rw, $rh If $bDirtyAll Then $aDirty[0][0] = 0 $aDirty[0][1] = 0 $aDirty[0][2] = $g_iBufW $aDirty[0][3] = $g_iBufH $n = 1 EndIf ; 1) background: screenshot layer + neon layer on top For $i = 0 To $n - 1 $rx = $aDirty[$i][0] $ry = $aDirty[$i][1] $rw = $aDirty[$i][2] $rh = $aDirty[$i][3] _GDIPlus_GraphicsDrawImageRectRect($g_hCompCtx, $g_hBuf, $rx, $ry, $rw, $rh, $rx, $ry, $rw, $rh) _GDIPlus_GraphicsDrawImageRectRect($g_hCompCtx, $g_hNeon, $rx, $ry, $rw, $rh, $rx, $ry, $rw, $rh) Next ; 2) sprites + HUD on top _DrawPacs($g_hCompCtx) _DrawGhost($g_hCompCtx) _DrawHud($g_hCompCtx) ; 3) finished areas to the window For $i = 0 To $n - 1 $rx = $aDirty[$i][0] $ry = $aDirty[$i][1] $rw = $aDirty[$i][2] $rh = $aDirty[$i][3] _GDIPlus_GraphicsDrawImageRectRect($hGfx, $g_hComp, $rx, $ry, $rw, $rh, $rx, $ry, $rw, $rh) Next $iDirty = 0 $bDirtyAll = False EndFunc ;==>_Compose ; Blurs a round spot of the screenshot layer once and tints it Func _BlurSpot($x, $y, $r, $hEffect, $hDim) Local $iR = Int($r) + 1 Local $sx = Int($x) - $iR - $BLUR_MARGIN Local $sy = Int($y) - $iR - $BLUR_MARGIN Local $sd = ($iR + $BLUR_MARGIN) * 2 If $hEffect <> 0 And $sx >= 0 And $sy >= 0 And $sx + $sd <= $g_iBufW And $sy + $sd <= $g_iBufH Then Local $hTmp = _GDIPlus_BitmapCreateFromScan0($sd, $sd) Local $hTmpCtx = _GDIPlus_ImageGetGraphicsContext($hTmp) _GDIPlus_GraphicsSetInterpolationMode($hTmpCtx, 5) _GDIPlus_GraphicsDrawImageRectRect($hTmpCtx, $g_hBuf, $sx, $sy, $sd, $sd, 0, 0, $sd, $sd) _GDIPlus_BitmapApplyEffect($hTmp, $hEffect) Local $hPath = _GDIPlus_PathCreate() _GDIPlus_PathAddEllipse($hPath, $x - $r, $y - $r, $r * 2, $r * 2) _GDIPlus_GraphicsSetClipPath($g_hCtx, $hPath) _GDIPlus_GraphicsDrawImageRectRect($g_hCtx, $hTmp, 0, 0, $sd, $sd, $sx, $sy, $sd, $sd) _GDIPlus_GraphicsResetClip($g_hCtx) _GDIPlus_PathDispose($hPath) _GDIPlus_GraphicsDispose($hTmpCtx) _GDIPlus_BitmapDispose($hTmp) EndIf If $hDim <> 0 Then _GDIPlus_GraphicsFillEllipse($g_hCtx, $x - $r, $y - $r, $r * 2, $r * 2, $hDim) EndFunc ;==>_BlurSpot ; Wipes a round spot of the neon layer completely Func _EraseNeon($x, $y, $r, $bMark = True) _GDIPlus_GraphicsSetCompositingMode($g_hNeonCtx, 1) _GDIPlus_GraphicsFillEllipse($g_hNeonCtx, $x - $r, $y - $r, $r * 2, $r * 2, $g_hClear) _GDIPlus_GraphicsSetCompositingMode($g_hNeonCtx, 0) If $bMark Then _MarkDirty($x - $r - 1, $y - $r - 1, $r * 2 + 2, $r * 2 + 2) EndFunc ;==>_EraseNeon ; ================================================================ ; Pac-Man System ; ================================================================ ; Spawns a pac at a random spot, far away from the ghost Func _SpawnPac($iSW, $iSH) Local $x, $y, $t, $gdx, $gdy For $t = 1 To 30 $x = Random(30, $iSW - 30) $y = Random(30, $iSH - 30) $gdx = $x - $g_fGX $gdy = $y - $g_fGY If Sqrt($gdx * $gdx + $gdy * $gdy) > 350 Then ExitLoop Next _SpawnPacAt($x, $y, Random($PAC_R_START_MIN, $PAC_R_START_MAX, 1), Random(0, 5, 1), $PAC_SPEED_FAST) EndFunc ;==>_SpawnPac Func _SpawnPacAt($x, $y, $r, $ci, $speed) ReDim $aPac[$iPac + 1][8] $aPac[$iPac][0] = $x $aPac[$iPac][1] = $y $aPac[$iPac][2] = $r $aPac[$iPac][3] = $ci Local $ang = Random(0, 359) $aPac[$iPac][4] = $speed * Cos(_DegToRad($ang)) $aPac[$iPac][5] = $speed * Sin(_DegToRad($ang)) $aPac[$iPac][6] = Random(5, 35, 1) $aPac[$iPac][7] = 1 $iPac += 1 _MarkDirty($x - $r - $PAC_SPRITE_PAD, $y - $r - $PAC_SPRITE_PAD, ($r + $PAC_SPRITE_PAD) * 2, ($r + $PAC_SPRITE_PAD) * 2) EndFunc ;==>_SpawnPacAt Func _AddBite($x, $y) $aBites[$iBitePtr][0] = $x $aBites[$iBitePtr][1] = $y $iBitePtr = Mod($iBitePtr + 1, $BITE_MAX) If $iBiteCount < $BITE_MAX Then $iBiteCount += 1 EndFunc ;==>_AddBite Func _AddFood($x, $y, $r, $ci) $aFood[$iFoodPtr][0] = $x $aFood[$iFoodPtr][1] = $y $aFood[$iFoodPtr][2] = $r $aFood[$iFoodPtr][3] = $ci $iFoodPtr = Mod($iFoodPtr + 1, $FOOD_MAX) EndFunc ;==>_AddFood ; A pac eats all reachable pellets of its own color: grows, gets slower Func _EatFood($i) Local $x = $aPac[$i][0], $y = $aPac[$i][1], $r = $aPac[$i][2], $ci = $aPac[$i][3] For $f = 0 To $FOOD_MAX - 1 If $aFood[$f][2] <= 0 Then ContinueLoop If $aFood[$f][3] <> $ci Then ContinueLoop Local $dx = $aFood[$f][0] - $x Local $dy = $aFood[$f][1] - $y If Sqrt($dx * $dx + $dy * $dy) > $r + $aFood[$f][2] Then ContinueLoop _EraseNeon($aFood[$f][0], $aFood[$f][1], $aFood[$f][2] + 3) $aFood[$f][2] = 0 $aPac[$i][2] += Random($PAC_GROW_MIN, $PAC_GROW_MAX, 1) Local $vx = $aPac[$i][4], $vy = $aPac[$i][5] Local $mag = Sqrt($vx * $vx + $vy * $vy) If $mag > $PAC_SPEED_MIN Then Local $newMag = $mag * $PAC_SLOWDOWN If $newMag < $PAC_SPEED_MIN Then $newMag = $PAC_SPEED_MIN Local $scale = $newMag / $mag $aPac[$i][4] *= $scale $aPac[$i][5] *= $scale EndIf Next EndFunc ;==>_EatFood ; Soft white flash when a pac is destroyed (drawn into the neon layer, can be eaten like everything else) Func _DrawAnnihilation(ByRef $hGfx, $x, $y, $r) _MarkDirty($x - $r - 16, $y - $r - 16, ($r + 16) * 2, ($r + 16) * 2) For $g = 3 To 0 Step -1 Local $hB = _GDIPlus_BrushCreateSolid(StringFormat("0x%02XFFFFFF", 0x14 + (3 - $g) * 0x18)) _GDIPlus_GraphicsFillEllipse($hGfx, $x - $r - $g * 4, $y - $r - $g * 4, ($r + $g * 4) * 2, ($r + $g * 4) * 2, $hB) _GDIPlus_BrushDispose($hB) Next EndFunc ;==>_DrawAnnihilation ; Game logic + trail. Draws NOTHING onto the window — the sprites come later in _Compose. Func _UpdatePac($iSW, $iSH) Local $bSplit[$iPac] For $i = 0 To $iPac - 1 Local $x = $aPac[$i][0] Local $y = $aPac[$i][1] Local $r = $aPac[$i][2] _AddBite($x, $y) ; Movement $aPac[$i][0] += $aPac[$i][4] $aPac[$i][1] += $aPac[$i][5] If $aPac[$i][0] < $r + 3 Or $aPac[$i][0] > $iSW - $r - 3 Then $aPac[$i][4] *= -1 If $aPac[$i][1] < $r + 3 Or $aPac[$i][1] > $iSH - $r - 3 Then $aPac[$i][5] *= -1 _EatFood($i) If $aPac[$i][2] >= $PAC_R_SPLIT Then $bSplit[$i] = True ; Animate mouth $aPac[$i][6] += $aPac[$i][7] * 5 If $aPac[$i][6] >= 40 Then $aPac[$i][7] = -1 If $aPac[$i][6] <= 2 Then $aPac[$i][7] = 1 ; Eat drawn stuff, blur + tint the screenshot _EraseNeon($aPac[$i][0], $aPac[$i][1], $aPac[$i][2] + $EAT_PAD, False) _BlurSpot($aPac[$i][0], $aPac[$i][1], $aPac[$i][2] + $BLUR_PAD, $g_hBlur, $g_aTint[$aPac[$i][3]]) Local $ro = $r + $PAC_SPRITE_PAD Local $rn = $aPac[$i][2] + $BLUR_PAD + 2 Local $ux0 = _Min($x - $ro, $aPac[$i][0] - $rn) Local $uy0 = _Min($y - $ro, $aPac[$i][1] - $rn) Local $ux1 = _Max($x + $ro, $aPac[$i][0] + $rn) Local $uy1 = _Max($y + $ro, $aPac[$i][1] + $rn) _MarkDirty($ux0, $uy0, $ux1 - $ux0, $uy1 - $uy0) Next ; Split: pacs that grew too big shrink back and spit out a 2nd small fast pac For $i = 0 To $iPac - 1 If Not $bSplit[$i] Then ContinueLoop Local $birthX = $aPac[$i][0] Local $birthY = $aPac[$i][1] Local $oldR = $aPac[$i][2] Local $ang = Random(0, 359) Local $aBirth = _DegToRad($ang) Local $childR = $PAC_R_MIN + Random(0, 4, 1) Local $separation = $oldR + $childR + 12 $aPac[$i][2] = $childR $aPac[$i][3] = Random(0, 5, 1) $aPac[$i][4] = $PAC_SPEED_FAST * Cos($aBirth) $aPac[$i][5] = $PAC_SPEED_FAST * Sin($aBirth) Local $childX = $birthX - $separation * Cos($aBirth) Local $childY = $birthY - $separation * Sin($aBirth) $childX = _Max($childR + 3, _Min($iSW - $childR - 3, $childX)) $childY = _Max($childR + 3, _Min($iSH - $childR - 3, $childY)) _SpawnPacAt($childX, $childY, $childR, Random(0, 5, 1), $PAC_SPEED_FAST) Next ; Collision pac <-> pac: both are wiped out Local $bDead[$iPac] For $i = 0 To $iPac - 2 If $bDead[$i] Then ContinueLoop For $j = $i + 1 To $iPac - 1 If $bDead[$j] Then ContinueLoop Local $dx = $aPac[$i][0] - $aPac[$j][0] Local $dy = $aPac[$i][1] - $aPac[$j][1] If Sqrt($dx * $dx + $dy * $dy) >= ($aPac[$i][2] + $aPac[$j][2]) * 0.8 Then ContinueLoop $bDead[$i] = True $bDead[$j] = True _DrawAnnihilation($g_hNeonCtx, ($aPac[$i][0] + $aPac[$j][0]) / 2, ($aPac[$i][1] + $aPac[$j][1]) / 2, ($aPac[$i][2] + $aPac[$j][2]) / 2) ExitLoop Next Next ; Collision pac <-> ghost: in front of the mouth = pac dies, side / back = ghost dies Local $fFrontCos = Cos(_DegToRad($FRONT_HALF_ANGLE)) For $i = 0 To $iPac - 1 If $bDead[$i] Then ContinueLoop Local $gdx = $g_fGX - $aPac[$i][0] Local $gdy = $g_fGY - $aPac[$i][1] Local $gdist = Sqrt($gdx * $gdx + $gdy * $gdy) If $gdist >= ($aPac[$i][2] + $GHOST_R) * 0.85 Then ContinueLoop Local $pspd = Sqrt($aPac[$i][4] * $aPac[$i][4] + $aPac[$i][5] * $aPac[$i][5]) Local $fCos = ($aPac[$i][4] * $gdx + $aPac[$i][5] * $gdy) / ($pspd * $gdist + 0.0001) If $fCos >= $fFrontCos Then If $FRONT_KILLS_PAC Then $bDead[$i] = True $g_iScore += 50 _DrawAnnihilation($g_hNeonCtx, $aPac[$i][0], $aPac[$i][1], $aPac[$i][2]) EndIf Else $g_bGhostDead = True EndIf Next ; Remove dead pacs from the array Local $bAnyDead = False For $i = 0 To $iPac - 1 If $bDead[$i] Then $bAnyDead = True Next If $bAnyDead Then Local $aNew[1][8], $iNew = 0 For $i = 0 To $iPac - 1 If $bDead[$i] Then ContinueLoop ReDim $aNew[$iNew + 1][8] For $c = 0 To 7 $aNew[$iNew][$c] = $aPac[$i][$c] Next $iNew += 1 Next $aPac = $aNew $iPac = $iNew EndIf ; Never let them die out completely If $iPac = 0 Then _SpawnPac($iSW, $iSH) EndFunc ;==>_UpdatePac ; Draws all pac sprites into the compose buffer Func _DrawPacs(ByRef $hGfx) For $i = 0 To $iPac - 1 Local $x = $aPac[$i][0] Local $y = $aPac[$i][1] Local $r = $aPac[$i][2] Local $mouth = $aPac[$i][6] Local $rot = _RadToDeg(ATan($aPac[$i][5] / ($aPac[$i][4] + 0.0001))) If $aPac[$i][4] < 0 Then $rot += 180 Local $startAngle = $rot + $mouth Local $sweepAngle = 360 - ($mouth * 2) Local $hBrush = _GDIPlus_BrushCreateSolid(_NeonIdx($aPac[$i][3], $PAC_ALPHA)) _GDIPlus_GraphicsFillPie($hGfx, $x - $r, $y - $r, $r * 2, $r * 2, $startAngle, $sweepAngle, $hBrush) _GDIPlus_BrushDispose($hBrush) Local $eyeAngle = $rot - 60 Local $eyeX = $x + ($r * 0.5) * Cos(_DegToRad($eyeAngle)) Local $eyeY = $y + ($r * 0.5) * Sin(_DegToRad($eyeAngle)) Local $hEye = _GDIPlus_BrushCreateSolid(0xFF000000) _GDIPlus_GraphicsFillEllipse($hGfx, $eyeX - 2, $eyeY - 2, 4, 4, $hEye) _GDIPlus_BrushDispose($hEye) Next EndFunc ;==>_DrawPacs Func _RadToDeg($r) Return $r * 180 / 3.14159265 EndFunc ;==>_RadToDeg Func _DegToRad($d) Return $d * 3.14159265 / 180 EndFunc ;==>_DegToRad ; ================================================================ ; Neon effects (all draw into the neon layer and mark their area as dirty) ; ================================================================ Func _DrawNeonParticle(ByRef $hGfx, $iSW, $iSH, $ox = -1, $oy = -1) Local $x, $y If $ox >= 0 Then $x = $ox $y = $oy Else $x = Random(10, $iSW - 10) $y = Random(10, $iSH - 10) EndIf Local $r = Random(1, 6, 1) Local $ci = Random(0, 5, 1) _AddFood($x, $y, $r + 6, $ci) _MarkDirty($x - $r - 12, $y - $r - 12, ($r + 12) * 2, ($r + 12) * 2) For $g = 3 To 0 Step -1 Local $alpha = 0x20 + $g * 0xff Local $hB = _GDIPlus_BrushCreateSolid(_NeonIdx($ci, $alpha)) _GDIPlus_GraphicsFillEllipse($hGfx, $x - $r - $g * 3, $y - $r - $g * 3, ($r + $g * 3) * 2, ($r + $g * 3) * 2, $hB) _GDIPlus_BrushDispose($hB) Next EndFunc ;==>_DrawNeonParticle Func _DrawNeonLine(ByRef $hGfx, $iSW, $iSH) Local $x1 = Random(0, $iSW), $y1 = Random(0, $iSH) Local $x2 = Random(0, $iSW), $y2 = Random(0, $iSH) Local $ci = Random(0, 5, 1) _AddFood(($x1 + $x2) / 2, ($y1 + $y2) / 2, 12, $ci) _MarkDirty(_Min($x1, $x2) - 6, _Min($y1, $y2) - 6, Abs($x1 - $x2) + 12, Abs($y1 - $y2) + 12) Local $hPenG = _GDIPlus_PenCreate(_NeonIdx($ci, 0x25), 4) _GDIPlus_GraphicsDrawLine($hGfx, $x1, $y1, $x2, $y2, $hPenG) _GDIPlus_PenDispose($hPenG) Local $hPen = _GDIPlus_PenCreate(_NeonIdx($ci, 0x50), 1) _GDIPlus_GraphicsDrawLine($hGfx, $x1, $y1, $x2, $y2, $hPen) _GDIPlus_PenDispose($hPen) EndFunc ;==>_DrawNeonLine ; Neon text: a tight glow made of shifted copies of the SAME text, then the sharp text on top Func _DrawNeonString(ByRef $hGfx, $sStr, $sFont, $sz, $x, $y, $ci, $iLayW, $iLayH) Local $hFam = _GDIPlus_FontFamilyCreate($sFont) Local $hFnt = _GDIPlus_FontCreate($hFam, $sz) Local $hFmt = _GDIPlus_StringFormatCreate() Local $tLay, $hBrush For $g = 2 To 1 Step -1 $hBrush = _GDIPlus_BrushCreateSolid(_NeonIdx($ci, Int($TEXT_GLOW / $g))) For $a = 0 To 7 $tLay = _GDIPlus_RectFCreate($x + $g * 2 * Cos(_DegToRad($a * 45)), $y + $g * 2 * Sin(_DegToRad($a * 45)), $iLayW, $iLayH) _GDIPlus_GraphicsDrawStringEx($hGfx, $sStr, $hFnt, $tLay, $hFmt, $hBrush) Next _GDIPlus_BrushDispose($hBrush) Next $hBrush = _GDIPlus_BrushCreateSolid(_NeonIdx($ci, 0xF0)) $tLay = _GDIPlus_RectFCreate($x, $y, $iLayW, $iLayH) _GDIPlus_GraphicsDrawStringEx($hGfx, $sStr, $hFnt, $tLay, $hFmt, $hBrush) _GDIPlus_BrushDispose($hBrush) _GDIPlus_FontDispose($hFnt) _GDIPlus_FontFamilyDispose($hFam) _GDIPlus_StringFormatDispose($hFmt) EndFunc ;==>_DrawNeonString Func _DrawNeonText(ByRef $hGfx, $iSW, $iSH) Local $x = Random(0, $iSW - 400), $y = Random(0, $iSH - 80) Local $sz = Random(18, 48, 1) Local $ci = Random(0, 5, 1) _AddFood($x + 60, $y + $sz * 0.5, $sz * 0.7, $ci) _MarkDirty($x - 8, $y - 8, StringLen($sText) * $sz * 0.9 + 24, $sz * 1.6 + 16) _DrawNeonString($hGfx, $sText, "Segoe UI", $sz, $x, $y, $ci, 1200, 300) EndFunc ;==>_DrawNeonText Func _DrawNeonClock(ByRef $hGfx, $iSW, $iSH) Local $sTime = @HOUR & ":" & StringFormat("%02d", @MIN) & ":" & StringFormat("%02d", @SEC) Local $x = Random(0, $iSW - 500), $y = Random(0, $iSH - 120) Local $sz = Random(40, 80, 1) Local $ci = Random(0, 5, 1) _AddFood($x + 70, $y + $sz * 0.5, $sz * 0.55, $ci) _MarkDirty($x - 8, $y - 8, $sz * 6 + 24, $sz * 1.6 + 16) _DrawNeonString($hGfx, $sTime, "Consolas", $sz, $x, $y, $ci, 700, 200) EndFunc ;==>_DrawNeonClock Func _DrawNeonStar(ByRef $hGfx, $iSW, $iSH, $ox = -1, $oy = -1) Local $cx, $cy If $ox >= 0 Then $cx = $ox $cy = $oy If $cx < 50 Then $cx = 50 If $cx > $iSW - 50 Then $cx = $iSW - 50 If $cy < 50 Then $cy = 50 If $cy > $iSH - 50 Then $cy = $iSH - 50 Else $cx = Random(50, $iSW - 50) $cy = Random(50, $iSH - 50) EndIf Local $r1 = Random(15, 60, 1), $r2 = Int($r1 * 0.4) Local $ci = Random(0, 5, 1) _AddFood($cx, $cy, $r1 * 0.7, $ci) _MarkDirty($cx - $r1 - 8, $cy - $r1 - 8, ($r1 + 8) * 2, ($r1 + 8) * 2) Local $pts[11][2] For $i = 0 To 9 Local $ang = ($i * 36 - 90) * 3.14159265 / 180 If Mod($i, 2) = 0 Then $pts[$i][0] = $cx + $r1 * Cos($ang) $pts[$i][1] = $cy + $r1 * Sin($ang) Else $pts[$i][0] = $cx + $r2 * Cos($ang) $pts[$i][1] = $cy + $r2 * Sin($ang) EndIf Next Local $hPenG = _GDIPlus_PenCreate(_NeonIdx($ci, 0x45), 9) Local $hPen = _GDIPlus_PenCreate(_NeonIdx($ci, 0x85), 2) For $i = 0 To 9 Local $jn = $i + 1 If $i = 9 Then $jn = 0 _GDIPlus_GraphicsDrawLine($hGfx, $pts[$i][0], $pts[$i][1], $pts[$jn][0], $pts[$jn][1], $hPenG) _GDIPlus_GraphicsDrawLine($hGfx, $pts[$i][0], $pts[$i][1], $pts[$jn][0], $pts[$jn][1], $hPen) Next _GDIPlus_PenDispose($hPenG) _GDIPlus_PenDispose($hPen) EndFunc ;==>_DrawNeonStar Func _DrawNeonTriangle(ByRef $hGfx, $iSW, $iSH, $ox = -1, $oy = -1) Local $cx, $cy If $ox >= 0 Then $cx = $ox $cy = $oy If $cx < 40 Then $cx = 40 If $cx > $iSW - 40 Then $cx = $iSW - 40 If $cy < 40 Then $cy = 40 If $cy > $iSH - 40 Then $cy = $iSH - 40 Else $cx = Random(40, $iSW - 40) $cy = Random(40, $iSH - 40) EndIf Local $r = Random(20, 70, 1), $ci = Random(0, 5, 1) _AddFood($cx, $cy, $r * 0.7, $ci) _MarkDirty($cx - $r - 8, $cy - $r - 8, ($r + 8) * 2, ($r + 8) * 2) Local $x1 = $cx + $r * Cos(-1.5708), $y1 = $cy + $r * Sin(-1.5708) Local $x2 = $cx + $r * Cos(-1.5708 + 2.0944), $y2 = $cy + $r * Sin(-1.5708 + 2.0944) Local $x3 = $cx + $r * Cos(-1.5708 + 4.1888), $y3 = $cy + $r * Sin(-1.5708 + 4.1888) Local $hPenG = _GDIPlus_PenCreate(_NeonIdx($ci, 0x45), 9) _GDIPlus_GraphicsDrawLine($hGfx, $x1, $y1, $x2, $y2, $hPenG) _GDIPlus_GraphicsDrawLine($hGfx, $x2, $y2, $x3, $y3, $hPenG) _GDIPlus_GraphicsDrawLine($hGfx, $x3, $y3, $x1, $y1, $hPenG) _GDIPlus_PenDispose($hPenG) Local $hPen = _GDIPlus_PenCreate(_NeonIdx($ci, 0x85), 2) _GDIPlus_GraphicsDrawLine($hGfx, $x1, $y1, $x2, $y2, $hPen) _GDIPlus_GraphicsDrawLine($hGfx, $x2, $y2, $x3, $y3, $hPen) _GDIPlus_GraphicsDrawLine($hGfx, $x3, $y3, $x1, $y1, $hPen) _GDIPlus_PenDispose($hPen) EndFunc ;==>_DrawNeonTriangle Func _DrawBgBlob(ByRef $hGfx, $iSW, $iSH, $ox = -1, $oy = -1) Local $rw = Random(10, 100, 1), $rh = Random(10, 100, 1) Local $x, $y If $ox >= 0 Then $x = $ox - $rw / 2 $y = $oy - $rh / 2 Else $x = Random(0, $iSW) $y = Random(0, $iSH) EndIf Local $ci = Random(0, 5, 1) Local $rMax = $rw If $rh > $rMax Then $rMax = $rh _AddFood($x + $rw / 2, $y + $rh / 2, $rMax / 2, $ci) _MarkDirty($x - 22, $y - 22, $rw + 44, $rh + 44) Local $hBg = _GDIPlus_BrushCreateSolid(_NeonIdx($ci, 0x35)) _GDIPlus_GraphicsFillEllipse($hGfx, $x - 20, $y - 20, $rw + 40, $rh + 40, $hBg) _GDIPlus_BrushDispose($hBg) Local $hB = _GDIPlus_BrushCreateSolid(_NeonIdx($ci, 0x45)) _GDIPlus_GraphicsFillEllipse($hGfx, $x, $y, $rw, $rh, $hB) _GDIPlus_BrushDispose($hB) EndFunc ;==>_DrawBgBlob Func _NeonIdx($iIdx, $iAlpha = 0xFF) Local $aNeon[6] = [0xFFFF00CC, 0xFF00FFFF, 0xFF39FF14, 0xFFFF6600, 0xFF7B2FFF, 0xFF0080FF] Local $sBase = Hex($aNeon[$iIdx]) Return "0x" & StringFormat("%02X", $iAlpha) & StringRight($sBase, 6) EndFunc ;==>_NeonIdx