Added samples.
authorblitz-research <blitzmunter@gamil.com>
Wed, 22 Jan 2014 22:33:28 +0000 (11:33 +1300)
committerblitz-research <blitzmunter@gamil.com>
Wed, 22 Jan 2014 22:33:28 +0000 (11:33 +1300)
235 files changed:
samples/aaronkoolen/AStar/Callback.bmx [new file with mode: 0644]
samples/aaronkoolen/AStar/astar_demo.bmx [new file with mode: 0644]
samples/aaronkoolen/AStar/astar_graph_walker.bmx [new file with mode: 0644]
samples/aaronkoolen/AStar/astar_node.bmx [new file with mode: 0644]
samples/aaronkoolen/AStar/map0 [new file with mode: 0644]
samples/aaronkoolen/AStar/map1 [new file with mode: 0644]
samples/aaronkoolen/AStar/map2 [new file with mode: 0644]
samples/aaronkoolen/AStar/map3 [new file with mode: 0644]
samples/aaronkoolen/AStar/map4 [new file with mode: 0644]
samples/aaronkoolen/AStar/map5 [new file with mode: 0644]
samples/aaronkoolen/AStar/map6 [new file with mode: 0644]
samples/aaronkoolen/AStar/map7 [new file with mode: 0644]
samples/aaronkoolen/AStar/mountain.png [new file with mode: 0644]
samples/aaronkoolen/AStar/nums.png [new file with mode: 0644]
samples/aaronkoolen/AStar/priority_queue.bmx [new file with mode: 0644]
samples/aaronkoolen/AStar/road.png [new file with mode: 0644]
samples/aaronkoolen/AStar/tree.png [new file with mode: 0644]
samples/aaronkoolen/AStar/water.png [new file with mode: 0644]
samples/birdie/games/tempest/tempest.bmx [new file with mode: 0644]
samples/birdie/games/tiledrop/media/back.png [new file with mode: 0644]
samples/birdie/games/tiledrop/media/blocks.png [new file with mode: 0644]
samples/birdie/games/tiledrop/media/part.png [new file with mode: 0644]
samples/birdie/games/tiledrop/media/pointer.PNG [new file with mode: 0644]
samples/birdie/games/tiledrop/media/shine.png [new file with mode: 0644]
samples/birdie/games/tiledrop/tiledrop.bmx [new file with mode: 0644]
samples/birdie/games/zombieblast/game.bmx [new file with mode: 0644]
samples/birdie/games/zombieblast/media/HitSpace.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/Title.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/cloud.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/mud.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/sand.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/scan.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/ship1.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/shot.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/shot2.PNG [new file with mode: 0644]
samples/birdie/games/zombieblast/media/smoke.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_0.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_1.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_2.PNG [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_3.PNG [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_4.PNG [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_5.PNG [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_6.png [new file with mode: 0644]
samples/birdie/games/zombieblast/media/zombie_7.PNG [new file with mode: 0644]
samples/birdie/misc/filmclip/main.bmx [new file with mode: 0644]
samples/birdie/misc/filmclip/media/B-Max.png [new file with mode: 0644]
samples/birdie/misc/filmclip/media/Thumbs.db [new file with mode: 0644]
samples/birdie/misc/filmclip/media/flmstp.png [new file with mode: 0644]
samples/birdie/misc/glblur/glblurr.bmx [new file with mode: 0644]
samples/birdie/misc/lightImage/main.bmx [new file with mode: 0644]
samples/birdie/misc/lightImage/media/B-Max.png [new file with mode: 0644]
samples/birdie/misc/lightImage/media/fl.png [new file with mode: 0644]
samples/birdie/misc/lightImage/media/light.png [new file with mode: 0644]
samples/breakout/breakout.bmx [new file with mode: 0644]
samples/breakout/media/B-Max.png [new file with mode: 0644]
samples/breakout/media/back1.png [new file with mode: 0644]
samples/breakout/media/back2.png [new file with mode: 0644]
samples/breakout/media/ball.png [new file with mode: 0644]
samples/breakout/media/paddle.png [new file with mode: 0644]
samples/breakout/media/pipes.png [new file with mode: 0644]
samples/breakout/media/tiles.png [new file with mode: 0644]
samples/digesteroids/Digesteroids.ppf [new file with mode: 0644]
samples/digesteroids/MathUtil.bmx [new file with mode: 0644]
samples/digesteroids/digesteroids.bmx [new file with mode: 0644]
samples/digesteroids/dynamicgame.bmx [new file with mode: 0644]
samples/digesteroids/graphics/bullet1.png [new file with mode: 0644]
samples/digesteroids/graphics/bullet2.png [new file with mode: 0644]
samples/digesteroids/graphics/digestive.png [new file with mode: 0644]
samples/digesteroids/graphics/lower.png [new file with mode: 0644]
samples/digesteroids/graphics/options.png [new file with mode: 0644]
samples/digesteroids/graphics/piece1.png [new file with mode: 0644]
samples/digesteroids/graphics/piece2.png [new file with mode: 0644]
samples/digesteroids/graphics/piece3.png [new file with mode: 0644]
samples/digesteroids/graphics/pop.png [new file with mode: 0644]
samples/digesteroids/graphics/ship.png [new file with mode: 0644]
samples/digesteroids/graphics/sparkle.png [new file with mode: 0644]
samples/digesteroids/graphics/stars.png [new file with mode: 0644]
samples/digesteroids/graphics/title.png [new file with mode: 0644]
samples/digesteroids/minitimer.bmx [new file with mode: 0644]
samples/digesteroids/simplephysics.bmx [new file with mode: 0644]
samples/digesteroids/sounds/crash.wav [new file with mode: 0644]
samples/digesteroids/sounds/ending.ogg [new file with mode: 0644]
samples/digesteroids/sounds/fire.wav [new file with mode: 0644]
samples/digesteroids/sounds/impactlarge.wav [new file with mode: 0644]
samples/digesteroids/sounds/menu.ogg [new file with mode: 0644]
samples/digesteroids/sounds/teleport.wav [new file with mode: 0644]
samples/digesteroids/sounds/thrust.wav [new file with mode: 0644]
samples/firepaint/bullet.png [new file with mode: 0644]
samples/firepaint/color.bmx [new file with mode: 0644]
samples/firepaint/firepaint.bmx [new file with mode: 0644]
samples/firepaint/player.png [new file with mode: 0644]
samples/firepaint/shoot.wav [new file with mode: 0644]
samples/firepaint/stars.png [new file with mode: 0644]
samples/flameduck/circlemania/anim0.png [new file with mode: 0644]
samples/flameduck/circlemania/anim1.png [new file with mode: 0644]
samples/flameduck/circlemania/anim10.png [new file with mode: 0644]
samples/flameduck/circlemania/anim11.png [new file with mode: 0644]
samples/flameduck/circlemania/anim12.png [new file with mode: 0644]
samples/flameduck/circlemania/anim13.png [new file with mode: 0644]
samples/flameduck/circlemania/anim14.png [new file with mode: 0644]
samples/flameduck/circlemania/anim15.png [new file with mode: 0644]
samples/flameduck/circlemania/anim2.png [new file with mode: 0644]
samples/flameduck/circlemania/anim3.png [new file with mode: 0644]
samples/flameduck/circlemania/anim4.png [new file with mode: 0644]
samples/flameduck/circlemania/anim5.png [new file with mode: 0644]
samples/flameduck/circlemania/anim6.png [new file with mode: 0644]
samples/flameduck/circlemania/anim7.png [new file with mode: 0644]
samples/flameduck/circlemania/anim8.png [new file with mode: 0644]
samples/flameduck/circlemania/anim9.png [new file with mode: 0644]
samples/flameduck/circlemania/circlebob.png [new file with mode: 0644]
samples/flameduck/circlemania/cmania.bmx [new file with mode: 0644]
samples/flameduck/circlemania/cmanialogo.png [new file with mode: 0644]
samples/flameduck/circlemania/rasta.png [new file with mode: 0644]
samples/flameduck/oldskool2/binarytherapy.png [new file with mode: 0644]
samples/flameduck/oldskool2/bouncy.ogg [new file with mode: 0644]
samples/flameduck/oldskool2/circlefont.png [new file with mode: 0644]
samples/flameduck/oldskool2/oldskool.png [new file with mode: 0644]
samples/flameduck/oldskool2/oldskool2.bmx [new file with mode: 0644]
samples/flameduck/oldskool2/readme.txt [new file with mode: 0644]
samples/hitoro/arraysort.bmx [new file with mode: 0644]
samples/hitoro/bench.bmx [new file with mode: 0644]
samples/hitoro/debugprintq.bmx [new file with mode: 0644]
samples/hitoro/extendednewtest.bmx [new file with mode: 0644]
samples/hitoro/fireworks.bmx [new file with mode: 0644]
samples/hitoro/gfx/bg.png [new file with mode: 0644]
samples/hitoro/gfx/block.png [new file with mode: 0644]
samples/hitoro/gfx/boing.png [new file with mode: 0644]
samples/hitoro/gfx/flame.png [new file with mode: 0644]
samples/hitoro/gfx/grass.png [new file with mode: 0644]
samples/hitoro/gfx/land.png [new file with mode: 0644]
samples/hitoro/gfx/rock.png [new file with mode: 0644]
samples/hitoro/gfx/shot.png [new file with mode: 0644]
samples/hitoro/gfx/sky.png [new file with mode: 0644]
samples/hitoro/gfx/water.png [new file with mode: 0644]
samples/hitoro/info.txt [new file with mode: 0644]
samples/hitoro/listextendedtypes.bmx [new file with mode: 0644]
samples/hitoro/newmethod.bmx [new file with mode: 0644]
samples/hitoro/passvarptr.bmx [new file with mode: 0644]
samples/hitoro/rockout.bmx [new file with mode: 0644]
samples/hitoro/rockout_gui.bmx [new file with mode: 0644]
samples/hitoro/shadowimage.bmx [new file with mode: 0644]
samples/hitoro/singlelist.bmx [new file with mode: 0644]
samples/hitoro/sounds/beep.ogg [new file with mode: 0644]
samples/hitoro/sounds/fall.ogg [new file with mode: 0644]
samples/hitoro/sounds/gameover.ogg [new file with mode: 0644]
samples/hitoro/sounds/hit.ogg [new file with mode: 0644]
samples/hitoro/sounds/shot.ogg [new file with mode: 0644]
samples/hitoro/throwrockets.bmx [new file with mode: 0644]
samples/hitoro/tilerocket.bmx [new file with mode: 0644]
samples/hitoro/viewport.bmx [new file with mode: 0644]
samples/mak/bullet1.png [new file with mode: 0644]
samples/mak/gnetchat.bmx [new file with mode: 0644]
samples/mak/gnetdemo.bmx [new file with mode: 0644]
samples/mak/requestgraphicsmode.bmx [new file with mode: 0644]
samples/mak/ship.png [new file with mode: 0644]
samples/mak/sparkle.png [new file with mode: 0644]
samples/maxgui/bigsearch.bmx [new file with mode: 0644]
samples/maxgui/glcube.bmx [new file with mode: 0644]
samples/maxgui/guilauncher/PNGHeader.bmx [new file with mode: 0644]
samples/maxgui/guilauncher/TLauncher.bmx [new file with mode: 0644]
samples/maxgui/guilauncher/bmxlogo.png [new file with mode: 0644]
samples/maxgui/guilauncher/test.bmx [new file with mode: 0644]
samples/maxgui/imagedrop.bmx [new file with mode: 0644]
samples/maxgui/sliderthing/sliderthing.bmx [new file with mode: 0644]
samples/maxgui/sliderthing/sourcepic.jpg [new file with mode: 0644]
samples/shooter/_shooter_main.bmx [new file with mode: 0644]
samples/shooter/background.bmx [new file with mode: 0644]
samples/shooter/enemies.bmx [new file with mode: 0644]
samples/shooter/gfont.bmx [new file with mode: 0644]
samples/shooter/gfx/Hill_1.png [new file with mode: 0644]
samples/shooter/gfx/SMOKE.png [new file with mode: 0644]
samples/shooter/gfx/TitlePage.png [new file with mode: 0644]
samples/shooter/gfx/abduction.png [new file with mode: 0644]
samples/shooter/gfx/alien_shot.png [new file with mode: 0644]
samples/shooter/gfx/bigcloud.png [new file with mode: 0644]
samples/shooter/gfx/bonusdecals.png [new file with mode: 0644]
samples/shooter/gfx/expl.png [new file with mode: 0644]
samples/shooter/gfx/multdecals.png [new file with mode: 0644]
samples/shooter/gfx/player.png [new file with mode: 0644]
samples/shooter/gfx/player_shot.png [new file with mode: 0644]
samples/shooter/gfx/playera.png [new file with mode: 0644]
samples/shooter/gfx/sky32.png [new file with mode: 0644]
samples/shooter/gfx/spark1.png [new file with mode: 0644]
samples/shooter/gfx/spark2.png [new file with mode: 0644]
samples/shooter/gfx/spark3.png [new file with mode: 0644]
samples/shooter/gfx/spikeyball.png [new file with mode: 0644]
samples/shooter/gfx/tex_1.png [new file with mode: 0644]
samples/shooter/gfx/tex_2.png [new file with mode: 0644]
samples/shooter/globals.bmx [new file with mode: 0644]
samples/shooter/init.bmx [new file with mode: 0644]
samples/shooter/particles.bmx [new file with mode: 0644]
samples/shooter/player.bmx [new file with mode: 0644]
samples/shooter/playershots.bmx [new file with mode: 0644]
samples/shooter/sound.bmx [new file with mode: 0644]
samples/shooter/sound/EXPLOSION1.WAV [new file with mode: 0644]
samples/shooter/sound/bombfall.wav [new file with mode: 0644]
samples/shooter/sound/explode.wav [new file with mode: 0644]
samples/shooter/sound/shot-1.wav [new file with mode: 0644]
samples/shooter/titles.bmx [new file with mode: 0644]
samples/simonh/fireworks/fireworks.bmx [new file with mode: 0644]
samples/simonh/fireworks/spark.png [new file with mode: 0644]
samples/simonh/snow/flake.png [new file with mode: 0644]
samples/simonh/snow/snowfall.bmx [new file with mode: 0644]
samples/spintext/spintext.bmx [new file with mode: 0644]
samples/starfieldpong/starfieldpong.bmx [new file with mode: 0644]
samples/teapot/teapot.bmx [new file with mode: 0644]
samples/teapot/teapot_test.bmx [new file with mode: 0644]
samples/tempest/Readme.txt [new file with mode: 0644]
samples/tempest/boarddata.bmx [new file with mode: 0644]
samples/tempest/boardgen.bmx [new file with mode: 0644]
samples/tempest/sfx.bmx [new file with mode: 0644]
samples/tempest/sfx/bonus.wav [new file with mode: 0644]
samples/tempest/sfx/bullet.wav [new file with mode: 0644]
samples/tempest/sfx/flippershot.wav [new file with mode: 0644]
samples/tempest/sfx/killedbybullet.wav [new file with mode: 0644]
samples/tempest/sfx/killedbyflipper.wav [new file with mode: 0644]
samples/tempest/sfx/pulse.wav [new file with mode: 0644]
samples/tempest/sfx/shot.wav [new file with mode: 0644]
samples/tempest/sfx/spikeshot.wav [new file with mode: 0644]
samples/tempest/sfx/tick.wav [new file with mode: 0644]
samples/tempest/sfx/zap.wav [new file with mode: 0644]
samples/tempest/sfx/zoomin.wav [new file with mode: 0644]
samples/tempest/sfx/zoomout.wav [new file with mode: 0644]
samples/tempest/tempest.bmx [new file with mode: 0644]
samples/tempest/transformfunctions.bmx [new file with mode: 0644]
samples/tempest/vectorfont.bmx [new file with mode: 0644]
samples/threads/background_loading.bmx [new file with mode: 0644]
samples/threads/bluboing.png [new file with mode: 0644]
samples/threads/bluegem.png [new file with mode: 0644]
samples/threads/boing.png [new file with mode: 0644]
samples/threads/dead.png [new file with mode: 0644]
samples/threads/greengem.png [new file with mode: 0644]
samples/threads/redgem.png [new file with mode: 0644]
samples/threads/threaded image downloader.bmx [new file with mode: 0644]
samples/threads/threads.bmx [new file with mode: 0644]

diff --git a/samples/aaronkoolen/AStar/Callback.bmx b/samples/aaronkoolen/AStar/Callback.bmx
new file mode 100644 (file)
index 0000000..a00aab6
--- /dev/null
@@ -0,0 +1,6 @@
+' Simple object to handle callbacks
+' Is there a way in BlitzMax to pass pointers to functions??
+
+Type Callback
+       Method callback() Abstract
+End Type
diff --git a/samples/aaronkoolen/AStar/astar_demo.bmx b/samples/aaronkoolen/AStar/astar_demo.bmx
new file mode 100644 (file)
index 0000000..d83034e
--- /dev/null
@@ -0,0 +1,805 @@
+Strict
+'
+' Simple demo program of an astar path finding algorithm
+' The GUI is pretty crappy
+' There are quite a few comments in the areas of importance. Sometimes this makes
+' the code a little harder to read, but this was done for instructional purposes foremost
+
+Import "astar_graph_walker.bmx"
+Import "Callback.bmx"
+
+Global nums:TImage
+
+Local demo:AStarDemo = New AStarDemo
+demo.run()
+End
+
+
+Private
+' Small class that encapsulates a position on the map
+Type MapPos
+       Method isAtPos(otherX, otherY)
+               Return otherX = x And otherY = y
+       End Method
+       Field x,y
+End Type
+
+
+' Class that defines the terrain types that the demo uses
+Type Terrain
+       Method set(weight:Int, filename:String)
+               _weight = weight
+               _image = LoadImage(filename)
+       End Method
+       Field _colour_r,_color_g,_color_b
+       Field _weight:Int
+       Field _image:TImage
+End Type
+
+' Main application class
+Type AStarDemo
+
+' Map stuff
+       Const blockAreaWidth:Int = 600
+       Const blockAreaHeight:Int = 600
+       Const mapHeight:Int = 20
+       Const mapWidth:Int = 20
+       Const blockWidth:Int = 600 / 20 
+       Const blockHeight:Int = 600 / 20
+' Block map
+       Field map:Int[mapWidth, mapHeight]
+
+' Node version of map
+       Field nodeMap:AStarNode[mapWidth, mapHeight]
+       Field startPos:MapPos
+       Field endPos:MapPos
+       Field currentMap = 0
+
+' Terrain information
+       Const numTerrainTypes = 4
+       Field terrainFilenames:String[] = [ "road.png", "mountain.png", "water.png", "tree.png" ]
+       Field terrainWeights:Int[] = [ 1, -1, 4, 2 ]
+       Field terrains:Terrain[numTerrainTypes]
+       Field currentTerrainIndex:Int = 1
+       Field terrainLegendBlockX:Int
+       Field terrainLegendBlockY:Int
+
+' Path finding stuff
+' Distance
+       Const numDistanceFunctions = 4  
+' Is there a DATA like statement in Blitz?
+       Field distanceNames:String[] = [        "(D) Euclidean Sqr(dx*dx+dy*dy)", ..
+                                                                               "(D) Pseudo Euclidean dx*dx+dy*dy", ..
+                                                                               "(D) Manhatten dx+dy", ..
+                                                                               "(D) Diagonal Shortcut dx>dy ? 1.4*dy + (dx-dy) : 1.4*dx + (dy-dx)" ]
+
+       Field distanceFunction = AStarGraphWalker.distanceEuclidean     
+
+' Whether we're allowed to chage the costs with the "Q" and "W" keys
+       Field costChangeAllowed:Int     = 0
+' Is the pathfinder allowed to cruise diagonals?
+       Field allowDiagonalPaths:Int    = 0
+       Field diagonalsAreLonger:Int = 1
+' Time in millisecs that the last path fund took
+       Field lastRunTime:Int = 0
+       Field path:TList = Null                 ' The last path that was found
+
+       Field heuristicMultiplier:Float = 1.0
+       Field showProgress:Int = False  ' Do we want to show the progress
+
+' UI stuff
+       Field mapButtonBlockX:Int = 0
+       Field mapButtonBlockY:Int = mapHeight + 1
+
+       Field showCosts:Int = 1
+       Field flagRedraw:Int = 1
+       Field textScale:Float = 800.0/1024.0
+       Field message:String = ""                               ' Any stat messages that are to be displayed
+
+' Input stuff
+' Used to detect mouse movements
+       Field oldBlockX:Int = -1
+       Field oldBlockY:Int = -1
+' Help
+       Field help:String[] = [ ..
+               "A - Allow/Disallow diagonals", ..
+               "Q - Divide terrain costs by 5", ..
+               "W - Multiply terrain costs by 5", ..
+               "D - Cycle distance functions", ..
+               "V - Toggle diagonal multiplier", ..
+               "S - Point mouse and press to set start node", ..
+               "E - Point mouse and press to set end node", ..
+               "P - Run AStar, showing progress", ..
+               "H - Click and drag on 'H' to change heuristic mult.", ..
+               "Click white square to load map of that number", ..
+               "Click red 'S' to save map as map # 'Current Map'", ..
+               "ESC - Quit program", ..
+               "", ..
+               "In progress mode:", ..
+               "Top Number    = Cost to get to that node", ..
+               "Mid Number    = Heurisitc from node to end", ..
+               "Bottom Number = Cost from start to end", ..
+               "                Through that node", ..
+               "Press 'P' to pause", ..
+               "ESC to quit progress mode", ..
+               "", ..
+               "Handy Hints", ..
+               "If DistanceFunc * heuristic Multiplier = ", ..
+               "True distance to goal, fastest path generated", ..
+               "", ..
+               "Heuristic Mult = 0 then optimal path for", ..
+               "chosen Distance Func "..
+       ]
+
+' This is the main entry point for the class
+       Method run()
+       
+' Setup the graphics stuff
+               Graphics 1024,768,32
+               
+               nums = LoadAnimImage("nums.png",5,8,0,12)
+               Assert nums<> Null,"Can't load number graphic nums.png"
+               
+' Initialise dimensions of maps and other useful data
+               initialise()
+               
+' Load the first map by default
+               loadMap(currentMap)
+               
+' Redraw 
+               redraw()
+               
+               While Not KeyDown(27)
+
+                       Local m:Int = MouseDown(1)
+
+                       Local blockX = MouseX() / blockWidth
+                       Local blockY = MouseY() / blockHeight
+
+                       If m
+                               handleMouseDown(blockX, blockY)
+                       EndIf
+
+                       processStartPlaced(blockX, blockY)
+                       processEndPlaced(blockX, blockY)
+                       processAllowDiagonalPaths()
+                       processShowProgress()
+                       processCycleDistanceFunction()
+                       processDiagonalsAreLonger()
+                       processDecreaseTerrainCost()
+                       processIncreaseTerrainCost()
+
+                       If flagRedraw 
+                               oldBlockX = -1                          ' Mark for refresh of mouse movement
+                               lastRunTime = runAStar()
+                               redraw()
+                               flagRedraw = False
+                       EndIf
+
+               Wend
+               EndGraphics
+       End Method
+
+'-------------------------------------
+' Input handling functions
+'-------------------------------------
+
+       Method processIncreaseTerrainCost()
+               If KeyHit(KEY_W)
+                       Local t
+                       For t = 0 To numTerrainTypes - 1
+                               terrains[t]._weight = terrains[t]._weight * 5
+                       Next
+                       setRedraw(True)
+                       costChangeAllowed = costChangeAllowed + 1
+               EndIf
+       End Method
+
+       Method processDecreaseTerrainCost()
+               If KeyHit(KEY_Q) And costChangeAllowed > 0
+                       Local t
+                       For t = 0 To numTerrainTypes - 1
+                               terrains[t]._weight = terrains[t]._weight / 5
+                       Next
+                       setRedraw(True)
+                       costChangeAllowed = costChangeAllowed - 1
+               EndIf
+       End Method
+
+       Method processDiagonalsAreLonger()
+               If KeyHit(KEY_V)
+                       diagonalsAreLonger = 1 - diagonalsAreLonger
+                       setRedraw(True)
+               EndIf
+       End Method
+
+' Cycling the distance function to use?
+       Method processCycleDistanceFunction()
+               If KeyHit(KEY_D)
+                       distanceFunction = (distanceFunction + 1) Mod numDistanceFunctions
+                       setRedraw(True);
+               EndIf
+       End Method
+
+' Clear the last calculated path?
+       Method processClearPath()
+               If KeyHit(KEY_P)
+                       path = Null
+                       setRedraw(True)
+               EndIf
+       End Method
+
+       Method processShowProgress()
+               If KeyHit(KEY_P)
+                       showProgress = True
+                       runAStar()
+                       showProgress = False
+               EndIf
+       End Method
+
+' Allow diagonal toggled?
+       Method processAllowDiagonalPaths()
+               If KeyHit(KEY_A)
+                       allowDiagonalPaths = 1 - allowDiagonalPaths
+                       setRedraw(True)
+               EndIf
+       End Method
+
+' Check if they want to move the start node
+       Method processStartPlaced(blockX:Int, blockY:Int)
+                       If KeyHit(KEY_S)
+                               If blockInMapArea(blockX, blockY)
+'                                      setMapBlock(blockX, blockY,0)
+                                       startPos.x = blockX
+                                       startPos.y = blockY
+                                       setRedraw(True)
+                               EndIf                                   
+                       EndIf
+       End Method
+
+' Check if they want to move the end node
+       Method processEndPlaced(blockX:Int, blockY:Int)
+                       If KeyHit(KEY_E)
+                               If blockInMapArea(blockX, blockY)
+'                                      setMapBlock(blockX, blockY,0)
+                                       endPos.x = blockX
+                                       endPos.y = blockY
+                                       setRedraw(True)
+                               EndIf                                   
+                       EndIf
+       End Method
+
+
+
+' Call this to tell the main engine to redraw
+       Method setRedraw(doRedraw:Int)
+               flagRedraw = doRedraw
+       End Method
+
+' Use this to change a map block while editing, so that redraws are sped up
+       Method setMapBlock(blockX, blockY, block)
+               map[blockX, blockY] = block
+       End Method
+
+' Redraws the map and last found path. You can tell it to draw more than once for double buffer purposes
+       Method redraw(times:Int = 1, flipIt:Int = 1)
+               While times > 0
+                       drawMap()
+                       drawPath()
+                       drawTerrains()
+                       drawInfo()
+                       drawMapButtons()
+                       If flipIt Then Flip
+                       times :- 1
+               Wend
+       End Method
+
+       Method saveMap:String(mapNumber:Int)
+               Local stream:TStream = WriteStream("littleendian::map"+mapNumber)               
+               If stream = Null
+                       Return "Error saving map"
+               EndIf
+               Local x,y;
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1
+                               WriteInt(stream,map[x,y])
+                       Next
+               Next
+               WriteInt stream, startPos.x
+               WriteInt stream, startPos.y
+               WriteInt stream, endPos.x
+               WriteInt stream, endPos.y
+               CloseStream stream
+               Return "Done"
+       End Method
+
+       Method loadMap(mapNumber:Int)
+               Local stream:TStream = ReadStream("littleendian::map"+mapNumber)
+               If stream = Null
+                       Return
+               EndIf
+               Local x,y;
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1
+                               map[x,y] = Readint(stream)
+                       Next
+               Next            
+               startPos.x = Readint(stream)
+               startPos.y = Readint(stream)
+               endPos.x = Readint(stream)
+               endPos.y = Readint(stream)
+               CloseStream stream
+       End Method
+
+
+' Handle mouse click
+       Method handleMouseDown(blockX:Int, blockY:Int)
+
+               If blockX = oldBlockX And blockY = oldBLockY
+                       setRedraw(False)
+                       Return
+               EndIf
+               oldBlockX = blockX
+               oldBlockY = blockY
+
+' Make sure they can't edit over the start and end positions
+               If startPos.isAtPos(blockX, blockY)
+                       setRedraw(False)
+                       Return
+               EndIf
+               If endPos.isAtPos(blockX, blockY)
+                       setRedraw(False)
+                       Return
+               EndIf
+
+' See if they are selecting a new terrain
+               If blockX = terrainLegendBlockX And blockY >= terrainLegendBlockY And blockY < terrainLegendBlockY + numTerrainTypes
+                       currentTerrainIndex = blockY - terrainLegendBlockY 
+                       Return
+               EndIf
+
+               If blockInMapArea(blockX, blockY)
+                       map[blockX, blockY] = currentTerrainIndex
+                       setRedraw(True)
+                       Return
+               EndIf
+
+' See if we have selected a new map
+               If blockX >= mapButtonBlockX And blockY = mapButtonBlockY
+                       Local block:Int = blockX - mapButtonBlockX
+                       Select block
+                               Case 8
+                                       message = saveMap(currentMap)
+                               Case 9
+                                       handleHeuristic()
+                               Default
+                                       If block < 8 
+                                               currentMap = block
+                                               loadMap(currentMap)
+                                       EndIf
+                       End Select
+               EndIf
+               setRedraw(True)
+               Return                  ' Signal that we've moved the mouse and done something
+       End Method
+
+
+       Method handleHeuristic()
+               Local oldX:Int = MouseX()
+               Local oldY:Int = MouseY()
+
+               While MouseDown(1)
+                       Local x:Int = MouseX()
+                       Local y:Int = MouseY()
+                       If  x <> oldX
+                               heuristicMultiplier = heuristicMultiplier + (x - oldX) / 10.0
+                               If heuristicMultiplier < 0 heuristicMultiplier = 0
+                               If heuristicMultiplier > 10 heuristicMultiplier = 10
+                               runAStar()
+                               redraw(2)
+                               oldX:Int = x
+                               oldY:Int = y
+                       EndIf
+               Wend
+       End Method
+
+' Are the block coordinates with in the map area?
+       Method blockInMapArea(blockX:Int, blockY:Int)
+               Return blockX >= 0 And blockY >= 0 And blockX < mapWidth And blockY < mapHeight 
+       End Method
+
+
+       Method drawPath()
+               If path <> Null
+                       Local a:Object
+                       For a:Object = EachIn path
+                               Local node:AStarNode = AStarNode(a)
+                               SetColor 255,255,0
+                               DrawRect node._x * blockWidth, node._y * blockHeight, blockWidth - 1, blockHeight - 1
+                       Next
+               EndIf
+       End Method
+
+' Draw the information text in the editor
+       Method drawInfo()
+' Clear 
+               Local y = mapButtonBlockY * blockHeight + blockHeight
+               SetColor 0,0,0
+               DrawRect 0, y, blockAreaWidth, blockHeight*5
+
+' Draw the distance function used
+               SetColor 255,255,255
+               DrawText distanceNames[distanceFunction], 0, y 
+
+' Whether diagonals are allowed or not
+               Local path:String
+               If allowDiagonalPaths
+                       path = "(A) Diagonals allowed"
+               Else
+                       path = "(A) Diagonals not allowed"
+               EndIf
+               DrawText path, 0, y + TextHeight(path)
+               
+' How long last path walk took         
+'              Local percentOfFrame:Float = lastRunTime * (60.0/1000.0) * 100.0
+'              DrawText "Milli:" + lastRunTime + "   % of 60th:" + percentOfFrame, 0, y + FontHeight() * 5
+
+'      
+               Local diagonals:String;
+               If diagonalsAreLonger 
+                       diagonals = "(V) Diagonals are longer than straights"
+               Else
+                       diagonals = "(V) Diagonals are same as straights"
+               EndIf
+               DrawText diagonals, 0, y + TextHeight(diagonals) * 2
+
+               DrawText "Heuristic:" + heuristicMultiplier, 0, y + TextHeight(heuristicMultiplier) * 4
+               SetColor 255,0,0
+               DrawText message, 0, y + TextHeight(message) * 5
+               SetColor 255,255,255
+
+' Draw help
+               Local a:String
+               Local count:Int = 0
+               For a:String = EachIn help
+                       DrawText a, blockAreaWidth, blockAreaHeight / 4 + count * TextHeight(a)
+                       count = count + 1
+               Next
+       End Method
+
+       Method drawMapButtons()
+               Local y = mapButtonBlockY * blockHeight
+               Local x = mapButtonBlockX * blockWidth
+               Local startX = x
+               Local t
+               Local output:String
+               For t = 0 To 9
+                       If t < 8 
+                               SetColor 255,255,255
+                               output = t
+                       Else If t = 8
+                               SetColor 255,0,0
+                               output = "S"
+                       Else If t = 9
+                               SetColor 0,255,0
+                               output = "H"
+                       EndIf
+                       DrawRect x, y, blockWidth - 1, blockHeight
+                       SetColor 0,0,0
+                       DrawText output, x, y
+                       x = x + blockWidth
+               Next
+' Current map
+               y = mapButtonBlockY * blockHeight  - blockHeight
+               x = mapButtonBlockX * blockWidth
+               SetColor 0,0,0
+               DrawRect x,y,blockAreaWidth,TextHeight(" ")
+               SetColor 255,255,255
+               DrawText "Current map:" +  currentMap, x, y
+
+       End Method
+
+       Method drawTerrains()
+               Local t
+               For t = 0 To numTerrainTypes - 1
+                       Local terrain:Terrain = terrains[t]
+                       Local x = terrainLegendBlockX * blockWidth
+                       Local y = (terrainLegendBlockY + t)* blockHeight
+
+                       SetColor 0,0,0
+                       DrawRect x, y, blockWidth * 5, blockHeight
+
+                       SetColor 255,255,255
+                       SetScale blockWidth / 32.0, blockHeight / 32.0
+                       DrawImage terrain._image, x, y
+                       SetScale 1,1
+       
+                       If showCosts
+                               SetColor 255,255,255
+                               DrawText terrain._weight, x + blockWidth , y
+                       EndIf
+       Next
+       End Method
+
+       Method drawMap()
+               SetColor 0,0,0
+               DrawRect 0, 0, blockAreaWidth, blockAreaHeight
+               Local x,y;
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1
+                               drawMapBlock(x,y)
+                       Next
+               Next            
+       End Method
+
+       Method drawMapBlock(x:Int, y:Int)
+               SetColor 255,255,255
+               If startPos.isAtPos(x,y)
+                       SetColor 255,255,0
+               Else If endPos.isAtPos(x,y)
+                       SetColor 255,0,0
+               Else
+'                      SetColor(terrains[map[x,y]]._colour)
+               EndIf
+               SetScale blockWidth / 32.0, blockHeight / 32.0
+               DrawImage terrains[map[x,y]]._image, x * blockWidth, y * blockHeight
+               SetScale 1,1
+       End Method
+
+       Method drawOnMap(x:Int, y:Int, r,g,b, margin:Int)
+               SetColor r,g,b
+               DrawRect x * blockWidth + margin, y * blockHeight + margin, blockWidth - margin * 2, blockHeight - margin * 2
+       End Method
+
+       Method printOnMap(x:Int, y:Int, text:String, offset:Int)
+               SetColor 255,255,255
+               SetScale textScale,textScale
+               DrawText text, x * blockWidth, y * blockHeight + offset
+               SetScale 1,1
+       End Method
+
+       Method printNums(s:String, x:Int, y:Int, offset:Int)
+               x = x * blockWidth + blockWidth / 2 - (Len(s) * 5)/2
+               y = y * blockHeight + offset
+               SetColor 255,255,255
+               SetMaskColor 255,0,255
+               SetScale 1,1
+               Local t
+               For t = 0 To Len(s) - 1
+                       DrawImage nums, x, y, Byte(s[t]) - 46
+                       x:+5
+               Next
+       End Method
+
+
+' Initialise the map and edit stuff
+       Method initialise()
+       
+'              blockWidth = blockAreaWidth / mapWidth
+'              blockHeight = blockAreaHeight / mapHeight
+
+' Setup other interactive pieces
+               terrainLegendBlockX = mapWidth + 1
+               terrainLegendBlockY = 0
+       
+'              map = Array:Int[mapWidth, mapHeight]
+'              nodeMap = Array:AStarNode[mapWidth, mapHeight]
+
+' Initialise terrain types
+               Local t
+               For t = 0 To numTerrainTypes - 1
+                       Local newTerrain:Terrain = New Terrain
+                       newTerrain.set(terrainWeights[t], terrainFilenames[t])
+                       terrains[t] = newTerrain
+               Next
+
+               startPos = New MapPos
+               startPos.x = 1
+               startPos.y = 1
+       
+               endPos = New MapPos
+               endPos.x = mapWidth - 2
+               endPos.y = mapHeight - 2
+               
+' Initialise the map
+               SeedRnd MilliSecs()
+               Local y
+               Local x
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1
+                               Local value:Int = 0'Rand(0,numTerrainTypes - 1)
+
+                               If y = 0 Or y = mapHeight - 1 Or x = 0 Or x = mapWidth - 1
+                                       value = 1
+                               EndIf
+
+                               map[x,y] = value 'Readint(stream)
+                       Next
+               Next
+       End Method
+
+' This runs AStar with the current setup
+
+       Method runAStar()
+
+' The first thing you need to do before using the AStarGraphWalker is to create your nodes, and link them up
+' with edges. What I do is first make an array of the nodes, this makes it easy to map nodes to map blocks if
+' I need to and other things.
+' Then I go over the node array and create links to the neighbouring nodes.
+'
+' NOTE: In my implementation you will notice that between two blocks, two edges are created.
+' Block 1 has an edge to block 2 (which is it's neighbour) and viceversa. If you wanted to
+' simplify this, you could, but you'd have to change the datastructure a little. I prefer my way (Except of course 
+' that more memory is consumed) because I can have different costs to get from A to B than from B to A, for example
+' if A was at the top of a hill and B at the bottom. In that case, going from A to B is generally easier than B to A
+               Local x:Int
+               Local y:Int
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1
+                               nodeMap[x,y] = New AStarNode
+                               Local node:AStarNode = nodeMap[x,y]
+                               node._x = x                     ' AStar needs these positions for distance estimation
+                               node._y = y
+                       Next
+               Next
+' This is just an array of offsets to give us our neighbours
+               Const offsetCount:Int = 8
+               Local xOffset:Int[] = [ 0,1,1,1,0,-1,-1,-1 ]
+               Local yOffset:Int[] = [ -1,-1,0,1,1,1,0,-1 ]
+
+' How we move through the offsets, so we can support "no diagnoal" paths
+               Local offsetStep:Int = 1
+               If Not allowDiagonalPaths
+                       offsetStep = 2
+               EndIf
+
+' This loop builds up all the neighbour lists for a node               
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1               
+                               If map[x,y] = 1
+                                       Continue                ' We don't worry about this node if we aren't passable
+                               EndIf
+                               Local node:AStarNode = nodeMap[x,y]
+' Now look around the map for neighbours and make nodes 
+' Joining the current one with a neighbour
+                               Local off = 0
+                               While off < offsetCount
+                                       Local neighbourX = x + xOffset[off]
+                                       Local neighbourY = y + yOffset[off]             
+' Check that the neighbour position is within the map bounds and is actually
+' not block 1 which I've designated as a block we can't go through at all so no point
+' making a neighbour of it
+                                       If map[neighbourX, neighbourY] <> 1 And neighbourX >= 0 And neighbourX < mapWidth And neighbourY >=0 And neighbourY < mapHeight
+                                               Local value:Int = terrains[map[x,y]]._weight
+                                               Local neighbourValue:Int = terrains[map[neighbourX,neighbourY]]._weight
+
+' Here is where you calculate the costs of the edge between two nodes. Because our map is square and the neighbour
+' I'm looking at is adjacent to the current node, then I can just take an average of the costs of each block.
+' E.G If the current block is water, and the neighbour is forest, I'd be walking half in water and half in forest
+' This isn't really necessary but I do it anyway
+                                               Local edgeCost:Float = (value + neighbourValue) / 2.0
+' Now if it's a diagonal we might want to make the cost of this edge higher to signify that
+' travelling diagonally in a suare environment like ours is a longer distance
+                                               If diagonalsAreLonger And xOffset[off] <> 0 And yOffset[off] <> 0
+                                                       edgeCost = edgeCost * 1.4;
+                                               EndIf           
+                                               node.addNeighbour(nodeMap[neighbourX, neighbourY], edgeCost)
+                                       EndIf           
+                                       off = off + offsetStep
+                               Wend
+                       Next
+               Next            
+
+' We have our node, so we can set up our AStarGraphWalker now.
+               Local walker:AStarGraphWalker = New AStarGraphWalker
+               
+               walker.setParameters(nodeMap[startPos.x,startPos.y], nodeMap[endPos.x,endPos.y], mapWidth * mapHeight)
+               walker.setDistanceFunction(distanceFunction)            ' If not called, default is distanceEuclidean
+               walker.setHeuristicMultiplier(heuristicMultiplier)                      ' If not called, default to 1
+
+' Set up our callback information. The callback is called after one node has been popped and processed
+               Local callback:WalkerCallback = New WalkerCallback
+               callback._walker = walker
+               callback._application = Self
+               If showProgress 
+                       walker.setCallback(callback)
+               EndIf
+
+               Local start:Int = MilliSecs()
+               Local res:Int = walker.walk()           
+               Local time:Int = MilliSecs() - start
+
+               If res
+                       path = walker.getFinalPath()            
+                       If showProgress 
+                               drawPath()
+                               Flip
+                       EndIf
+               Else
+                       path = Null
+               EndIf
+'EndRem
+
+' Tidy up after ourselves
+       walker.setCallback(Null)        
+
+' Need to make sure memory gets freed because we have references to objects all over
+' the place
+               For y = 0 To mapHeight - 1
+                       For x = 0 To mapWidth - 1               
+                               Local node:AStarNode = nodeMap[x,y]                             
+                               Local neighbour:AStarNeighbourInfo
+                               For neighbour:AStarNeighbourInfo = EachIn node.getNeighbours()
+                                       neighbour.free()
+                               Next
+                               walker.resetNode(node)
+                               nodeMap[x,y] = Null
+                       Next
+               Next
+               Return time
+       End Method
+EndType
+
+' This is our personal callback function so that we can draw the map. In a real implementation you might not have this
+' or maybe the callback allows you to check to see if the algorithm is taking too long and so pause for a frame and continue
+' next frame. You'd need some more work that though
+Type WalkerCallback Extends AStarCallback
+
+       Method New()
+               _waitForKey = True                      ' If ever set to false, then we are ignoring the callback so we just return
+       End Method
+
+       Method callback()
+                       If _waitForKey = False                  ' If not waiting for key, then we've finished
+                               While KeyDown(27) Wend
+                               _application.setRedraw(True)
+                               Return
+                       EndIf
+                       Local currentNode:AStarNode = node
+               
+                       _application.redraw(1,0)
+                       Local x:Int
+                       Local y:Int
+
+                       For y = 0 To _application.mapHeight - 1
+                               For x = 0 To _application.mapWidth - 1
+                                       Local node:AStarNode = _application.nodeMap[x,y]
+                                       Local col_r=128,col_g=128,col_b=128
+                                       Local do:Int = 0;
+                                       If node.inClosed() Or Not node.inOpen() Then 
+                                               Continue
+                                       EndIf
+                                       If node.inOpen() Then 
+                                               col_r=0 ; col_g=0 ;col_b=255
+                                               do = 1
+                                       EndIf
+                                       If do Then 
+                                               _application.drawOnMap(node._x, node._y, col_r, col_g, col_b , 2 )
+                                               _application.printNums(oneDec(node.costToGetHere()), node._x , node._y, 4 )
+                                               _application.printNums(oneDec(node._goalDistance), node._x , node._y, 11 )
+                                               _application.printNums(oneDec(node._key), node._x , node._y, 18 )
+                                       EndIf
+                               Next
+                       Next    
+                       Flip
+                       
+                       If KeyHit(KEY_P)
+                               WaitKey
+                       EndIf
+                       If KeyDown(27)
+                               _waitForKey = False
+                       EndIf
+
+       End Method
+
+' Makes a single decimal place string from a number - ugly....
+       Method oneDec:String(number:Float)
+               Return String(Int(number)) + "." + Int((number-Int(number))*10)
+       End Method
+
+       Field _walker:AStarGraphWalker;
+       Field _application:AStarDemo;
+       Field _waitForKey:Int
+EndType
+
+
diff --git a/samples/aaronkoolen/AStar/astar_graph_walker.bmx b/samples/aaronkoolen/AStar/astar_graph_walker.bmx
new file mode 100644 (file)
index 0000000..03e1319
--- /dev/null
@@ -0,0 +1,259 @@
+' Class for walking an astar graph
+' It's up to you to make the graph yourself.
+
+
+Import "astar_node.bmx"
+Import "priority_queue.bmx"
+Import "Callback.bmx"
+
+' Customised callback class
+Type AStarCallback Extends Callback
+       Field node:AStarNode;
+       Field queue:PriorityQueue
+End Type
+
+Type AStarGraphWalker
+
+' public
+' Constructor
+       Method New()
+               _queue = New PriorityQueue
+               _finalPath = New TList
+       End Method
+
+' public
+' Sets the parameters for walking
+' startNode - The first node in the graph where searching will start from
+' endNode      - The node you're trying to find the path to
+' maxNodes     - The maximum number of nodes in the graph you want to walk
+
+       Method setParameters(startNode:AStarNode, endNode:AStarNode, maxNodes:Int )
+               Assert startNode <> Null,"startNode Null"
+               Assert endNode <> Null,"endNode Null"
+               Assert maxNodes > 0,"maxNodes <= 0"
+               _start = startNode;                             ' The start of the graph
+               _end = endNode;                         ' The start of the graph
+               _queue.setMaxSize(maxNodes)
+               _parametersSet = True;
+       End Method
+
+' public
+' Sets the callback function
+' callback - A object with a callback() mtehod. Derive from Callback Type
+       Method setCallback(callback:AStarCallback)
+               _callback = callback
+       End Method
+
+       Method setDistanceFunction(func:Int)
+               _distanceFunction = func
+       End Method
+
+       Method setHeuristicMultiplier(heuristic:Float)
+               _heuristicMultiplier = heuristic
+       End Method
+
+' public
+' Returns the final path after a path find
+       Method getFinalPath:TList()
+               Assert _lastWalkSucceeded, "Can't return path as last path walk failed"
+               Return _finalPath
+       End Method
+
+' private
+' Makes the list of successors that will be searched next
+' ARGUMENTS:
+' node                 - The node who's successors we're looking at
+' endNode      - The destination node we're trying to get to
+       Method _makeSuccessors(node:AStarNode, endNode:AStarNode)
+               Local done:Int = False
+               For neighbour:AStarNeighbourInfo = EachIn node.getNeighbours()
+                       Local neighbourNode:AStarNode = neighbour.getNode()
+                       Assert neighbourNode,"Node is NULL"
+
+' Only look at neighbours that aren't the start node and also aren't in 
+' the closed list (We'd be backtracking)
+                       If neighbourNode <> _start And Not neighbourNode.inClosed()
+' Calculate total cost to get to this neighbour based on edge cost to neighbour +
+' current cost to get to us
+                               Local cost:Float = neighbour.edgeCost() + node.costToGetHere()
+' Estimate a distance to the goal from the neighbour
+                               Local goalDistance:Float = _distanceTo(neighbourNode, endNode)
+' If heuristic was 0 then we'd have an optimal search...
+                               goalDistance = goalDistance * _heuristicMultiplier
+' What we guess the total cost would be to get from start to finish through
+' this neighbour
+                               Local totalCostOfNeighbourPath:Float = goalDistance + cost
+
+' If we haven't visited this neighbour node yet at all, save it for later visiting                             
+' This line used to be If Not neighbourNode.inClosed() And Not neighbourNode.inOpen()
+' Don't need it as now we have the optimisation above that doesn't enter here if they
+' neighbour is in the closed list
+'                              If Not neighbourNode.inClosed()And  Not neighbourNode.inOpen()
+                               If Not neighbourNode.inOpen()
+' Assume we'll go from us to neighbour by setting us as the parent
+                                       neighbourNode.setParent(node)
+' Set the PQueue key as the total cost of this path to the goal
+' Queue is sorted smallest first so we always look at shortest distances
+                                       neighbourNode.setKey(totalCostOfNeighbourPath)  ' Goes in queue based on total distance
+' Save what we calculated that the cost was to get to this neighbour
+                                       neighbourNode.setCostToGetHere(cost)                                            ' What we consider it's cost is
+                                       neighbourNode.setGoalDistance(goalDistance)                                             ' What we consider it's cost is
+                                       neighbourNode.setInOpen(True)
+                                       _queue.insert(neighbourNode)
+                               Else
+' OK, neighbour is in a list (Actually must be in Open list at this point)
+' so see if we have a better path to it by seeing if the cost to get 
+' to this neighbour the other way is more than the cost from our node 
+' to this neighbour. 
+' If it is, then our path is better 
+                                       If neighbourNode.costToGetHere() > cost 
+' If it was in the closed list, then we're going to put it in the open list
+' cause we want to now be able to look at it again as a possible path
+'                                              If neighbourNode.inClosed()
+'                                                      neighbourNode.setInClosed(False)
+'                                              EndIf
+' Above is removed because of optimisation
+                                               neighbourNode.setParent(node)
+                                               neighbourNode.setKey(totalCostOfNeighbourPath)  ' Goes in queue based on total distance
+                                               neighbourNode.setGoalDistance(goalDistance)             ' Estimate to get to goal
+                                               neighbourNode.setCostToGetHere(cost)                    ' What we consider it's cost is
+'TODO: Optimise this. Rather than remove and add, we could shift in the queue if
+' we knew it's index.
+' Removed if below because optimisation allows us to know that we must be in the open list to get here
+'                                              If neighbourNode.inOpen()
+                                                       pos:Int = _queue.find(neighbourNode)
+                                                       Assert pos > 0, "Was going to remove item that wasn't in queue!"
+                                                       _queue.remove(pos)
+                                                       neighbourNode.setInOpen(False)
+'                                              EndIf
+                                               _queue.insert(neighbourNode)
+                                               neighbourNode.setInOpen(True)                                           
+                                       EndIf
+                               EndIf
+                       EndIf
+'                      If _callback <> Null
+'                              _callback.node = node
+'                              _callback.queue = _queue
+'                              _callback.callback()
+'                              Flip;WaitKey
+'                      EndIf
+               Next
+       End Method
+
+
+' public
+' Method to walk the graph, finding the shortest path
+' 
+' RETURNS:
+' False - Failed to find path to the end node
+' True         - Found a path to the end
+' PRE: Must have called setParameters first
+       Method walk()
+               Assert _parametersSet,"Must call setParameters() first"
+
+               _lastWalkSucceeded = False
+
+               Local startNode:AStarNode = _start
+               Local endNode:AStarNode =_end
+               
+               ' Initialise starting node's information
+               Local distanceToGoal:Float = _distanceTo(_start, _end)
+               startNode.setCostToGetHere(0)
+               startNode.setKey(distanceToGoal * _heuristicMultiplier + startNode.costToGetHere())
+               startNode.setParent(Null)
+               startNode.setInOpen(True)
+               _queue.insert(startNode)
+               
+               While _queue.size() > 0
+                       Local node:AStarNode = AStarNode(_queue.remove())
+'                      node.setInOpen(False)
+                       node.setInClosed(True)
+
+' Have we found our destination???
+                       If node = endNode Then
+                               Local currentNode:AStarNode = node
+                               While currentNode <> Null
+                                       _finalPath.AddFirst(currentNode)
+                                       currentNode = currentNode.getParent()
+                               Wend
+                               _lastWalkSucceeded = True
+                               _queue = Null
+                               Return True
+                       EndIf
+
+                       _makeSuccessors(node, endNode)
+                       If _callback <> Null
+                               _callback.node = node
+                               _callback.queue = _queue
+                               _callback.callback()
+                       EndIf
+' temp
+
+               Wend
+               Return False
+       End Method
+
+' Resets a node so that it's ready for a new path find. Call this from whatever manages the nodes 
+' as AStarGraphWalker, doesn't actually know how many, or what nodes you have, but it does know how
+' to reset one
+       Method resetNode(node:AStarNode)
+               node._parentNode = Null
+               node.setInClosed(False)
+               node.setInOpen(False)
+       End Method
+
+'private
+
+' Returns an estimated distance between two nodes
+       Method _distanceTo:Float(startNode:AStarNode, endNode:AStarNode)
+               Local startX = startNode._x
+               Local startY = startNode._y
+               Local endX = endNode._x
+               Local endY = endNode._y
+               Local dx = Abs(endX - startX)
+               Local dy = Abs(endY - startY)
+'TODO: I had distanceFunction without the _ below and Blitz Didn't complain
+               Select _distanceFunction
+                       Case distanceEuclidean
+                               Return Sqr( dx * dx + dy * dy )
+                       Case distancePseudoEuclidean
+                               Return dx * dx + dy * dy
+                       Case distanceManhatten
+                               Return dx + dy
+                       Case distanceDiagonalShortcut
+                               If dx > dy
+                                    Return 1.4*dy + (dx-dy)
+                               Else
+                                    Return 1.4*dx + (dy-dx)
+                               End If
+                       Default
+                               Assert 0,"Bad distance function"
+               End Select
+       End Method
+
+' Fields
+
+' Possible ways to calculate distance. It's good to specify the edge costs between nodes
+' relative to your distance calculations because as they are related. For instance, if you calculate edge costs
+' using simple Euclidean distance, so that two adjacent blocks would be 1 away or 1.4 (if diagonal)
+' multiplied by some small "difficulty factor", say 1 for normal roads, or 2 for water
+' Then distanceEuclidean is a good estimator of distance and distancePseudoEuclidean
+' tends to override the edgecosts and the pathfinder sort of busts through them. 
+' This can be a good thing as it could provide a simple way to make a unit "dumber"
+       Const distanceEuclidean = 0
+       Const distancePseudoEuclidean = 1
+       Const distanceManhatten = 2
+       Const distanceDiagonalShortcut = 3
+
+       Field _heuristicMultiplier = 1                  ' 0 should generate "optimal" path
+       Field _start:AStarNode
+       Field _end:AStarNode
+       Field _distanceMode:Int = distanceEuclidean
+       Field _queue:PriorityQueue
+       Field _parametersSet = False
+       Field _finalPath:TList
+       Field _callback:AStarCallback = Null
+       Field _distanceFunction = distanceEuclidean
+       Field _lastWalkSucceeded = False
+
+EndType
diff --git a/samples/aaronkoolen/AStar/astar_node.bmx b/samples/aaronkoolen/AStar/astar_node.bmx
new file mode 100644 (file)
index 0000000..234a4df
--- /dev/null
@@ -0,0 +1,117 @@
+' This is an implementation of an AStar Algorithm
+
+Strict
+Import "priority_queue.bmx"
+
+'Private
+' Each AStar node has a list of neighbours that it connects to
+' This is the AStarNeighbourInfo type. AStarNeighbourInfo
+' holds both a reference to the neighbouring nodes, but also information
+' about the cost to get to that node
+Type AStarNeighbourInfo
+       Method getNode:AStarNode()
+               Return _neighbour
+       End Method
+
+       Method edgeCost:Float()
+               Return _edgeCost
+       End Method
+
+       Method free()
+               _neighbour = Null
+       End Method
+' private
+       Field _neighbour:AStarNode
+       Field _edgeCost:Float                   ' Cost to get to this neighbour 
+EndType
+
+Public
+' These are the nodes in the AStar graph
+Type AStarNode Extends PriorityQueueNode
+' public
+
+' Call this to add a fully constructed neighbour node to this node
+       Method addNeighbour(neighbourNode:AStarNode, edgeCost:Float)
+               Local neighbourInfo:AStarNeighbourInfo = New AStarNeighbourInfo
+
+               neighbourInfo._neighbour        = neighbourNode
+               neighbourInfo._edgeCost         = edgeCost
+
+               _neighbours.AddLast(neighbourInfo)
+       End Method
+
+       Method getNeighbours:TList()
+               Return _neighbours
+       End Method
+
+       Method setGoalDistance(goalDistance:Float)
+               _goalDistance = goalDistance
+       End Method
+
+       Method goalDistance:Float()
+               Return _goalDistance
+       End Method
+
+       Method setCostToGetHere(cost:Float)
+               _costFromStart = cost
+       End Method
+
+       Method costToGetHere:Float()
+               Return _costFromStart
+       End Method
+
+' Yes using PTR here is what we want
+       Method setParent(parent:AStarNode)
+               _parentNode = parent
+       End Method
+
+       Method getParent:AStarNode()
+               Return _parentNode
+       End Method
+
+' Sets whether the node is in the open list or not
+       Method setInOpen(inOpen:Int)
+               _inOpen = inOpen
+       End Method
+
+       Method inOpen()
+               Return _inOpen
+       End Method
+
+' Sets whether the node is in the closed list or not
+       Method setInClosed(inClosed:Int)
+               _inClosed = inClosed
+       End Method
+
+       Method inClosed()
+               Return _inClosed
+       End Method
+
+' Initialise new nodes to default values
+       Method New()
+               _costFromStart  = 0
+               _parentNode             = Null
+               _neighbours     = New TList
+               _inOpen                 = False
+               _inClosed               = False
+               _goalDistance   = 0
+       End Method
+
+' private
+       Field _costFromStart:Float                      ' We keep track of cost to get to this node
+       Field _goalDistance:Float                       ' Goal to distance
+       Field _parentNode:AStarNode                     ' Used to trace back from the end to the start of the finished path
+       Field _neighbours:TList                         ' The neighbours of this node
+
+       Field _inOpen:Int                                       ' Keep track of what list the node is in
+       Field _inClosed:Int
+
+' TODO:
+' These are required in order to calculate distance
+' What would be better is to provide something like an AStarPos object
+' with a method to get distance between them that way you could provide a more
+' generic mechanism for distanc calculation
+       Field _x:Int
+       Field _y:Int            
+
+End Type
diff --git a/samples/aaronkoolen/AStar/map0 b/samples/aaronkoolen/AStar/map0
new file mode 100644 (file)
index 0000000..542ffa9
Binary files /dev/null and b/samples/aaronkoolen/AStar/map0 differ
diff --git a/samples/aaronkoolen/AStar/map1 b/samples/aaronkoolen/AStar/map1
new file mode 100644 (file)
index 0000000..285a679
Binary files /dev/null and b/samples/aaronkoolen/AStar/map1 differ
diff --git a/samples/aaronkoolen/AStar/map2 b/samples/aaronkoolen/AStar/map2
new file mode 100644 (file)
index 0000000..baa5e45
Binary files /dev/null and b/samples/aaronkoolen/AStar/map2 differ
diff --git a/samples/aaronkoolen/AStar/map3 b/samples/aaronkoolen/AStar/map3
new file mode 100644 (file)
index 0000000..3d1ea51
Binary files /dev/null and b/samples/aaronkoolen/AStar/map3 differ
diff --git a/samples/aaronkoolen/AStar/map4 b/samples/aaronkoolen/AStar/map4
new file mode 100644 (file)
index 0000000..30063c4
Binary files /dev/null and b/samples/aaronkoolen/AStar/map4 differ
diff --git a/samples/aaronkoolen/AStar/map5 b/samples/aaronkoolen/AStar/map5
new file mode 100644 (file)
index 0000000..db1e218
Binary files /dev/null and b/samples/aaronkoolen/AStar/map5 differ
diff --git a/samples/aaronkoolen/AStar/map6 b/samples/aaronkoolen/AStar/map6
new file mode 100644 (file)
index 0000000..0a06346
Binary files /dev/null and b/samples/aaronkoolen/AStar/map6 differ
diff --git a/samples/aaronkoolen/AStar/map7 b/samples/aaronkoolen/AStar/map7
new file mode 100644 (file)
index 0000000..d3b6fee
Binary files /dev/null and b/samples/aaronkoolen/AStar/map7 differ
diff --git a/samples/aaronkoolen/AStar/mountain.png b/samples/aaronkoolen/AStar/mountain.png
new file mode 100644 (file)
index 0000000..5ca2107
Binary files /dev/null and b/samples/aaronkoolen/AStar/mountain.png differ
diff --git a/samples/aaronkoolen/AStar/nums.png b/samples/aaronkoolen/AStar/nums.png
new file mode 100644 (file)
index 0000000..5813a74
Binary files /dev/null and b/samples/aaronkoolen/AStar/nums.png differ
diff --git a/samples/aaronkoolen/AStar/priority_queue.bmx b/samples/aaronkoolen/AStar/priority_queue.bmx
new file mode 100644 (file)
index 0000000..845ea69
--- /dev/null
@@ -0,0 +1,161 @@
+Strict
+'Module PUB.PriorityQueue
+
+'ModuleInfo "Author: Aaron Koolen"
+'ModuleInfo "Version: 1.0"
+
+Rem
+This is an implementation of a priority queue implemented as
+a heap stored in an array.
+Note, it might not be the most optimised code, as I don't know some
+of the BlitzMax tricks that I might be able to do here.
+Let me know if you see anything simple too slow or crappy. 
+End Rem
+
+
+' You should derive your nodes from this class
+'
+Type PriorityQueueNode
+       Method setKey(key:Float)
+               _key = key;
+       End Method
+       Field _key:Float                        ' I don't think blitz max has the concept of templated types?
+End Type
+
+
+' Main PriorityQueue class
+Type PriorityQueue
+' private
+       Field _contents:PriorityQueueNode[]
+       Field _size:Int = 0
+       Field _sizeSet:Int = 0
+
+' public
+
+' Must call this first before you do anything
+       Method setMaxSize(newSize:Int)
+               Assert newSize > 0, "Must set size of queue > 0"
+               _contents = New PriorityQueueNode[newSize + 1]  ' We don't add any, you have to add them
+               _size = 0
+               _sizeSet = newSize
+       End Method
+
+'---------------------------------------
+' Queue manipulation
+'---------------------------------------
+
+' Insert a node into the queue
+       Method insert(newNode:PriorityQueueNode)
+               Assert _sizeSet > 0,"Must call setMaxSize first with size > 0"
+               Assert _size < _sizeSet, "Queue is full" 
+               _size = _size + 1
+               _contents[_size] = newNode
+               _reheapUp(_size)
+       End Method
+
+' Remove and return a node from the queue and re-sort queue
+       Method remove:PriorityQueueNode(index:Int = 1)
+               Local node:PriorityQueueNode = _contents[index]
+               _contents[index] = _contents[_size]
+               _size = _size - 1
+               _reheapDown(index, _size)
+               Return node
+       End Method
+
+'---------------------------------------
+' Queue searching
+'---------------------------------------
+       Method find:Int(node:PriorityQueueNode)
+               Local t
+               For t = 1 To _size
+                       If node = _contents[t]
+                               Return t
+                       EndIf
+               Next
+               Return 0
+       End Method
+' Return the current size of the queue
+       Method size:Int()
+               Return _size
+       End Method
+
+' Helper function for returning the nodes as an ordered list
+       Method returnList:TList()
+               Local list:Tlist = New TList
+               Local a:PriorityQueueNode
+               For a = EachIn _contents
+                       list.AddLast(remove(1))         ' The '1' here removes the top item
+               Next
+               Return list
+       End Method
+
+'------------------------------------------------
+' PRIVATE
+'------------------------------------------------
+' Reheap an inserted item
+' ARGUMENTS:
+' index - The Index of the newly inserted item
+       Method _reheapUp(index:Int)
+               Local parentIndex = _parent(index)
+               Local ok = False
+               While( index > 1 And ok = False )
+                       If _contents[parentIndex]._key < _contents[index]._key Then
+                               ok = True
+                       Else
+                               Local temp:PriorityQueueNode = _contents[parentIndex]
+                               _contents[parentIndex] = _contents[index]
+                               _contents[index] = temp
+                               index = parentIndex
+                               parentIndex = _parent(index)
+                       EndIf
+               Wend
+               Return index
+       End Method
+
+' Reheaps downward - Called after a delete of a node
+' ARGUMENTS:
+' root                 - Index of the root (Top of tree) item
+' bottom       -  The index of the last item in the tree
+       Method _reheapDown(root:Int, bottom:Int)
+               Local ok = False
+               Local maxChild = 0
+               
+               While _left(root) <= bottom And ok = False
+                       If _left(root) = bottom
+                               maxChild = _left(root)
+                       Else
+                               If _contents[_left(root)]._key < _contents[_right(root)]._key 
+                                       maxChild = _left(root)
+                               Else
+                                       maxChild = _right(root)
+                               EndIf                           
+                       EndIf
+                       If Not (_contents[root]._key < _contents[maxChild]._key) Then
+                               Local t:PriorityQueueNode = _contents[root]
+                               _contents[root] = _contents[maxChild]
+                               _contents[maxChild] = t
+                               root = maxChild
+                       Else
+                               ok = True
+                       EndIf
+               Wend            
+               Return root
+       End Method
+
+' Returns the index of the parent node to a child node
+       Method _parent:Int(childIndex:Int)
+               Return childIndex / 2
+       End Method
+
+' Returns the index of the left child of a node
+       Method _left:Int(siblingIndex:Int)
+               Return siblingIndex * 2
+       End Method
+
+' Returns the index of the right child of a node
+       Method _right:Int(siblingIndex:Int)
+               Return siblingIndex * 2 +1
+       End Method
+
+End Type
+
diff --git a/samples/aaronkoolen/AStar/road.png b/samples/aaronkoolen/AStar/road.png
new file mode 100644 (file)
index 0000000..aa2b97c
Binary files /dev/null and b/samples/aaronkoolen/AStar/road.png differ
diff --git a/samples/aaronkoolen/AStar/tree.png b/samples/aaronkoolen/AStar/tree.png
new file mode 100644 (file)
index 0000000..bacff75
Binary files /dev/null and b/samples/aaronkoolen/AStar/tree.png differ
diff --git a/samples/aaronkoolen/AStar/water.png b/samples/aaronkoolen/AStar/water.png
new file mode 100644 (file)
index 0000000..537a8ef
Binary files /dev/null and b/samples/aaronkoolen/AStar/water.png differ
diff --git a/samples/birdie/games/tempest/tempest.bmx b/samples/birdie/games/tempest/tempest.bmx
new file mode 100644 (file)
index 0000000..c89456f
--- /dev/null
@@ -0,0 +1,443 @@
+'Tempest
+'Coded by David Bird
+Strict
+
+Const CWidth#=640
+Const CHeight#=480
+Const K# = 50
+
+Global CCenterX#=CWidth/2.0
+Global CCenterY#=(CHeight/3.0)'*2
+
+Global SHOT_LIST:TList = New TList
+Global theLevel:Level
+
+Function TFormSZ#(x#, z#)
+  z:+5
+  Return (x/(z/K))
+EndFunction
+
+Function TForm(x#, y#, z#, x2d# Var, y2d# Var )
+  z:+5
+  y:+100
+  x2d = CCenterX+(x/(z/K))
+  y2d = CCenterY+(y/(z/K))
+EndFunction
+
+'Setup Graphics mode
+Graphics CWidth,CHeight,32
+
+HideMouse
+
+
+Global MainPlayer:Player
+
+Type Player
+  Field e_Index        'the edge the player is on
+  Field zPos
+
+  Field scl#=0.5          'where on the edge 0-1
+
+  Method SetEdge(index)
+    e_index = index
+  EndMethod
+
+  Method AddShot()
+    Shot.Create(theLevel.edges[e_Index])
+  EndMethod
+
+  Method ShiftLeft()
+    If e_Index=0
+      e_Index = theLevel.e_Cnt-1
+    Else
+      e_Index:-1
+    EndIf
+  EndMethod
+
+  Method ShiftRight()
+    If e_Index=theLevel.e_cnt-1
+      e_Index = 0
+    Else
+      e_Index:+1
+    EndIf
+  EndMethod
+
+  Method Update()
+    'Control it
+    If KeyHit(KEY_SPACE) self.AddShot()
+
+    If KeyDown(KEY_LEFT)
+      scl:-0.1
+      If scl<0 Then
+        self.ShiftLeft()
+        scl:+1
+      EndIf
+    EndIf
+    If KeyDown(KEY_RIGHT)
+      scl:+0.1
+      If scl>1 Then
+        self.ShiftRight()
+        scl:-1
+      EndIf
+    EndIf
+    SetRotation 0
+    'Draw it
+    SetColor 255,255,0
+    Local zz#
+    Local x#[3],y#[3]
+    Select theLevel.state
+      Case Level_Begin
+        zz# = theLevel.position
+      Case Level_Ready
+        zpos=theLevel.position
+        zz = zpos
+      Case Level_Complete
+        zz = zpos
+    EndSelect
+
+
+    Local zh# = 4
+    Local e:Edge = theLevel.edges[e_Index]
+    TForm e.p1.x, e.p1.y, zz,x[0],y[0]
+
+    TForm e.p2.x+ ( (e.p1.x - e.p2.x) * scl ), e.p2.y+ ( (e.p1.y - e.p2.y) * scl ),zz-zh,x[1],y[1]
+
+    TForm e.p2.x, e.p2.y, zz,x[2],y[2]
+    DrawLine x[0],y[0],x[1],y[1]
+    DrawLine x[1],y[1],x[2],y[2]
+  EndMethod
+
+
+  Function Create:Player()
+    Local p:Player = New Player
+
+    Return p
+  EndFunction
+EndType
+
+Type Point
+  Field x#,y#
+  Field e0:edge
+  Field e1:edge
+
+  Function Create:Point( x#, y# )
+    Local p:Point = New Point
+    p.x=x
+    p.y=y
+    Return p
+  EndFunction
+
+EndType
+
+Type Edge
+  Field p1:point
+  Field p2:point
+
+  Field xx#,yy#
+
+  Method Draw( zd1#, zd2# )
+    If zd1<1 zd1=1
+    If zd2<1 zd2=1
+
+    'draw the edge at zero position,
+    'the depth line and the far point
+    Local x#[4],y#[4]
+    TForm p1.x,p1.y,zd1, x[0],y[0]
+    TForm p1.x,p1.y,zd2, x[1],y[1]
+
+    TForm p2.x,p2.y,zd1, x[2],y[2]
+    TForm p2.x,p2.y,zd2, x[3],y[3]
+
+    DrawLine x[0],y[0],x[1],y[1]
+    DrawLine x[0],y[0],x[2],y[2]
+    DrawLine x[1],y[1],x[3],y[3]
+    DrawLine x[3],y[3],x[2],y[2]
+  EndMethod
+
+  Function Create:Edge(p1:Point, p2:Point)
+    Local e:Edge = New edge
+
+    'assign the points
+    e.p1=p1
+    e.p2=p2
+
+    'linkem up
+    p1.e1=e
+    p2.e0=e
+    
+    'store the midpoint for speeding up
+    e.xx =( ( p2.x - p1.x ) / 2.0 ) + p1.x
+    e.yy =( ( p2.y - p1.y ) / 2.0 ) + p1.y
+
+    Return e
+  EndFunction
+EndType
+
+Const Level_Begin    = 0
+Const Level_Complete = 1
+Const Level_Ready    = 2
+
+Type Level
+  Field depth#    = 400
+  Field position# = 1500
+  Field move#     = 0
+  Field state     = Level_Begin
+
+  Field points:TList
+  Field edges:Edge[10],e_cnt,e_cap=10
+
+  Method AddPoint:Point(x#,y#)
+    Local p:Point = Point.Create( x, y )
+    points.AddLast( p )
+    Return p
+  EndMethod
+
+  Method AddEdge:Edge( p1:Point, p2:point )
+    Local e:Edge = Edge.Create( p1, p2 )
+    If e_cnt>=e_cap
+      e_cap:+10
+      edges=edges[..e_cap]
+    EndIf
+    edges[e_cnt] = e
+    e_cnt:+1
+    Return e
+  EndMethod
+
+  Method Update()
+    Select state
+      Case Level_Begin
+        If position>50
+          position:-10
+        Else
+          state=Level_Ready
+        EndIf
+      Case Level_Ready
+
+      Case Level_Complete
+        position:-10
+    EndSelect
+
+  EndMethod
+
+  Method Draw()
+    Local a=0
+    Select state
+      Case Level_Begin
+
+      Case Level_Ready
+
+      Case Level_Complete
+    EndSelect
+    SetRotation 0
+    SetColor 0,0,100
+    For a=0 Until e_cnt
+      edges[a].Draw(position,position+depth)
+    Next
+  EndMethod
+
+  Function Create:Level()
+    Local l:Level = New Level
+    l.points = New TList
+
+    Return l
+  EndFunction
+EndType
+
+Type Shot
+  Field e:edge  ' the edge its on
+  Field z#      ' its position
+  Field r#      ' rotation
+  Field xx#,yy#
+
+  Method Draw()
+    SetColor Rand(255),Rand(255),Rand(255)
+    Local zz = z+theLevel.position
+    Local sz = TFormSZ(10,zz)
+    Local pxx#,pyy#
+
+    TForm(xx,yy,zz,pxx,pyy)
+
+    For Local a=0 Until 360 Step 45
+      SetRotation r+a
+      DrawLine pxx+sz,pyy,pxx-sz,pyy
+    Next
+    r:+15
+    SetRotation 0
+  EndMethod
+
+  Method Update()
+    z:+5
+    Local bad:Baddies
+    If z>theLevel.depth
+      SHOT_LIST.Remove(Self)
+      Return
+    Else
+      'check for collisions
+      For bad = EachIn BaddieList
+        If bad.CheckColl(e,z)
+          SHOT_LIST.Remove(Self)
+          Return
+        EndIf
+      Next
+    EndIf
+
+  EndMethod
+
+  Function Create:Shot(e:Edge)
+    Local ns:Shot = New Shot
+    ns.e = e
+    ns.xx =e.xx
+    ns.yy =e.yy
+    ns.z  = -5
+    SHOT_LIST.AddLast( ns )
+    Return ns
+  EndFunction
+EndType
+
+Function UpdateShots()
+  Local s:shot
+  For s=EachIn SHOT_LIST
+    s.Update
+  Next
+  For s=EachIn SHOT_LIST
+    s.Draw()
+  Next
+EndFunction
+
+Global BaddieList:Tlist = New TList
+
+Function UpdateBaddies()
+  Local b:Baddies
+  For b = EachIn Baddielist
+    b.Update()
+  Next
+  For b = EachIn Baddielist
+    b.Draw()
+  Next
+EndFunction
+
+Type Baddies
+  Field OnEdge:Edge
+
+  Method Update() Abstract
+  Method Draw() Abstract
+  Method CheckColl(e:edge,z#) Abstract
+EndType
+
+Type Crawler Extends Baddies
+  Field EdgeIndex 'used to traverse theLevel edgelist
+  Field typ       '0 just slide up the tube
+                  '1 rolls round the tube
+
+  Field Pause     'the pause before changing edge
+  Field dir       'direction left or right
+  Field angle     'the angle when changing lanes
+
+  Method Update()
+  EndMethod
+  Method Draw()
+  EndMethod
+  Method CheckColl(e:edge,z#)
+  EndMethod
+
+  Function Create:Crawler(index,typ = 0)
+    Local c:Crawler = New Crawler
+    c.OnEdge = theLevel.edges[index]
+    c.typ    = typ
+    BaddieList.AddLast c
+    Return c
+  EndFunction
+EndType
+
+Type Spikes Extends Baddies
+  Field height#=0
+  Field grow_speed#
+
+  Method CheckColl(e:edge,z#)
+    'check to see if any will hit
+    Local sp# = theLevel.Depth-height
+    If e = OnEdge
+      If z>sp
+        height:-40
+        If height<0
+          BaddieList.Remove(Self)
+          Return True
+        EndIf
+        Return True
+      EndIf
+    EndIf
+    Return False
+  EndMethod
+
+  Method Draw()
+    Local xx#,yy#,zz1#,zz2#
+    zz1 = theLevel.position+theLevel.depth
+    zz2 = zz1 - height
+
+    Local x#[2],y#[2]
+    xx =( ( OnEdge.p2.x - OnEdge.p1.x ) / 2.0 ) + OnEdge.p1.x
+    yy =( ( OnEdge.p2.y - OnEdge.p1.y ) / 2.0 ) + OnEdge.p1.y
+    TForm(xx,yy,zz1,x[0],y[0])
+    TForm(xx,yy,zz2,x[1],y[1])
+    SetColor 0,255,0
+    DrawLine x[0],y[0],x[1],y[1]
+    SetColor 255,0,0
+    Plot x[1],y[1]
+  EndMethod
+
+  Method Update()
+    If height<theLevel.Depth
+      height:+grow_speed
+    Else
+      height = theLevel.Depth
+    EndIf
+  EndMethod
+
+  Function Create:Spikes(index,speed#)
+    Local s:Spikes = New Spikes
+    s.OnEdge=theLevel.Edges[index]
+    s.height=10
+    s.grow_speed# = speed
+    BaddieList.AddLast s
+    Return s
+  EndFunction
+EndType
+
+
+Local a
+Local p1:Point
+Local p2:Point
+Local fp:Point
+theLevel = Level.Create()
+MainPlayer = Player.Create()
+
+For a=0 Until 360 Step 30
+  p1 = theLevel.AddPoint( Cos(a)*280, Sin(a)*180 )
+  If p2
+    theLevel.AddEdge(p1,p2)
+  Else
+    fp = p1
+  EndIf
+  p2=p1
+Next
+Local lastedge:edge = theLevel.AddEdge(fp,p2)
+MainPlayer.SetEdge( 0 )
+
+For a=0 Until 10
+  spikes.Create( a ,Rnd(0.5,1.0))
+Next
+
+'main loop
+While Not KeyDown(KEY_ESCAPE)
+  Cls
+  theLevel.Update()
+  theLevel.Draw()
+  UpdateShots()
+  UpdateBaddies()
+
+  MainPlayer.Update()
+
+  Flip
+Wend
+End
+
diff --git a/samples/birdie/games/tiledrop/media/back.png b/samples/birdie/games/tiledrop/media/back.png
new file mode 100644 (file)
index 0000000..5777faa
Binary files /dev/null and b/samples/birdie/games/tiledrop/media/back.png differ
diff --git a/samples/birdie/games/tiledrop/media/blocks.png b/samples/birdie/games/tiledrop/media/blocks.png
new file mode 100644 (file)
index 0000000..0519dcd
Binary files /dev/null and b/samples/birdie/games/tiledrop/media/blocks.png differ
diff --git a/samples/birdie/games/tiledrop/media/part.png b/samples/birdie/games/tiledrop/media/part.png
new file mode 100644 (file)
index 0000000..93836ea
Binary files /dev/null and b/samples/birdie/games/tiledrop/media/part.png differ
diff --git a/samples/birdie/games/tiledrop/media/pointer.PNG b/samples/birdie/games/tiledrop/media/pointer.PNG
new file mode 100644 (file)
index 0000000..6080438
Binary files /dev/null and b/samples/birdie/games/tiledrop/media/pointer.PNG differ
diff --git a/samples/birdie/games/tiledrop/media/shine.png b/samples/birdie/games/tiledrop/media/shine.png
new file mode 100644 (file)
index 0000000..86ce18b
Binary files /dev/null and b/samples/birdie/games/tiledrop/media/shine.png differ
diff --git a/samples/birdie/games/tiledrop/tiledrop.bmx b/samples/birdie/games/tiledrop/tiledrop.bmx
new file mode 100644 (file)
index 0000000..b6367b2
--- /dev/null
@@ -0,0 +1,373 @@
+Strict
+Incbin "media/back.png"
+Incbin "media/blocks.png"            
+Incbin "media/part.png"
+Incbin "media/pointer.PNG"
+Incbin "media/shine.png"
+
+Graphics 640,480
+Global backIm:TImage = LoadImage("incbin::media/back.png")
+AutoMidHandle 1
+Global blocks:TImage = LoadAnimImage("incbin::media/blocks.png",32,32,0,16)
+Global partImg:TImage = LoadImage("incbin::media/part.png")
+Global mousePoint:TImage= LoadImage("incbin::media/pointer.PNG")
+Global shine_img:TImage = LoadImage("incbin::media/shine.png")
+AutoMidHandle 0
+Global Map[8,14]
+Global t1x,t1y,t2x,t2y
+Global mouse_left_state
+Global selection_done
+Global rotation# = 0
+Global Center_X#
+Global Center_Y#
+Global mt1,mt2
+Global Tile_Rad#
+Global THE_Axis
+Global FLIPSPEED=8
+Global Scn_Flash#=0
+Global shine_pos#=0
+
+HideMouse
+While Not KeyDown(KEY_ESCAPE)
+  Cls
+  DrawLayout()
+  If selection_done =0
+    FillGrid()
+  EndIf
+
+  DrawGrid()
+
+  If selection_done
+    do_swap_tiles()
+  Else
+    UpdateSelection()
+  EndIf
+
+  SetBlend MASKBLEND
+  DrawText mouse_left_state,0,0
+  DrawText t1x+","+t1y,0,12
+  DrawText t2x+","+t2y,0,23
+  DrawImage mousePoint,MouseX(),MouseY()
+  Flip
+Wend
+
+End
+Function UpdateSelection()
+  Local x=MouseX()-192
+  Local y=MouseY()-24
+  Local dx,dy
+
+  If MouseDown(1)
+    Select mouse_left_state
+      Case 0
+        If x>=0 And x<256
+          If y>=0 And y<448
+            'select tile1
+            t1x=Floor(x/32.0)
+            t1y=Floor(y/32.0)
+          EndIf
+        EndIf
+        'get tile 1
+        mouse_left_state=1
+      Case 2
+        If x>=0 And x<256
+          If y>=0 And y<448
+            'select tile1
+            t2x=Floor(x/32.0)
+            t2y=Floor(y/32.0)
+          EndIf
+        EndIf
+        mouse_left_state=3
+    EndSelect
+  Else
+    Select mouse_left_state
+      Case 1
+        mouse_left_state=2
+      Case 3
+        'check that only 1 tile away and not diag
+        dx=Abs(t2x-t1x)
+        dy=Abs(t2y-t1y)
+        If dx=1 And dy=0
+'          Switch(t1x,t1y,t2x,t2y)
+          selection_done=1
+        ElseIf dx=0 And dy=1
+'          Switch(t1x,t1y,t2x,t2y)
+          selection_done=1
+        EndIf
+          mouse_left_state=0
+      Case 99
+        mouse_left_state=0
+    EndSelect
+  EndIf
+
+EndFunction
+
+'add tiles to array at the top
+Function FillGrid()
+  Local x,y,tl,tlc
+  For x=0 Until 8
+    If map[x,0]=0
+      map[x,0]=1+Rnd(1)*7'15
+    EndIf
+  Next
+  'Fall
+  For y=12 To 0 Step -1
+    For x=0 Until 8
+      If map[x,y]>0
+        If map[x,y+1]=0
+          map[x,y+1]=map[x,y]
+          map[x,y]=0
+        EndIf
+      EndIf
+    Next
+  Next
+
+  For y=0 Until 14
+    For x=0 Until 8
+      tl=map[x,y]
+      If tl>0
+        If Counttile(x,y,tl,0,tlc)
+          KillTiles(x,y,tlc,0)
+        ElseIf Counttile(x,y,tl,1,tlc)
+          KillTiles(x,y,tlc,1)
+        ElseIf Counttile(x,y,tl,2,tlc)
+          KillTiles(x,y,tlc,2)
+        ElseIf Counttile(x,y,tl,3,tlc)
+          KillTiles(x,y,tlc,3)
+        EndIf
+
+      EndIf
+    Next
+  Next
+EndFunction
+
+Function KillTiles(x,y,c,dir)
+  Local d
+  For d=0 Until c
+    Select dir
+      Case 0
+        map[x,y]=0
+        y:-1
+      Case 1
+        map[x,y]=0
+        x:+1
+      Case 2
+        map[x,y]=0
+        y:+1
+      Case 3
+        map[x,y]=0
+        x:-1
+    EndSelect
+  Next
+EndFunction
+
+Function CountTile(x,y,ty,dir, cn Var)
+  cn = 0
+  Select dir
+    Case 0 ' Up
+      While y>0
+        If map[x,y]=ty
+          cn:+1
+        Else
+          Return cn>2
+        EndIf
+        y=y-1
+      Wend
+      Return cn>2
+    Case 1 ' Right
+      While x<8
+        If map[x,y]=ty
+          cn:+1
+        Else
+          Return cn>2
+        EndIf
+        x:+1
+      Wend
+      Return cn>2
+    Case 2 ' Down
+      While y<14
+        If map[x,y]=ty
+          cn:+1
+        Else
+          Return cn>2
+        EndIf
+        y:+1
+      Wend
+      Return cn>2
+    Case 3 ' Left
+      While x>0
+        If map[x,y]=ty
+          cn:+1
+        Else
+          Return cn>2
+        EndIf
+        x:-1
+      Wend
+      Return cn>2
+  EndSelect
+  cn = 0
+  Return 0
+EndFunction
+
+Function DrawGrid()
+  SetColor 255,255,255
+  Local x,y
+  For y=0 Until 14
+    For x=0 Until 8
+      If selection_done
+        If map[x,y]>0
+          If (x=t1x And y=t1y) Or (x=t2x And y=t2y)
+          Else
+            SetBlend MASKBLEND
+            DrawImage blocks,208+x*32,32+y*32,map[x,y]-1
+          EndIf
+        EndIf
+      Else
+        If map[x,y]>0
+          DrawImage blocks,208+x*32,32+y*32,map[x,y]-1
+        EndIf
+      EndIf
+    Next
+  Next
+  SetViewport 0,0,640,480
+EndFunction
+
+Function DrawLayout()
+  Cls
+  If Scn_Flash<0
+    Scn_Flash:+0.2
+  Else
+    Scn_Flash=0
+  EndIf
+    SetBlend SOLIDBLEND
+    SetColor 255,255,255
+  TileImage backIm,0,0
+  SetColor 128,128,128
+  SetViewport 192,24,256,448
+  Cls
+  TileImage backIm,0,0
+  If shine_pos#=0  SetViewport 0,0,640,480
+EndFunction
+
+Function CausesPop()
+  Local x,y,tl,tlc
+  For y=0 Until 14
+    For x=0 Until 8
+      tl=map[x,y]
+      If tl>0
+        If Counttile(x,y,tl,0,tlc)
+          Return 1
+        ElseIf Counttile(x,y,tl,1,tlc)
+          Return 1
+        ElseIf Counttile(x,y,tl,2,tlc)
+          Return 1
+        ElseIf Counttile(x,y,tl,3,tlc)
+          Return 1
+        EndIf
+      EndIf
+    Next
+  Next
+  Return 0
+EndFunction
+
+Function Switch(x0,y0,x1,y1)
+  Local a
+  a=map[x0,y0]
+  map[x0,y0]=map[x1,y1]
+  map[x1,y1]=a
+  If CausesPop() Return 1
+  a=map[x0,y0]
+  map[x0,y0]=map[x1,y1]
+  map[x1,y1]=a
+  Return 0
+EndFunction
+
+Function Do_Swap_Tiles()
+  Local x1,x2,y1,y2
+  Local size1#,size2#
+  Select selection_done
+    Case 1
+      'setup tile swap
+      rotation=180
+      selection_done = 2
+      'calculate center
+      x1 = 208+t1x*32
+      x2 = 208+t2x*32
+      y1 = 32+t1y*32
+      y2 = 32+t2y*32
+      Center_X = ((x2-x1)/2)+x1
+      Center_Y = ((y2-y1)/2)+y1
+      Tile_Rad = 16
+      'check side
+      If t1y=t2y
+        If t1x>t2x
+          mt1 = map[t2x,t2y]
+          mt2 = map[t1x,t1y]
+        Else
+          mt1 = map[t1x,t1y]
+          mt2 = map[t2x,t2y]
+        EndIf
+      Else
+        If t1y>t2y
+          mt1 = map[t2x,t2y]
+          mt2 = map[t1x,t1y]
+        Else
+          mt1 = map[t1x,t1y]
+          mt2 = map[t2x,t2y]
+        EndIf
+      EndIf
+
+      THE_Axis = 1
+      If t1y=t2y THE_Axis = 0
+    Case 2
+      If rotation<0
+        If Switch(t1x,t1y,t2x,t2y)
+          selection_done = 0
+        Else
+          selection_done = 3
+        EndIf
+      Else
+        rotation:-FLIPSPEED
+        size2# = 0.80+0.20*Sin(rotation)
+        size1# = 0.80+0.20*Sin(-rotation)
+        Select THE_Axis
+          Case 0 'x
+            SetScale size1,size1
+            DrawImage blocks, Center_X+Tile_Rad*Cos(rotation), Center_Y, mt1-1
+            SetScale size2,size2
+            DrawImage blocks, Center_X-Tile_Rad*Cos(rotation), Center_Y, mt2-1
+            SetScale 1,1
+          Case 1 ' y
+            SetScale size1,size1
+            DrawImage blocks, Center_X, Center_Y+Tile_Rad*Cos(rotation), mt1-1
+            SetScale size2,size2
+            DrawImage blocks, Center_X, Center_Y-Tile_Rad*Cos(rotation), mt2-1
+            SetScale 1,1
+        EndSelect
+      '  DrawImage blocks,192+t2x*32,24+t2y*32,mt2
+      EndIf
+    Case 3 '
+      If rotation>=180
+        selection_done = 0
+      Else
+        rotation:+FLIPSPEED
+        size2# = 0.80+0.20*Sin(rotation)
+        size1# = 0.80+0.20*Sin(-rotation)
+        Select THE_Axis
+          Case 0 'x
+            SetScale size1,size1
+            DrawImage blocks, Center_X+Tile_Rad*Cos(rotation), Center_Y, mt1-1
+            SetScale size2,size2
+            DrawImage blocks, Center_X-Tile_Rad*Cos(rotation), Center_Y, mt2-1
+            SetScale 1,1
+          Case 1 ' y
+            SetScale size1,size1
+            DrawImage blocks, Center_X, Center_Y+Tile_Rad*Cos(rotation), mt1-1
+            SetScale size2,size2
+            DrawImage blocks, Center_X, Center_Y-Tile_Rad*Cos(rotation), mt2-1
+            SetScale 1,1
+        EndSelect
+      EndIf
+  EndSelect
+
+EndFunction
diff --git a/samples/birdie/games/zombieblast/game.bmx b/samples/birdie/games/zombieblast/game.bmx
new file mode 100644 (file)
index 0000000..fa77c8f
--- /dev/null
@@ -0,0 +1,771 @@
+Strict
+'
+' Game Demo Coded By David Bird (Birdie)
+'
+Incbin "media/sand.png"
+Incbin "media/ship1.png"
+Incbin "media/cloud.png"
+Incbin "media/shot.png"
+Incbin "media/shot2.PNG"
+Incbin "media/mud.png"
+Incbin "media/smoke.png"
+Incbin "media/scan.png"
+Incbin "media/zombie_0.png"
+Incbin "media/zombie_1.png"
+Incbin "media/zombie_2.PNG"
+Incbin "media/zombie_3.PNG"
+Incbin "media/zombie_4.PNG"
+Incbin "media/zombie_5.PNG"
+Incbin "media/zombie_6.png"
+Incbin "media/zombie_7.PNG"
+Incbin "media/Title.png"
+Incbin "media/HitSpace.png"
+
+Global C_ScreenWidth# = 640, C_ScreenHeight# = 480
+Global C_ScreenMidX# =C_ScreenWidth/2
+Global C_ScreenMidY# =C_ScreenHeight/2
+Global MapPosition_X#=400, MapPosition_Y#=400
+Global WorldSize = 8192
+Global Scanner_Rot#
+Global Scanner_X#= C_ScreenWidth - 80
+Global Scanner_Y#= 80
+Global Scanner_Scale# = 0.5
+Global ObjectList:TList = New TList
+Global DetailList:TList = New TList
+Global CloudList:TList  = New TList
+Global ScanList:TList   = New TList
+
+Global TitleWidth#,TitleHeight#
+Graphics C_ScreenWidth, C_ScreenHeight ,32
+HideMouse
+AutoImageFlags MASKEDIMAGE|FILTEREDIMAGE|MIPMAPPEDIMAGE
+
+'media globals
+Global media_sand:TImage
+Global media_ship1:TImage
+Global media_cloud:TImage
+Global media_shots:TImage
+Global media_shot2:TImage
+Global media_mud:TImage
+Global media_smoke:TImage
+Global Media_scan:TImage
+Global media_Title:TImage
+Global media_HitSP:TImage
+
+Global Media_zombie:TImage[8]
+LoadMedia()
+
+Local P1:Player = New Player
+ObjectList.AddLast p1
+
+'title screen
+
+While Not KeyDown(KEY_SPACE)
+  Cls
+  SetBlend SOLIDBLEND
+  SetColor 255,255,255
+  TileImage Media_sand,MapPosition_X,MapPosition_Y
+  MapPosition_X:+1
+  SetRotation 0
+  SetBlend ALPHABLEND
+  SetColor 255,255,255
+  SetAlpha 1
+  SetScale TitleWidth,TitleHeight
+  DrawImage Media_Title,C_ScreenMidX,C_ScreenMidY-24
+  SetScale 1,1
+  SetAlpha 0.5
+  DrawImage media_HitSP, C_ScreenMidX, C_ScreenHeight - media_HitSP.height
+  Flip
+Wend
+
+Local a
+For a=0 Until 100
+  cloud.Create( Rnd(-WorldSize,WorldSize), Rnd(-WorldSize,WorldSize) )
+Next
+For a=0 Until 250
+  Baddie.Create(Rnd(-1000,1000), Rnd(-1000,1000), 0)
+Next
+
+While Not KeyDown(KEY_ESCAPE)
+  Cls
+  UpdateObjects()
+
+  DrawLevel(p1)
+  DrawObjects()
+  DrawScanner( P1 )
+
+  Flip
+Wend
+End
+
+Function LoadMedia()
+  SetHandle 0.5,0.5
+  AutoMidHandle True
+  media_sand  = LoadImage("incbin::media/sand.png")
+  media_ship1 = LoadImage("incbin::media/ship1.png")
+  media_cloud = LoadImage("incbin::media/cloud.png")
+  media_shots = LoadImage("incbin::media/shot.png")
+  media_shot2 = LoadImage("incbin::media/shot2.PNG")
+  media_scan  = LoadImage("incbin::media/scan.png")
+  media_mud   = LoadImage("incbin::media/mud.png")
+  media_smoke = LoadImage("incbin::media/smoke.png")
+  media_Title = LoadImage("incbin::media/Title.png")
+  media_HitSP = LoadImage("incbin::media/HitSpace.png")
+  
+  'scale to fullscreen
+
+  TitleWidth = media_title.width / C_ScreenWidth
+  TitleHeight= media_title.height / (C_ScreenHeight+48)
+  Media_zombie[0] = LoadAnimImage("incbin::media/zombie_0.png",32,64,0,17)
+  Media_zombie[1] = LoadAnimImage("incbin::media/zombie_1.png",32,64,0,17)
+  Media_zombie[2] = LoadAnimImage("incbin::media/zombie_2.PNG",32,64,0,17)
+  Media_zombie[3] = LoadAnimImage("incbin::media/zombie_3.PNG",32,64,0,17)
+  Media_zombie[4] = LoadAnimImage("incbin::media/zombie_4.PNG",32,64,0,17)
+  Media_zombie[5] = LoadAnimImage("incbin::media/zombie_5.PNG",32,64,0,17)
+  Media_zombie[6] = LoadAnimImage("incbin::media/zombie_6.png",32,64,0,17)
+  Media_zombie[7] = LoadAnimImage("incbin::media/zombie_7.PNG",32,64,0,17)
+
+EndFunction
+
+Function DrawLevel(o:Entity)
+  'using the object{o} position and direction to draw the map
+'  MapPosition_X = MapPosition_X + ((o.x - MapPosition_X)*0.25)
+'  MapPosition_Y = MapPosition_Y + ((o.y - MapPosition_Y)*0.25)
+  MapPosition_X = o.x
+  MapPosition_Y = o.y
+  SetBlend SOLIDBLEND
+  SetColor 255,255,255
+  SetScale 1,1
+  TileImage Media_sand,MapPosition_X,MapPosition_Y
+
+EndFunction
+
+Function UpdateObjects()
+  Local e:Entity
+  For e=EachIn ObjectList
+    e.Update()
+  Next
+EndFunction
+
+Function DrawObjects()
+  Local e:Entity
+  Local c:Cloud
+  For c=EachIn CloudList
+    c.Update()
+  Next
+
+  'Draw Shadows
+  For e=EachIn ObjectList
+    e.DrawShadow()
+  Next
+  'Draw Details
+  Local d:Detail
+  For d=EachIn DetailList
+    d.Update(MapPosition_X, MapPosition_Y)
+  Next
+
+
+  'Draw objects without shadows
+  For e=EachIn ObjectList
+    e.DrawBody()
+  Next
+
+  'DrawClouds
+
+  For c=EachIn CloudList
+    c.DrawShadow()
+  Next
+  For c=EachIn CloudList
+    c.DrawBody()
+  Next
+
+EndFunction
+
+Type Entity
+  Field x#,y#
+  Field height#
+  Field rotation#
+  Field spd#=1
+
+  Method Update() Abstract
+
+  Method DrawBody() Abstract
+  Method DrawShadow() Abstract
+EndType
+
+Type Player Extends Entity
+  Field RotationSpd#
+  Field liftSpd#
+  Field thrust#
+  Field osc#
+
+  Method Update()
+    If KeyDown(KEY_UP)
+      thrust:+0.01
+      If thrust>0.5
+        thrust = 0.5
+      EndIf
+    EndIf
+    If KeyDown(KEY_DOWN)
+      thrust:-0.05
+    EndIf
+    spd:+thrust
+
+    If thrust<0
+      thrust = 0
+    EndIf
+
+    If spd>8
+      spd=8
+    EndIf
+    If spd<0.5 spd = 0.5
+
+    If KeyHit(KEY_SPACE)
+      Local a,thei#
+      thei = height +(3.5*Cos(osc) )
+
+      Shots.Create x, y, spd+5, thei, rotation
+      For a=0 Until 3
+        Shots.Create x, y, spd+5, thei, rotation+Rnd(-1.75,1.75)
+      Next
+    EndIf
+    Local sz#=14*(1+(height/140.0))
+    Local sd#=16
+    Local cs#= Cos(rotation-90)
+    Local sn#= Sin(rotation-90)
+    Local ddx# = sz
+    Local ddy# = 9
+
+    Local tx1# = ddx*cs + ddy*sn
+    Local ty1# = ddx*sn - ddy*cs
+    ddx=-ddx
+    Local tx2# = ddx*cs + ddy*sn
+    Local ty2# = ddx*sn - ddy*cs
+
+    Local thei#
+    thei = height +(3.5*Cos(osc) )
+    Local deltasm#= ( 0.5 * (spd/8.0))
+    Trail.Create( x+tx1, y+ty1, thei, deltasm, rotation )
+    Trail.Create( x+tx2, y+ty2, thei, deltasm, rotation )
+
+    Local tx#= 20 * Cos(rotation)
+    Local ty#= 20 * Sin(rotation)
+    Local rd= 255*thrust*2
+    Local gn= rd*0.7
+    Local bl= gn*0.5
+    ColTrail.Create( x-tx, y-ty, thei, 0.3, rotation, [rd, gn, bl] ,2.0)
+
+    ColTrail.Create( x-tx, y-ty, thei, 0.3, rotation, [rd*2, 0, 0] ,1.0)
+
+    If KeyDown(KEY_RIGHT)
+      rotationSpd:+0.25
+      If rotationSpd>2
+        rotationSpd=2
+      EndIf
+    EndIf
+    If KeyDown(KEY_LEFT)
+      rotationSpd:-0.25
+      If rotationSpd<-2
+        rotationSpd=-2
+      EndIf
+    EndIf
+    rotation:+rotationSpd
+    rotationSpd:*0.95
+
+    If KeyDown(KEY_A)
+      liftSpd:-0.02
+      If liftSpd<-1
+        liftSpd=-1
+      EndIf
+    EndIf
+    If KeyDown(KEY_Z)
+      liftSpd:+0.02
+      If liftSpd>1
+        liftSpd=1
+      EndIf
+    EndIf
+    height:+liftSpd
+
+    liftspd:*0.985
+
+    If height<4
+      height = 4
+      liftspd = 0
+    EndIf
+    If height>50
+      height = 50
+      liftspd=0
+    EndIf
+    x=x+(spd*Cos(rotation))
+    y=y+(spd*Sin(rotation))
+    If x>WorldSize x=-WorldSize
+    If x<-WorldSize x=WorldSize
+    If y>WorldSize y=-WorldSize
+    If y<-WorldSize y=WorldSize
+    osc:+1
+  EndMethod
+
+  Method DrawShadow()
+    Local dx#,dy#,sz#,thei#
+    thei = height +(3.5*Cos(osc) )
+    sz =(0.002*thei)
+    SetRotation rotation+90
+    SetBlend ALPHABLEND
+    SetScale 0.25+sz,0.25+sz
+    SetColor 0,0,0
+    SetAlpha 0.5
+    DrawImage media_ship1,C_ScreenMidX + (x-MapPosition_X), C_ScreenMidY + ( y - MapPosition_Y )
+  EndMethod
+
+  Method DrawBody()
+    Local dx#,dy#,sz#,thei#
+    thei = height +(3.5*Cos(osc) )
+    sz =(0.002*thei)
+    SetAlpha 1
+    SetRotation rotation+90
+    SetBlend MASKBLEND
+    SetColor 255,255,255
+    dx=thei/3.0
+    dy=thei
+    SetScale 0.25+sz, 0.25+sz
+    DrawImage media_ship1,(x-MapPosition_X+dx) + C_ScreenMidX,(y-MapPosition_Y+dy) + C_ScreenMidY
+  EndMethod
+  Function Create:Player(x#,y#)
+    Local p:Player = New Player
+    p.x=x
+    p.y=y
+    p.height = 4
+    p.spd=1
+    ObjectList.AddFirst p
+    Return p
+  EndFunction
+EndType
+
+Type Cloud
+  Field x#,y#,height#, rotation
+
+  Method Update()
+    x:+1
+    y:+0.1
+    If x>WorldSize x=-WorldSize
+    If x<-WorldSize x=WorldSize
+    If y>WorldSize y=-WorldSize
+    If y<-WorldSize y=WorldSize
+  EndMethod
+
+  Method DrawBody()
+    Local dx#,dy#
+    dx=height/2.0
+    dy=height
+    SetBlend LIGHTBLEND
+    SetAlpha 1
+    SetScale 2.4,2.4
+    SetRotation rotation
+    SetColor 255,255,255
+    DrawImage media_cloud,(MapPosition_X+dx-x) + C_ScreenMidX,(MapPosition_Y+dy-y) + C_ScreenMidY
+  EndMethod
+
+  Method DrawShadow()
+    SetBlend ALPHABLEND
+    SetColor 0,0,0
+    SetAlpha 0.2
+    SetScale 4, 4
+    SetRotation rotation
+    DrawImage media_cloud,(MapPosition_X-x) + C_ScreenMidX,(MapPosition_Y-y) + C_ScreenMidY
+  EndMethod
+
+  Function Create:Cloud( x#, y# )
+    Local c:Cloud = New Cloud
+    c.x= x
+    c.y= y
+    c.rotation = Rnd(360)
+    c.height = 75
+    CloudList.AddLast c
+    Return c
+  EndFunction
+EndType
+
+Type Shots Extends Entity
+  Field life
+  Method DrawBody()
+    Local dx#,dy#
+    dx=height/3.0
+    dy=height
+    SetBlend MASKBLEND
+    SetColor 255,255,255
+    SetAlpha 1
+    SetScale 1, 1
+    SetRotation rotation + 90
+    DrawImage media_shots,(MapPosition_X+dx-x) + C_ScreenMidX,(MapPosition_Y+dy-y) + C_ScreenMidY
+  EndMethod
+
+  Method DrawShadow()
+    SetBlend ALPHABLEND
+    SetColor 0,0,0
+    SetAlpha 0.2
+    SetScale 1, 1
+    SetRotation rotation + 90
+    DrawImage media_shots,(MapPosition_X-x) + C_ScreenMidX,(MapPosition_Y-y) + C_ScreenMidY
+  EndMethod
+  Method Update()
+    x=x+(spd*Cos(rotation))
+    y=y+(spd*Sin(rotation))
+    If x>WorldSize x=-WorldSize
+    If x<-WorldSize x=WorldSize
+    If y>WorldSize y=-WorldSize
+    If y<-WorldSize y=WorldSize
+    If life<80
+      height:-0.75
+    EndIf
+    Trail.Create( x, y, height, 0.3, rotation )
+    If height<0
+      ObjectList.Remove Self
+      Mud.Create(x, y, rotation)
+      Local ee#
+      ee=1
+      SmokeEmitter.create( x#,y#, 0,ee, ee, ee )
+    Else
+      life:-1
+      If life<0
+        ObjectList.Remove Self
+      EndIf
+    EndIf
+  EndMethod
+
+  Function Create:Shots(x#,y#,spd#,hei#,rot#)
+    Local s:Shots = New Shots
+    s.x=x
+    s.y=y
+    s.rotation = rot
+    s.spd = spd
+    s.height = hei
+    s.life = 100
+    ObjectList.AddFirst s
+    Return s
+  EndFunction
+EndType
+
+Type Detail
+  Field life
+  Field x#,y#,rot#,alp#
+  Field col[3]
+
+  Method Update( wx#, wy# ) Abstract
+EndType
+
+Type Trail Extends Detail
+  Field height#
+  Field size#
+
+  Method Update( wx#, wy# )
+    Local dx#, dy#
+    alp:-0.005
+    If alp<0
+      life = 0
+    EndIf
+
+    life:-1
+    If life<0
+      DetailList.Remove Self
+    Else
+      dx=height/3.0
+      dy=height
+      SetAlpha alp
+      SetBlend alphablend
+      SetRotation rot
+      SetColor 255,255,255
+      size:+0.05
+      SetScale 1,size
+      DrawRect (wx-x+dx)+C_ScreenMidX,(wy-y+dy)+C_ScreenMidY,10,1
+    EndIf
+  EndMethod
+
+  Function Create:Trail(x#,y#,hei#,alp#,rot#)
+    Local t:Trail = New Trail
+    t.x=x
+    t.y=y
+    t.height= hei
+    t.alp = alp
+    t.rot = rot
+    t.life= 100
+    t.size= 1
+    DetailList.AddLast t
+  EndFunction
+EndType
+
+Type ColTrail Extends Detail
+  Field height#,size#
+
+  Method Update( wx#, wy# )
+    Local dx#, dy#
+    alp:-0.01
+    size:*0.9
+    If alp<0
+      life = 0
+    EndIf
+
+    life:-1
+    If life<0
+      DetailList.Remove Self
+    Else
+      dx=height/3.0
+      dy=height
+      SetAlpha alp
+      SetBlend LIGHTBLEND
+      SetRotation rot
+      SetColor Col[0],Col[1],Col[2]
+      SetScale size,size
+      DrawRect (wx-x+dx)+C_ScreenMidX,(wy-y+dy)+C_ScreenMidY,10,4
+    EndIf
+  EndMethod
+
+  Function Create:ColTrail(x#,y#,hei#,alp#,rot#,col[],size#)
+    Local t:ColTrail = New ColTrail
+    t.x=x
+    t.y=y
+    t.height= hei
+    t.alp = alp
+    t.rot = rot
+    t.life= 100
+    t.size=size
+    t.col = col
+    DetailList.AddLast t
+  EndFunction
+EndType
+
+Type Mud Extends Detail
+
+  Method Update( wx#, wy# )
+    SetRotation rot
+    SetBlend ALPHABLEND
+    If life<50
+      alp = Float(life)/100.0
+    EndIf
+    SetAlpha alp
+    SetColor 0,0,0
+    SetScale 0.5,0.5
+
+    DrawImage media_mud,(wx-x)+C_ScreenMidX,(wy-y)+C_ScreenMidY
+    life:-1
+    If life<0
+      DetailList.Remove Self
+    EndIf
+  EndMethod
+
+  Function Create:Mud(x#,y#, rot#)
+    Local m:Mud = New Mud
+    m.x = x
+    m.y = y
+    m.rot = rot
+    m.alp = 0.5
+    m.life = 200
+    DetailList.AddLast M
+  EndFunction
+EndType
+
+Type smoke_prt
+  Field x#,y#,height#  'local to emitter
+  Field scl#
+  Field alp#
+  Field dx#,dy#
+  Field life
+  Field rot#, rotdir#
+
+  Method Draw( tx#, ty# )
+    y:-dy
+    x:+dx
+    life:-1
+    alp:-0.005
+    scl:+0.017
+    If alp<=0
+      life =0
+      Return
+    EndIf
+    SetBlend LightBlend
+    SetAlpha alp
+    SetScale scl,scl
+    SetRotation rot
+    rot:+rotdir
+    DrawImage media_smoke, tx+x, ty+y
+  EndMethod
+
+  Function Create:smoke_prt(scl#,alp#,x#,y#,dx#,dy#,life)
+    Local s:Smoke_prt = New Smoke_prt
+    s.x=x
+    s.y=y
+    s.dx=dx
+    s.dy=dy
+    s.life=life
+    s.alp=alp
+    s.scl=scl
+    s.rotdir = Rnd(-4,4)
+    s.rot = Rnd(360)
+    Return s
+  EndFunction
+EndType
+
+Type SmokeEmitter Extends Detail
+  Field smlist:TList = New TList
+
+  Field rd#,gn#,bl#, max_cnt=50, cur_cnt
+
+  Method Update( wx#, wy# )
+    Local sp:smoke_prt
+    SetColor 255*rd,255*gn,255*bl
+    For sp=EachIn smlist
+      sp.Draw((wx-x)+C_ScreenMidX, (wy-y)+C_ScreenMidY)
+      If sp.life<0
+        'remove it and add another
+        smlist.remove sp
+        cur_cnt:-1
+      EndIf
+    Next
+    If cur_cnt<max_cnt
+      smlist.addfirst( smoke_prt.Create( 0.2, 0.3, 0, 0, Rnd( -0.1, 0.1 ), Rnd(0.1,1), 40 ) )
+      cur_cnt:+1
+    EndIf
+    life:-1
+    If life<0
+      DetailList.Remove Self
+      smlist.clear()
+    EndIf
+  EndMethod
+
+  Function Create:SmokeEmitter(x#,y#, rot#,cr#,cg#,cb#)
+    Local sm:SmokeEmitter = New SmokeEmitter
+    sm.x = x
+    sm.y = y
+    sm.rot = rot
+    sm.alp = 0.20
+    sm.life = 50
+    sm.rd=cr
+    sm.gn=cg
+    sm.bl=cb
+
+    DetailList.AddLast sm
+  EndFunction
+EndType
+
+Type Baddie Extends Entity
+  Field frame = 0
+  Field frm_p = 2
+  Field frm_t = 0
+  Field direct= 0
+  Field life
+
+  Method Update()
+    frm_t:+1
+    If frm_t>frm_p
+      frm_t= 0
+      frame:+1
+      If frame = 17 frame = 0
+    EndIf
+    x=x+(spd*Cos(rotation-90))
+    y=y+(spd*Sin(rotation-90))
+    If x>WorldSize x=-WorldSize
+    If x<-WorldSize x=WorldSize
+    If y>WorldSize y=-WorldSize
+    If y<-WorldSize y=WorldSize
+
+    spd=0.3
+    rotation:+1
+    If rotation<0 rotation:+360
+    If rotation>=360 rotation:-360
+    direct = rotation / 45
+  EndMethod
+  Method DrawShadow()
+    Local dx = -12
+    Local dy = -4
+    SetBlend alphaBlend
+    SetColor 0,0,0
+    SetAlpha 0.3
+    SetRotation -30
+    SetScale 0.43,0.47
+    DrawImage Media_zombie[direct],(MapPosition_X-x) + C_ScreenMidX+dx,(MapPosition_Y-y) + C_ScreenMidY+dy, frame
+
+  EndMethod
+  Method DrawBody()
+    SetBlend alphaBlend
+    SetColor 255,255,255
+    SetAlpha 1
+    SetRotation 0
+    SetScale 0.4,0.4
+    DrawImage Media_zombie[direct],(MapPosition_X-x) + C_ScreenMidX,(MapPosition_Y-y) + C_ScreenMidY, frame
+
+  EndMethod
+
+  Function Create:Baddie(x#,y#,spd#)
+    Local s:Baddie = New Baddie
+    s.x=x
+    s.y=y
+    s.rotation = Rand(350)
+    s.spd = Rnd(1,2)
+    s.height = 0
+    s.life = 100
+    ObjectList.AddFirst s
+    Return s
+  EndFunction
+
+EndType
+
+Type Scan_Object
+  Field alp#,x#,y#,typ
+  Method Update(cx#, cy#)
+    alp:-0.01
+    If alp<0
+      ScanList.Remove Self
+    Else
+      SetAlpha alp
+      DrawRect cx+x,cy+y,5,5
+    EndIf
+  EndMethod
+  Function Create:Scan_Object(x#, y#, typ )
+    Local so:Scan_Object = New Scan_Object
+    so.x=x
+    so.y=y
+    so.typ=typ
+    so.alp=0.4
+    ScanList.AddLast so
+  EndFunction
+EndType
+
+Function DrawScanner(p:Player) 'according to a certain player
+  SetBlend LightBlend
+  SetColor 255,255,255
+  SetAlpha 0.5
+  SetRotation Scanner_Rot+90
+  Scanner_rot:-5
+  If scanner_rot<0 scanner_rot:+360
+
+  SetScale Scanner_Scale,Scanner_Scale
+  DrawImage media_scan,Scanner_X,Scanner_Y
+  Local b:Baddie
+  Local so:Scan_Object
+  Local dx#,dy#,ang#,ln#
+
+  For b=EachIn ObjectList
+    'get angle to object
+    dx=p.x-b.x
+    dy=p.y-b.y
+    ln=Sqr(dx*dx+dy*dy)
+    If ln<1200
+      ang = ATan2(dx,dy)
+      If ang<0 ang=360+ang
+      If Abs(ang-(Scanner_rot))<2
+        'add a new dot on the scanner
+        Scan_Object.Create(dx/20.0, dy/20.0, 0 )
+      EndIf
+    EndIf
+  Next
+  SetBlend LightBlend
+  SetAlpha 0.25
+  SetColor 48,64,48
+  SetRotation 0
+  DrawRect Scanner_X-64,Scanner_Y-64,256,256
+  SetColor 0,255,0
+  For so=EachIn ScanList
+    so.Update(scanner_x,Scanner_Y)
+  Next
+EndFunction
+
+
diff --git a/samples/birdie/games/zombieblast/media/HitSpace.png b/samples/birdie/games/zombieblast/media/HitSpace.png
new file mode 100644 (file)
index 0000000..9040371
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/HitSpace.png differ
diff --git a/samples/birdie/games/zombieblast/media/Title.png b/samples/birdie/games/zombieblast/media/Title.png
new file mode 100644 (file)
index 0000000..9d9e92a
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/Title.png differ
diff --git a/samples/birdie/games/zombieblast/media/cloud.png b/samples/birdie/games/zombieblast/media/cloud.png
new file mode 100644 (file)
index 0000000..b720fb6
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/cloud.png differ
diff --git a/samples/birdie/games/zombieblast/media/mud.png b/samples/birdie/games/zombieblast/media/mud.png
new file mode 100644 (file)
index 0000000..7f99f91
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/mud.png differ
diff --git a/samples/birdie/games/zombieblast/media/sand.png b/samples/birdie/games/zombieblast/media/sand.png
new file mode 100644 (file)
index 0000000..8b293cf
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/sand.png differ
diff --git a/samples/birdie/games/zombieblast/media/scan.png b/samples/birdie/games/zombieblast/media/scan.png
new file mode 100644 (file)
index 0000000..ccbc483
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/scan.png differ
diff --git a/samples/birdie/games/zombieblast/media/ship1.png b/samples/birdie/games/zombieblast/media/ship1.png
new file mode 100644 (file)
index 0000000..088788a
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/ship1.png differ
diff --git a/samples/birdie/games/zombieblast/media/shot.png b/samples/birdie/games/zombieblast/media/shot.png
new file mode 100644 (file)
index 0000000..099ee8d
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/shot.png differ
diff --git a/samples/birdie/games/zombieblast/media/shot2.PNG b/samples/birdie/games/zombieblast/media/shot2.PNG
new file mode 100644 (file)
index 0000000..e795a3b
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/shot2.PNG differ
diff --git a/samples/birdie/games/zombieblast/media/smoke.png b/samples/birdie/games/zombieblast/media/smoke.png
new file mode 100644 (file)
index 0000000..feee4ed
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/smoke.png differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_0.png b/samples/birdie/games/zombieblast/media/zombie_0.png
new file mode 100644 (file)
index 0000000..a12a458
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_0.png differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_1.png b/samples/birdie/games/zombieblast/media/zombie_1.png
new file mode 100644 (file)
index 0000000..1dcfee6
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_1.png differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_2.PNG b/samples/birdie/games/zombieblast/media/zombie_2.PNG
new file mode 100644 (file)
index 0000000..3a9c2e1
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_2.PNG differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_3.PNG b/samples/birdie/games/zombieblast/media/zombie_3.PNG
new file mode 100644 (file)
index 0000000..ff158a0
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_3.PNG differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_4.PNG b/samples/birdie/games/zombieblast/media/zombie_4.PNG
new file mode 100644 (file)
index 0000000..63458de
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_4.PNG differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_5.PNG b/samples/birdie/games/zombieblast/media/zombie_5.PNG
new file mode 100644 (file)
index 0000000..e16fa17
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_5.PNG differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_6.png b/samples/birdie/games/zombieblast/media/zombie_6.png
new file mode 100644 (file)
index 0000000..7877b24
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_6.png differ
diff --git a/samples/birdie/games/zombieblast/media/zombie_7.PNG b/samples/birdie/games/zombieblast/media/zombie_7.PNG
new file mode 100644 (file)
index 0000000..944dddc
Binary files /dev/null and b/samples/birdie/games/zombieblast/media/zombie_7.PNG differ
diff --git a/samples/birdie/misc/filmclip/main.bmx b/samples/birdie/misc/filmclip/main.bmx
new file mode 100644 (file)
index 0000000..6dc2e1d
--- /dev/null
@@ -0,0 +1,56 @@
+
+
+Graphics 640,480,32
+
+AutoMidHandle True
+Global BMX01IMG:TImage = LoadImage("media/B-Max.png",FILTEREDIMAGE|DYNAMICIMAGE)
+ConvertToBW BMX01IMG,0
+Global FLM01IMG:TImage = LoadAnimImage("media/flmstp.png",126,66,0,10)
+
+While Not KeyDown(KEY_ESCAPE)
+  Cls
+
+  SetColor 255,255,255
+  SetBlend ALPHABLEND          
+  SetScale 1,1
+  SetAlpha Rnd(0.75,0.95)
+  DrawImage bmx01img,320+Rnd(-1,1),240+Rnd(-1,1),0
+  If Rand(40)=5
+    SetColor 128,128,128
+    SetBlend addativeBlend
+    x=Rnd(640)
+    DrawLine x,0,x+Rnd(-5,5),Rnd(400,480)
+    EndIf
+  SetBlend MASKBLEND
+  SetColor 255,255,255
+  SetScale 6.5,7.5
+  DrawImage FLM01IMG,320,240,a
+  a:+1
+  a=a Mod 10
+  Flip
+Wend
+
+
+Function ConvertToBW(i:TImage,frame)
+  Local col,a,r,g,b,cc,x=0,y=0
+  Local pix:TPixmap
+  
+  pix=LockImage(i,frame)
+  While y<i.height
+    x=0
+    While x<i.width
+      col = ReadPixel( pix, x, y )
+      a = ( col & $ff000000)
+      r = ( col & $ff0000 ) Shr 16
+      g = ( col & $ff00 ) Shr 8
+      b = ( col & $ff )
+      cc= (r+g+b)/3
+      col = a | (cc Shl 16) | (cc Shl 8) | cc
+      WritePixel( pix, x, y, col )
+      x=x+1
+    Wend
+    y=y+1
+  Wend
+  UnlockImage i,frame
+EndFunction
+
diff --git a/samples/birdie/misc/filmclip/media/B-Max.png b/samples/birdie/misc/filmclip/media/B-Max.png
new file mode 100644 (file)
index 0000000..701db3d
Binary files /dev/null and b/samples/birdie/misc/filmclip/media/B-Max.png differ
diff --git a/samples/birdie/misc/filmclip/media/Thumbs.db b/samples/birdie/misc/filmclip/media/Thumbs.db
new file mode 100644 (file)
index 0000000..cb549c6
Binary files /dev/null and b/samples/birdie/misc/filmclip/media/Thumbs.db differ
diff --git a/samples/birdie/misc/filmclip/media/flmstp.png b/samples/birdie/misc/filmclip/media/flmstp.png
new file mode 100644 (file)
index 0000000..cb1d84d
Binary files /dev/null and b/samples/birdie/misc/filmclip/media/flmstp.png differ
diff --git a/samples/birdie/misc/glblur/glblurr.bmx b/samples/birdie/misc/glblur/glblurr.bmx
new file mode 100644 (file)
index 0000000..c9e488d
--- /dev/null
@@ -0,0 +1,282 @@
+Rem
+ NEHE OpenGL Lesson 36:  Radial Blur & Rendering To A Texture
+ converted to blitzmax by David Bird
+EndRem
+Strict
+
+'User Defined Variables
+Global C_WIDTH = 640
+Global C_HEIGHT= 480
+Global angle#                                           'Used To Rotate The Helix
+Global         vertexes#[4,3]     'Holds Float Info For 4 Sets Of Vertices
+Global normal#[3]         'An Array To Store The Normal Data
+Global         BlurTexture        'An Unsigned Int To Store The Texture Number
+Global tSize=256
+Const RAD_TO_DEG! =  57.2957795130823208767981548141052
+
+Function Cos_R!(rads!)
+  Return Cos(rads * RAD_TO_DEG)
+EndFunction
+
+Function Sin_R!(rads!)
+  Return Sin(rads * RAD_TO_DEG)
+EndFunction
+
+Function EmptyTexture()                                                                                        ' Create An Empty Texture
+       Local txtnumber                                                                                 ' Texture ID
+       Local data[tSize*tSize*4]
+       glGenTextures(1, Varptr txtnumber )                                                             ' Create 1 Texture
+       glBindTexture(GL_TEXTURE_2D, txtnumber)                                 ' Bind The Texture
+       glTexImage2D(GL_TEXTURE_2D, 0, 4, 128, 128, 0,..
+               GL_RGBA, GL_UNSIGNED_BYTE, data)                                                ' Build Texture Using Information In data
+       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
+       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
+       Return txtnumber                                                                                        ' Return The Texture ID
+EndFunction
+
+Function ReduceToUnit(vector:Float Ptr)                                                                ' Reduces A Normal Vector (3 Coordinates)
+       Local length#
+       ' Calculates The Length Of The Vector
+       length = Sqr((vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2]))
+       If length = 0.0 length=1.0                                              ' Prevents Divide By 0 Error By Providing
+
+       vector[0]:/ length                                                                              ' Dividing Each Element By
+       vector[1]:/ length                                                                              ' The Length Results In A
+       vector[2]:/ length                                                                              ' Unit Normal Vector.
+End Function
+
+Function ProcessHelix()                                                                                                ' Draws A Helix
+  Local a
+       Local x#                                                                                                        ' Helix x Coordinate
+       Local y#                                                                                                        ' Helix y Coordinate
+       Local z#                                                                                                        ' Helix z Coordinate
+       Local phi#                                                                                              ' Angle
+       Local theta#                                                                                    ' Angle
+       Local v#,u#                                                                                             ' Angles
+       Local r#                                                                                                        ' Radius Of Twist
+       Local twists = 5                                                                                                ' 5 Twists
+       Local glfMaterialColor#[]=[0.4#,0.2#,0.8#,1.0#]                 ' Set The Material Color
+       Local specular#[]=[1.0#,1.0#,1.0#,1.0#]                                 ' Sets Up Specular Lighting
+  Local tv1#[3],tv2#[3]
+
+       glLoadIdentity()                                                                                        ' Reset The Modelview Matrix
+       gluLookAt(0, 5, 50, 0, 0, 0, 0, 1, 0)                                           ' Eye Position (0,5,50) Center Of Scene (0,0,0), Up On Y Axis
+
+       glPushMatrix()                                                                                          ' Push The Modelview Matrix
+
+       glTranslatef(0,0,-50)                                                                           ' Translate 50 Units Into The Screen
+       glRotatef(angle/2.0,1,0,0)                                                              ' Rotate By angle/2 On The X-Axis
+       glRotatef(angle/3.0,0,1,0)                                                              ' Rotate By angle/3 On The Y-Axis
+  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,glfMaterialColor)
+       glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular)
+
+       r=1.5                                                                                                           ' Radius
+
+       glBegin(GL_QUADS)                                                                                       ' Begin Drawing Quads
+       For phi=0 Until 360 Step 20.0                                                   ' 360 Degrees In Steps Of 20
+               For theta=0 Until (360*twists) Step 20.0        ' 360 Degrees * Number Of Twists In Steps Of 20
+                       v=(phi/180.0*3.142)                                                             ' Calculate Angle Of First Point        (  0 )
+                       u=(theta/180.0*3.142)                                                   ' Calculate Angle Of First Point        (  0 )
+
+                       x=(cos_r(u)*(2.0+cos_r(v) ))*r                                  ' Calculate x Position (1st Point)
+                       y=(sin_r(u)*(2.0+cos_r(v) ))*r                                  ' Calculate y Position (1st Point)
+                       z=((( u-(2.0*3.142)) + sin_r(v) )* r)           ' Calculate z Position (1st Point)
+
+                       vertexes[0,0]=x                                                                 ' Set x Value Of First Vertex
+                       vertexes[0,1]=y                                                                 ' Set y Value Of First Vertex
+                       vertexes[0,2]=z                                                                 ' Set z Value Of First Vertex
+
+                       v=(phi/180.0*3.142)                                                             ' Calculate Angle Of Second Point       (  0 )
+                       u=((theta+20)/180.0*3.142)                                              ' Calculate Angle Of Second Point       ( 20 )
+
+                       x=(cos_r(u)*(2.0+cos_r(v) ))*r                                  ' Calculate x Position (2nd Point)
+                       y=(sin_r(u)*(2.0+cos_r(v) ))*r                                  ' Calculate y Position (2nd Point)
+                       z=((( u-(2.0*3.142)) + sin_r(v) ) * r)          ' Calculate z Position (2nd Point)
+
+                       vertexes[1,0]=x                                                                 ' Set x Value Of Second Vertex
+                       vertexes[1,1]=y                                                                 ' Set y Value Of Second Vertex
+                       vertexes[1,2]=z                                                                 ' Set z Value Of Second Vertex
+
+                       v=((phi+20)/180.0*3.142)                                                        ' Calculate Angle Of Third Point        ( 20 )
+                       u=((theta+20)/180.0*3.142)                                              ' Calculate Angle Of Third Point        ( 20 )
+
+                       x=(cos_r(u)*(2.0+cos_r(v) ))*r                                  ' Calculate x Position (3rd Point)
+                       y=(sin_r(u)*(2.0+cos_r(v) ))*r                                  ' Calculate y Position (3rd Point)
+                       z=((( u-(2.0*3.142)) + sin_r(v) ) * r)          ' Calculate z Position (3rd Point)
+
+                       vertexes[2,0]=x                                                                 ' Set x Value Of Third Vertex
+                       vertexes[2,1]=y                                                                 ' Set y Value Of Third Vertex
+                       vertexes[2,2]=z                                                                 ' Set z Value Of Third Vertex
+
+                       v=((phi+20)/180.0*3.142)                                                        ' Calculate Angle Of Fourth Point       ( 20 )
+                       u=((theta)/180.0*3.142)                                                 ' Calculate Angle Of Fourth Point       (  0 )
+
+                       x=Float(cos_r(u)*(2.0+cos_r(v) ))*r                                     ' Calculate x Position (4th Point)
+                       y=Float(sin_r(u)*(2.0+cos_r(v) ))*r                                     ' Calculate y Position (4th Point)
+                       z=Float((( u-(2.0*3.142)) + sin_r(v) ) * r)             ' Calculate z Position (4th Point)
+
+                       vertexes[3,0]=x                                                                 ' Set x Value Of Fourth Vertex
+                       vertexes[3,1]=y                                                                 ' Set y Value Of Fourth Vertex
+                       vertexes[3,2]=z                                                                 ' Set z Value Of Fourth Vertex
+
+      For a=0 Until 3
+       ' Calculate The Vector From Point 1 To Point 0
+       tv1[a] = vertexes[0,a] - vertexes[1,a]                                                                  ' Vector 1.x=Vertex[0].x-Vertex[1].x
+         tv2[a] = vertexes[1,a] - vertexes[2,a]                                                                        ' Vector 2.x=Vertex[0].x-Vertex[1].x
+        ' Compute The Cross Product To Give Us A Surface Normal
+      Next
+      normal[0] = tv1[1]*tv2[2] - tv1[2]*tv2[1]
+      normal[1] = tv1[2]*tv2[0] - tv1[0]*tv2[2]
+      normal[2] = tv1[0]*tv2[1] - tv1[1]*tv2[0]
+       ReduceToUnit(normal)                                                                                    ' Normalize The Vectors
+
+       glNormal3f(normal[0],normal[1],normal[2])                       ' Set The Normal
+
+                       ' Render The Quad
+                       glVertex3f(vertexes[0,0],vertexes[0,1],vertexes[0,2])
+                       glVertex3f(vertexes[1,0],vertexes[1,1],vertexes[1,2])
+                       glVertex3f(vertexes[2,0],vertexes[2,1],vertexes[2,2])
+                       glVertex3f(vertexes[3,0],vertexes[3,1],vertexes[3,2])
+               Next
+       Next
+       glEnd()                                                                                                 ' Done Rendering Quads
+
+       glPopMatrix()                                                                                           ' Pop The Matrix
+EndFunction
+
+Function ViewOrtho()                                                                                           ' Set Up An Ortho View
+       glMatrixMode(GL_PROJECTION)                                                             ' Select Projection
+       glPushMatrix()                                                                                          ' Push The Matrix
+       glLoadIdentity()                                                                                        ' Reset The Matrix
+       glOrtho( 0, C_WIDTH ,C_HEIGHT , 0, -10, 10 )                                                    ' Select Ortho Mode (640x480)
+       glMatrixMode(GL_MODELVIEW)                                                                      ' Select Modelview Matrix
+       glPushMatrix()                                                                                          ' Push The Matrix
+       glLoadIdentity()                                                                                        ' Reset The Matrix
+EndFunction
+
+Function ViewPerspective()                                                                                     ' Set Up A Perspective View
+       glMatrixMode( GL_PROJECTION )                                                           ' Select Projection
+       glPopMatrix()                                                                                           ' Pop The Matrix
+       glMatrixMode( GL_MODELVIEW )                                                            ' Select Modelview
+       glPopMatrix()                                                                                           ' Pop The Matrix
+EndFunction
+
+Function RenderToTexture()                                                                                     ' Renders To A Texture
+       glViewport(0,0,tSize,tSize)                                                                     ' Set Our Viewport (Match Texture Size)
+       ProcessHelix()                                                                                          ' Render The Helix
+
+       glBindTexture(GL_TEXTURE_2D,BlurTexture)                                        ' Bind To The Blur Texture
+       ' Copy Our ViewPort To The Blur Texture (From 0,0 To 128,128... No Border)
+       glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 0, 0, tSize, tSize, 0)
+       glClearColor(0.0, 0.0, 0.25, 0.5)                                               ' Set The Clear Color To Medium Blue
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)                      ' Clear The Screen And Depth Buffer
+       glViewport(0 , 0,C_WIDTH ,C_HEIGHT)                                                                     ' Set Viewport (0,0 to 640x480)
+EndFunction
+
+Function DrawBlur(times, inc#)                                                         ' Draw The Blurred Image
+  Local num
+       Local spost# = 0.0                                                                                      ' Starting Texture Coordinate Offset
+  Local alphainc# = 0.9 / Float(times)                                                         ' Fade Speed For Alpha Blending
+       Local alpha# = 0.1                                                                                      ' Starting Alpha Value
+
+       ' Disable AutoTexture Coordinates
+       glDisable(GL_TEXTURE_GEN_S)
+       glDisable(GL_TEXTURE_GEN_T)
+
+       glEnable(GL_TEXTURE_2D)                                                                 ' Enable 2D Texture Mapping
+       glDisable(GL_DEPTH_TEST)                                                                        ' Disable Depth Testing
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE)                                                        ' Set Blending Mode
+       glEnable(GL_BLEND)                                                                                      ' Enable Blending
+       glBindTexture(GL_TEXTURE_2D,BlurTexture)                                        ' Bind To The Blur Texture
+       ViewOrtho()                                                                                             ' Switch To An Ortho View
+  alphainc = alpha / times                                                                     ' alphainc=0.2f / Times To Render Blur
+
+       glBegin(GL_QUADS)                                                                                       ' Begin Drawing Quads
+               For num = 0 Until  times                                                ' Number Of Times To Render Blur
+                       glColor4f(1.0, 1.0, 1.0, alpha)                                 ' Set The Alpha Value (Starts At 0.2)
+                       glTexCoord2f(0+spost,1-spost)                                           ' Texture Coordinate    ( 0, 1 )
+                       glVertex2f(0,0)                                                                 ' First Vertex          (   0,   0 )
+
+                       glTexCoord2f(0+spost,0+spost)                                           ' Texture Coordinate    ( 0, 0 )
+                       glVertex2f(0,C_HEIGHT)                                                                  ' Second Vertex (   0, 480 )
+
+                       glTexCoord2f(1-spost,0+spost)                                           ' Texture Coordinate    ( 1, 0 )
+                       glVertex2f(C_WIDTH,C_HEIGHT)                                                            ' Third Vertex          ( C_WIDTH, 480 )
+
+                       glTexCoord2f(1-spost,1-spost)                                           ' Texture Coordinate    ( 1, 1 )
+                       glVertex2f(C_WIDTH,0)                                                                   ' Fourth Vertex ( C_WIDTH,   0 )
+
+                       spost:+ inc                                                                             ' Gradually Increase spost (Zooming Closer To Texture Center)
+                       alpha = alpha - alphainc                                                        ' Gradually Decrease alpha (Gradually Fading Image Out)
+               Next
+       glEnd()                                                                                                 ' Done Drawing Quads
+
+       ViewPerspective()                                                                                       ' Switch To A Perspective View
+
+       glEnable(GL_DEPTH_TEST)                                                                 ' Enable Depth Testing
+       glDisable(GL_TEXTURE_2D)                                                                        ' Disable 2D Texture Mapping
+       glDisable(GL_BLEND)                                                                             ' Disable Blending
+
+
+       glBindTexture(GL_TEXTURE_2D,0)                                                          ' Unbind The Blur Texture
+EndFunction
+
+Function Initialize ()
+       ' Start Of User Initialization
+       angle           = 0.0                                                                                   ' Set Starting Angle To Zero
+       BlurTexture = EmptyTexture()                                                            ' Create Our Empty Texture
+       glViewport(0 , 0,C_WIDTH ,C_HEIGHT)     ' Set Up A Viewport
+       glMatrixMode(GL_PROJECTION)                                                             ' Select The Projection Matrix
+       glLoadIdentity()                                                                                        ' Reset The Projection Matrix
+       gluPerspective(50, Float(C_WIDTH)/Float(C_HEIGHT), 5,  2000) ' Set Our Perspective
+       glMatrixMode(GL_MODELVIEW)                                                                      ' Select The Modelview Matrix
+       glLoadIdentity()                                                                                        ' Reset The Modelview Matrix
+       glEnable(GL_DEPTH_TEST)                                                                 ' Enable Depth Testing
+
+       Local global_ambient#[]=[0.2#, 0.2#,  0.2#, 1.0#]               ' Set Ambient Lighting To Fairly Dark Light (No Color)
+       Local light0pos#[]=     [0.0#, 5.0#, 10.0#, 1.0#]               ' Set The Light Position
+       Local light0ambient#[]= [0.2#, 0.2#,  0.2#, 1.0#]               ' More Ambient Light
+       Local light0diffuse#[]= [0.3#, 0.3#,  0.3#, 1.0#]               ' Set The Diffuse Light A Bit Brighter
+       Local light0specular#[]=[0.8#, 0.8#,  0.8#, 1.0#]               ' Fairly Bright Specular Lighting
+
+       Local lmodel_ambient#[]=[ 0.2#,0.2#,0.2#,1.0#]                  ' And More Ambient Light
+       glLightModelfv(GL_LIGHT_MODEL_AMBIENT,lmodel_ambient)           ' Set The Ambient Light Model
+
+       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient)          ' Set The Global Ambient Light Model
+       glLightfv(GL_LIGHT0, GL_POSITION, light0pos)                            ' Set The Lights Position
+       glLightfv(GL_LIGHT0, GL_AMBIENT, light0ambient)                 ' Set The Ambient Light
+       glLightfv(GL_LIGHT0, GL_DIFFUSE, light0diffuse)                 ' Set The Diffuse Light
+       glLightfv(GL_LIGHT0, GL_SPECULAR, light0specular)                       ' Set Up Specular Lighting
+       glEnable(GL_LIGHTING)                                                                           ' Enable Lighting
+       glEnable(GL_LIGHT0)                                                                             ' Enable Light0
+       glShadeModel(GL_SMOOTH)                                                                 ' Select Smooth Shading
+       glMateriali(GL_FRONT, GL_SHININESS, 128)
+       glClearColor(0.0, 0.0, 0.0, 0.5)                                                ' Set The Clear Color To Black
+       Return 1                                                                                                ' Return TRUE (Initialization Successful)
+EndFunction
+
+Function Update(milliseconds#)                                                         ' Perform Motion Updates Here
+       If KeyDown(KEY_ESCAPE) End
+       angle:+(milliseconds/5.0)                                               ' Update angle Based On The Clock
+EndFunction
+
+Function Draw()                                                                                                ' Draw The Scene
+       glClearColor(0.0, 0.0, 0.0, 0.25)                                               ' Set The Clear Color To Black
+       glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)             ' Clear Screen And Depth Buffer
+       glLoadIdentity()                                                                                        ' Reset The View
+
+       RenderToTexture()                                                                                       ' Render To A Texture
+       ProcessHelix()                                                                                          ' Draw Our Helix
+       DrawBlur(25,.02)                                                                                        ' Draw The Blur Effect
+       glFlush ()                                                                                                      ' Flush The GL Rendering Pipeline
+EndFunction
+
+GLGraphics C_WIDTH,C_HEIGHT,32
+
+Initialize()
+
+Repeat
+    Update(25)
+    Draw()
+       Flip
+Forever
diff --git a/samples/birdie/misc/lightImage/main.bmx b/samples/birdie/misc/lightImage/main.bmx
new file mode 100644 (file)
index 0000000..2abcb9c
--- /dev/null
@@ -0,0 +1,67 @@
+'
+' Using Lightblend/image as a light
+'
+Strict
+
+'Include media in the final file
+Incbin "media/fl.png"
+Incbin "media/light.png"
+Incbin "media/B-Max.png"
+
+'set the graphics mode
+Graphics 640, 480, 32
+
+'Hide the pointer
+HideMouse
+
+'All images will be handled from the center
+AutoMidHandle True
+
+'Load images in now. incbin points the file to the included images
+Global backImage:TImage = LoadImage("incbin::media/fl.png")
+Global logoImage:TImage = LoadImage("incbin::media/B-Max.png")
+Global lightImage:TImage = LoadImage("incbin::media/light.png")
+
+'setup some vars now
+Local x#, y#, tim#
+Local mx, my
+Local lightcolor[] = [255,255,255]
+Local BackColor[]  = [128,128,128]
+
+'Main Loop
+While Not KeyDown(KEY_ESCAPE)
+  x:+5*Sin(tim)
+  y:+1
+  tim:+4
+  mx = MouseX()
+  my = MouseY()
+
+  'draw the backgound
+  SetScale 1,1
+  SetColor BackColor[0],BackColor[1],BackColor[2]
+  TileImage backImage,x,y
+
+  'draw the logo
+  SetBlend MaskBlend
+  SetColor 0,0,0
+  DrawImage logoimage,340,260
+  SetColor 100,100,100
+  DrawImage logoimage,320,240
+
+  'Draw the light
+  SetBlend LightBlend
+  SetColor LightColor[0],LightColor[1],LightColor[2]
+  SetScale 1.5+1*Cos(tim), 1.5+1*Cos(tim)
+  DrawImage lightimage, mx, my
+  
+  'draw the mousepointer
+  SetBlend SolidBlend
+  SetColor 255,255,255
+  SetScale 1,1
+  DrawLine mx-5,my,mx+5,my
+  DrawLine mx,my-5,mx,my+5
+  Flip
+Wend
+
+End
+
diff --git a/samples/birdie/misc/lightImage/media/B-Max.png b/samples/birdie/misc/lightImage/media/B-Max.png
new file mode 100644 (file)
index 0000000..701db3d
Binary files /dev/null and b/samples/birdie/misc/lightImage/media/B-Max.png differ
diff --git a/samples/birdie/misc/lightImage/media/fl.png b/samples/birdie/misc/lightImage/media/fl.png
new file mode 100644 (file)
index 0000000..3e60171
Binary files /dev/null and b/samples/birdie/misc/lightImage/media/fl.png differ
diff --git a/samples/birdie/misc/lightImage/media/light.png b/samples/birdie/misc/lightImage/media/light.png
new file mode 100644 (file)
index 0000000..b0949d6
Binary files /dev/null and b/samples/birdie/misc/lightImage/media/light.png differ
diff --git a/samples/breakout/breakout.bmx b/samples/breakout/breakout.bmx
new file mode 100644 (file)
index 0000000..719b2eb
--- /dev/null
@@ -0,0 +1,334 @@
+
+Strict
+
+Const WIDTH = 640,HEIGHT = 480, DEPTH = 32
+Const ShadowOn   = 1
+Const ShadowSize = 10
+
+Global gtime
+Global Pipes_img:TImage
+Global Tiles_img:TImage
+Global logo_img:TImage
+Global paddle:TImage
+Global ballvis:TImage
+'Setup the level
+Global Tilelist:TList
+Global Balllist:TList
+Global playerX#,PlayerY#
+Global Score
+
+Private
+  Global ballcount=0
+
+  Function Minf#(a#,b#)
+    If a<b Return a
+    Return b
+  EndFunction
+  Function Maxf#(a#,b#)
+    If a>b Return a
+    Return b
+  EndFunction
+Public
+
+Type ball
+  Field x#,y#
+  Field dx#,dy#,spd#,rot#=0
+
+  Field visual
+
+  Method Update()
+    x:+ (dx * spd)
+    y:+ (dy * spd)
+    If x<34 Or x>606
+      dx=-dx
+    EndIf
+    If y<50
+      dy=-dy
+    EndIf
+    If y>Height-8
+      ballcount:-1
+      BallList.Remove(Self)
+    Else
+      If dy>0
+        If y>playery-8
+          If x>playerx-32 And x<playerx+32
+            dy=dy*-1
+          EndIf
+        EndIf
+      EndIf
+      rot:+10
+    EndIf
+  EndMethod
+
+  Method Draw(offx,offy)
+    SetRotation rot
+    DrawImage ballvis,x+offx,y+offy
+    SetRotation 0
+  EndMethod
+
+  Function Create:Ball(x=Width/2 , y=Height/2)
+    Local b:Ball = New Ball
+    ballcount:+1
+    b.x = x
+    b.y = y
+    b.dx = Rnd(-2, 2)
+    b.dy = Rnd(-2, 2)
+    b.spd = 4'0.1
+    Return b
+  EndFunction
+EndType
+
+'all tiles are a standard size so
+Type Tile
+  Field x#,y#
+  Field typ = 0
+  Field state = 0
+  Field rot#=0,size#=1
+
+  Method Draw(offx,offy)
+    Select state
+      Case 0
+        SetRotation rot
+        If size>1
+          SetScale size,size
+          size=size*0.9
+        Else
+          size = 1
+          SetScale 0.95+(0.05*Cos(gTime)),0.95+(0.05*Sin(gTime))
+        EndIf
+      Case 1
+        SetRotation rot
+        SetScale size,size
+    EndSelect
+    Select typ
+      Case 0
+        DrawImage tiles_img,x+offx,y+offy+(2*Sin(gtime)),0
+      Case 1
+        DrawImage tiles_img,x+offx,y+offy+(2*Sin(gtime)),1
+      Case 2
+        DrawImage tiles_img,x+offx,y+offy+(2*Sin(gtime)),2
+      Case 3
+        DrawImage tiles_img,x+offx,y+offy+(2*Sin(gtime)),3
+      Case 4
+        DrawImage tiles_img,x+offx,y+offy+(2*Sin(gtime)),4
+    EndSelect
+
+    SetScale 1,1
+    SetRotation 0
+  EndMethod
+
+  Method Update()
+    Local c
+    Local b:Ball
+    If state = 0
+      'Check this tile for collision with all of the balls
+      For b=EachIn BallList
+        If b.x>x-4 And b.x<x+24
+          If b.y>y-4 And b.y<y+24
+            b.dy=-b.dy
+            Select typ
+              Case 1
+                If ballcount=1
+                  For c=0 Until 2
+                    BallList.AddLast(ball.Create(b.x,b.y))
+                  Next
+                EndIf
+                state = 1
+                size = 1
+              Case 2
+                typ = 3
+                size=1.5
+              Case 3
+                typ = 4
+                size=1.5
+              Default
+                Score:+((1+typ)*100)
+                state = 1
+            EndSelect
+            Return
+          EndIf
+        EndIf
+      Next
+    Else
+      y:+4
+      rot:+5
+      size:-.005
+      If y>HEIGHT
+        BallList.Remove(b)
+      EndIf
+    EndIf
+  EndMethod
+
+
+  Function Create:Tile(x=0,y=0,typ=0)
+    Local t:Tile = New Tile
+      t.x=x
+      t.y=y
+      t.typ = typ
+      Return t
+  EndFunction
+EndType
+
+Graphics WIDTH,HEIGHT,DEPTH
+
+AutoMidHandle True
+
+'Media
+Global back:TImage[2]
+back[0] = LoadImage("media\back1.png")
+back[1] = LoadImage("media\back2.png")
+Pipes_img=LoadAnimImage("media\pipes.png",32,32,0,4)
+Tiles_img=LoadAnimImage("media\tiles.png",32,20,0,5)
+paddle = LoadImage("media\paddle.png")
+ballvis = LoadImage("media\ball.png")
+logo_img=LoadImage("media\B-Max.png")
+
+
+Tilelist:TList = New TList
+Balllist:TList = New TList
+playerX# = Width/2
+PlayerY# = Height-40
+Score=0
+
+ResetGame()
+
+
+
+HideMouse
+While Not KeyDown(KEY_ESCAPE)
+
+       'Update Players Position
+       playerx = minf(574,maxf(64,MouseX()))
+       'Update Balls
+       UpdateBalls()
+       'Update Tiles
+       UpdateTiles()
+       'Draw Level
+       DrawLevel()
+
+       gTime:+10
+
+       SetAlpha .75
+       SetColor 0,0,255
+       DrawRect 0,0,Width,20
+
+       SetBlend ALPHABLEND
+
+       SetAlpha 0.5
+       SetColor 0,0,0
+       DrawText "Score:"+Score,4,4
+
+       SetAlpha 1
+       SetColor 255,255,255
+       DrawText "Score:"+Score+" "+ballcount,2,2
+
+       Flip
+Wend
+
+End
+
+
+Function DrawLevel()
+  Local w,aa#
+  TileImage back[1],0,gTime/20
+  SetBlend ALPHABLEND
+  DrawImage logo_img,width/2,height/2
+  aa#=0.5+(0.5*Cos(gtime/50))
+  SetBlend AlphaBLEND
+  SetAlpha aa
+  TileImage back[0],0,gTime/10
+
+  If ShadowOn
+    SetColor 0,0,0
+    SetBlend AlphaBLEND
+    SetAlpha 0.5
+    DrawPipes ShadowSize+16,ShadowSize+16
+
+    DrawTiles ShadowSize+16,ShadowSize+10
+    DrawPlayer ShadowSize,ShadowSize
+    DrawBalls ShadowSize,ShadowSize
+  EndIf
+
+  SetColor 255,255,255
+  SetBlend MASKBLEND
+  SetAlpha 1
+  DrawPipes()
+  DrawTiles()
+  DrawPlayer()
+  DrawBalls()
+EndFunction
+
+Function ResetGame()
+  TileList = New TList
+  BallList = New TList
+  Local x,y
+  For y=0 Until 5
+    For x=0 Until 18
+        Tilelist.AddLast(Tile.Create(38+x*32,(y*24)+66,4-Y))
+    Next
+  Next
+
+  BallList.AddLast(Ball.Create())
+EndFunction
+
+Function DrawPipes(x=16,y=16)
+  Local tmp
+
+  'top
+  For tmp=0 Until 18
+    DrawImage Pipes_img,x+32+(tmp*32),y+16,3
+  Next
+
+  'sides
+  For tmp=0 Until 14
+    DrawImage Pipes_img,x,y+48+(tmp*32),2
+    DrawImage Pipes_img,x+Width-32,y+48+(tmp*32),2
+  Next
+
+  'Corners
+  DrawImage Pipes_img,x,y+16 ,0
+  DrawImage Pipes_img,x+Width-32,y+16,1
+
+EndFunction
+
+Function DrawTiles(x_off=10, y_off=10)
+       Local tl:Tile
+       Local any=0
+  For tl=EachIn TileList
+               tl.Draw(x_off, y_off)
+               any=1
+       Next
+       If Not any 
+        ResetGame()
+        score:+10000
+       EndIf
+EndFunction
+
+Function DrawBalls(x_off=0, y_off=0)
+       Local bl:Ball
+       For bl=EachIn balllist
+               bl.Draw(x_off, y_off)
+       Next
+EndFunction
+
+Function UpdateBalls()
+  If ballcount=0
+    BallList.AddLast(Ball.Create(Width/2,Height/2))
+  Else
+       Local bl:Ball
+       For bl = EachIn BallList
+               bl.Update()
+       Next
+  EndIf
+EndFunction
+
+Function UpdateTiles()
+       Local tl:Tile
+       For tl=EachIn tilelist
+               tl.Update()
+       Next
+EndFunction
+
+Function DrawPlayer(x_off=0,y_off=0)
+  DrawImage paddle, playerx+x_off, playery+y_off
+End Function
diff --git a/samples/breakout/media/B-Max.png b/samples/breakout/media/B-Max.png
new file mode 100644 (file)
index 0000000..701db3d
Binary files /dev/null and b/samples/breakout/media/B-Max.png differ
diff --git a/samples/breakout/media/back1.png b/samples/breakout/media/back1.png
new file mode 100644 (file)
index 0000000..19084ba
Binary files /dev/null and b/samples/breakout/media/back1.png differ
diff --git a/samples/breakout/media/back2.png b/samples/breakout/media/back2.png
new file mode 100644 (file)
index 0000000..ef38308
Binary files /dev/null and b/samples/breakout/media/back2.png differ
diff --git a/samples/breakout/media/ball.png b/samples/breakout/media/ball.png
new file mode 100644 (file)
index 0000000..0862646
Binary files /dev/null and b/samples/breakout/media/ball.png differ
diff --git a/samples/breakout/media/paddle.png b/samples/breakout/media/paddle.png
new file mode 100644 (file)
index 0000000..9ffde5d
Binary files /dev/null and b/samples/breakout/media/paddle.png differ
diff --git a/samples/breakout/media/pipes.png b/samples/breakout/media/pipes.png
new file mode 100644 (file)
index 0000000..dafe7f7
Binary files /dev/null and b/samples/breakout/media/pipes.png differ
diff --git a/samples/breakout/media/tiles.png b/samples/breakout/media/tiles.png
new file mode 100644 (file)
index 0000000..6db868b
Binary files /dev/null and b/samples/breakout/media/tiles.png differ
diff --git a/samples/digesteroids/Digesteroids.ppf b/samples/digesteroids/Digesteroids.ppf
new file mode 100644 (file)
index 0000000..539784b
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version='1.0'?>
+<!--This project file was generated by Protean
+Editing it may render it inoperable. You have been warned!-->
+<xml>
+  <Project GUID="2EF9C725-F0F3-40F8-AFF9-155E7F196071" Expanded="True">
+    <Version>
+      <Formatting Short="%major%.%minor%" Long="%major%.%minor%.%build%.%revision%" />
+      <Values Major="0" Minor="1" Build="11" Revision="1113" />
+      <Rules RuleData="0,0,1,0,0,0,0,0,0,0,0,1,5000,0,0,0,0,0,0,0,0" />
+    </Version>
+    <Configurations>
+      <Configuration Name="Release">
+        <Property Name="Blitz_BeforeEXE_Options">True,True,True</Property>
+        <Property Name="Blitz_OverrideDebug">False</Property>
+        <Property Name="Blitz_IncludeLongVersion">True</Property>
+        <Property Name="Blitz_Compiler">Blitz Basic</Property>
+        <Property Name="Blitz_AfterCompile_Options">True,True,True</Property>
+        <Property Name="Blitz_IncludeShortVersion">True</Property>
+        <Property Name="Blitz_DebugEnabled">False</Property>
+        <Property Name="Blitz_ShortVersionVariable">VersionShort</Property>
+        <Property Name="Blitz_BeforeCheck_Options">True,True,True</Property>
+        <Property Name="Blitz_AfterEXE_Options">True,True,True</Property>
+        <Property Name="Blitz_LongVersionVariable">VersionLong</Property>
+        <Property Name="Blitz_BeforeCompile_Options">True,True,True</Property>
+        <Property Name="Blitz_CompileType">0</Property>
+        <Property Name="Blitz_AfterCheck_Options">True,True,True</Property>
+        <Property Name="Blitz_CommandLineEnabled">True</Property>
+      </Configuration>
+    </Configurations>
+    <Options>
+      <WorkingDirectory>D:\BlitzMax\robhutchinson\digesteroids</WorkingDirectory>
+      <SelectedConfiguration>Release</SelectedConfiguration>
+    </Options>
+    <File GUID="473AF815-1E27-48BD-9630-70D541441EB9" Open="True" Line="0" Column="0" Name="MathUtil.bmx">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="B02F06E0-4386-49CC-B5F8-35AB8BF082C8" Open="True" Line="0" Column="0" Name="simplephysics.bmx">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="5ED55F16-174B-42BD-A47A-1F99E39E1DF1" Open="True" Line="0" Column="0" Name="dynamicgame.bmx">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="9AF2C6A5-D96E-4391-9CA8-911FE7253975" Open="True" Line="901" Column="57" Name="digesteroids.bmx">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="31498CEA-525C-457E-A80B-754134C4A5F5" Open="False" Line="0" Column="0" Name="minitimer.bmx">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="9B56E13A-1332-43FE-BB98-B1218E5F4BEA" Open="False" Line="0" Column="0" Name="graphics\bullet1.png">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="8569E9CB-E52A-4E82-81BA-C3A58B63B620" Open="False" Line="0" Column="0" Name="graphics\bullet2.png">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="EA76DE94-7251-4DE9-B305-DDA538BBE239" Open="False" Line="0" Column="0" Name="graphics\digestive.png">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="B3632217-1AAA-45AE-90F4-D7D6113B69D7" Open="False" Line="0" Column="0" Name="graphics\ship.png">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <File GUID="45A32819-5298-4540-A707-E135C65C7672" Open="False" Line="0" Column="0" Name="graphics\stars.png">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </File>
+    <Directory Expanded="False" Name="graphics">
+      <Configurations>
+        <Configuration Name="Release" />
+      </Configurations>
+    </Directory>
+  </Project>
+</xml>
\ No newline at end of file
diff --git a/samples/digesteroids/MathUtil.bmx b/samples/digesteroids/MathUtil.bmx
new file mode 100644 (file)
index 0000000..aa5a075
--- /dev/null
@@ -0,0 +1,60 @@
+' *******************************************************************
+' Source: Math Util
+' Version: 1.00
+' Author: Rob Hutchinson 2004
+' Email: rob@proteanide.co.uk
+' WWW: http://www.proteanide.co.uk/
+' -------------------------------------------------------------------
+' Some generic functions. Certainly nothing to do with Math. HURRAH!
+' -------------------------------------------------------------------
+' Required:
+'  - Nothing.
+' *******************************************************************
+
+Type MathUtil
+
+'#Region Method: QWrapF
+       ' Wraps only once, if the value is out of the range by twice as much, this function will return incorrect values,
+       ' However, it is faster than Wrap. Use Wrap for accurate results.
+       Function QWrapF:Float(Value:Float,Minimum:Float,Maximum:Float)
+               If Value > Maximum
+                       Return Minimum + (Value Mod Maximum)
+               ElseIf Value < Minimum
+                       Return Maximum - Abs(Minimum - Value)
+               EndIf
+               Return Value
+       End Function
+'#End Region
+'#Region Method: QWrapDegrees
+       Function QWrapDegrees:Double(Value:Double)
+               If Value > 359.0
+                       Return (0.0 + (Value Mod 359.0))
+               ElseIf Value < 0.0
+                       Return (359.0 - Abs(0.0 - Value))
+               EndIf
+               Return Value
+       End Function
+'#End Region
+'#Region Method: Wrap
+       Function Wrap:Float(Value:Float,Minimum:Float,Maximum:Float)
+               Local Difference:Float = Maximum - Minimum
+               While ((Value < Minimum) Or (Value => Maximum))
+                       If Value => Maximum
+                               Value:- Difference
+                       Else
+                               If Value < Minimum
+                                       Value:+ Difference
+                               EndIf
+                       EndIf
+               Wend
+               Return value
+       End Function
+'#End Region
+'#Region Method: CurveValue
+       Function CurveValue:Float(Current:Float,Destination:Float,Curve:Int)
+               Current = Current + ( (Destination - Current) /Curve)
+               Return Current
+       End Function
+'#End Region
+
+End Type
diff --git a/samples/digesteroids/digesteroids.bmx b/samples/digesteroids/digesteroids.bmx
new file mode 100644 (file)
index 0000000..e73c278
--- /dev/null
@@ -0,0 +1,1496 @@
+' *******************************************************************
+' Digesteroids - V1.0
+' --------------------------------------------------------
+' An evil biscuit corporation are using their army of
+' sweet snack food to take over the world. Use your ship
+' to take down the evil invading corporation before 
+' they infest the world with dunkables sweetmeal biscuits.
+' REQUIRES 1024x768x32! @75Hz
+' --------------------------------------------------------
+' Author: Rob Hutchinson 2004
+' Email: rob@proteanide.co.uk
+' Written entirely in Protean IDE: 
+' WWW: http://www.proteanide.co.uk/
+' --------------------------------------------------------
+' Yep, there's stuff in here, I didnt get time to implement
+' Pickups, Weapons and Vortexes.
+' *******************************************************************
+       
+Strict
+
+' Import various utilities.
+Import "simplephysics.bmx"
+Import "dynamicgame.bmx"
+Import "MathUtil.bmx"
+
+' Screen settings.
+Const WIDTH       = 1024    ' Width of the screen.
+Const HEIGHT      = 768     ' Height of the screen.
+Const DEPTH       = 32      ' Depth of the screen.
+Const REFRESHRATE = 75      ' How often to update the screen (Per second).
+
+' Game Settings
+Const DYNAMICTIMING = True  ' If true then the game will try to keep up with
+Const DESIREDFPS    = 75    ' The Desired FPS of the game, can be independant of Refresh Rate.
+
+Function ScreenPan(OffsetX:Float, OffsetY:Float)
+       Local Width,Height,Depth,Hz
+       Width=GraphicsWidth()
+       Height=GraphicsHeight()
+       Depth=GraphicsDepth()
+       Hz=GraphicsHertz()
+    glMatrixMode GL_PROJECTION
+    glLoadIdentity
+    glOrtho 0,Width,Height,0,-1,1
+    glTranslatef OffsetX, OffsetY,0
+    glMatrixMode GL_MODELVIEW
+EndFunction
+
+Function QFlushKeys()
+       ' Quick implementation of flushkeys as BMX doesnt have one at time of writing, sure it
+       ' will be added though.
+       For Local Key:Int = 0 To 255
+               KeyHit(Key)
+               KeyDown(Key)
+       Next
+End Function
+
+'#Region Scene: MainMenu
+       ' The main menu scene.
+       Type MainMenuScene Extends T2DDynamicGameScene
+
+'#Region DrawTextCentered
+       Function DrawTextCentered:Int(Text:String,Y:Int)
+               Local Out:Int = (WIDTH / 2) - (TextWidth(Text) / 2)
+               DrawText(Text, Out, Y)
+               Return Out
+       End Function
+'#End Region
+
+'#Region Declarations
+               Const STARS_PER_SECOND = 6
+               Field BackColor:Float
+               Field Direction:Float = 0.01
+               Field ExitGame:Int = False
+               Field Music:TSound
+               Field MusicChannel:TChannel
+               Field Title:TImage
+               Field LowerTitle:TImage
+               Field Options:TImage
+               Field Craft:TImage
+               Field EnteredText:String = ""
+               Field LastHighScore:Int
+               Field ShowCredits:Int = False
+
+               Field Viewing:Int = VIEW_MENU
+               Field HoverOver:Int = VIEW_START
+
+               Const VIEW_MENU         = 0
+               Const VIEW_START        = 0
+               Const VIEW_INSTRUCTIONS = 1
+               Const VIEW_HIGHSCORES   = 2
+               Const VIEW_QUIT         = 3
+               Const VIEW_ENTERHIGH    = 4
+
+               Field Stars:TPhysicsProviderCollection = New TPhysicsProviderCollection
+               Field World:TWorldPhysicsProvider = TWorldPhysicsProvider.Create(0.0, 0.0, 0.0, True)
+'#End Region
+
+'#Region Method: FinishScoreEntry
+               Method FinishScoreEntry()
+                       Self.ViewMenu(VIEW_HIGHSCORES)
+                       Scores.Add(Self.LastHighScore, Self.EnteredText)
+
+                       ' Add this to the high scores..
+                       Self.LastHighScore = 0
+                       Self.EnteredText = ""
+               End Method
+'#End Region
+'#Region Method: ViewMenu
+               Method ViewMenu(Menu:Int)
+                       Self.Viewing = Menu
+                       Self.HoverOver = Menu
+                       QFlushKeys()
+               End Method
+'#End Region
+
+'#Region Method: Update
+               Method Update()
+                       Self.Stars.ApplyPhysics()
+
+                       ' Add new stars..
+                       For Local CountStars:Int = 0 To STARS_PER_SECOND
+                               Local Star:TMenuStar = TMenuStar.Create(World, Self, 10.0)
+                               Self.Stars.AddLast(Star)
+                       Next
+
+                       ' Do enter key checking..
+                       Select Self.Viewing
+                               Case VIEW_MENU
+                                       If KeyHit(KEY_ENTER) Then 
+                                               Select Self.HoverOver
+                                                       Case VIEW_START
+                                                               Self.TerminateMainLoop = True
+               
+                                                       Case VIEW_INSTRUCTIONS
+                                                               Self.ViewMenu(VIEW_INSTRUCTIONS)
+               
+                                                       Case VIEW_HIGHSCORES
+                                                               Self.ViewMenu(VIEW_HIGHSCORES)
+               
+                                                       Case VIEW_QUIT
+                                                               Self.TerminateMainLoop = True
+                                                               Self.ExitGame = True
+               
+                                               End Select
+                                       EndIf
+
+                                       If KeyHit(KEY_UP)
+                                               Self.HoverOver :- 1
+                                               If Self.HoverOver < VIEW_START Then Self.HoverOver = VIEW_START
+                                       EndIf
+                                       If KeyHit(KEY_DOWN)
+                                               Self.HoverOver :+ 1
+                                               If Self.HoverOver > VIEW_QUIT Then Self.HoverOver = VIEW_QUIT
+                                       EndIf
+
+                                       If KeyHit(KEY_ESCAPE) Then 
+                                               Self.TerminateMainLoop = True
+                                               Self.ExitGame = True
+                                       Else
+                                               If KeyHit(KEY_C)
+                                                       Self.TerminateMainLoop = True
+                                                       Self.ShowCredits = True
+                                               EndIf
+                                       EndIf
+
+                               Case VIEW_INSTRUCTIONS, VIEW_HIGHSCORES
+                                       If KeyHit(KEY_ENTER) Or KeyHit(KEY_ESCAPE)
+                                               Self.Viewing = VIEW_MENU
+                                       EndIf
+
+                               Case VIEW_ENTERHIGH
+                                       ' Check for alpha keys.
+                                       For Local Count:Int = KEY_A To KEY_Z
+                                               If KeyHit(Count) Then Self.EnteredText = Self.EnteredText + Chr(Count)
+                                       Next
+                                       ' Check for number key hits
+                                       For Local Count:Int = KEY_0 To KEY_9
+                                               If KeyHit(Count) Then Self.EnteredText = Self.EnteredText + Chr(Count)
+                                       Next
+                                       ' Special case, check for space bar
+                                       If KeyHit(KEY_SPACE)
+                                               Self.EnteredText = Self.EnteredText + " "
+                                       EndIf
+                                       ' Remove a character when user hits backspace.
+                                       If KeyHit(KEY_BACKSPACE)
+                                               If Len(Self.EnteredText) > 0
+                                                       Self.EnteredText = Mid(Self.EnteredText,0,Len(Self.EnteredText))
+                                               EndIf
+                                       EndIf
+                                       ' If 5 characters are entered, end high score entry.
+                                       If Len(Self.EnteredText) = 5 Then Self.FinishScoreEntry()
+                       
+                                       If KeyHit(KEY_ENTER)
+                                               Self.FinishScoreEntry()
+                                       EndIf
+
+                       End Select
+
+               End Method
+'#End Region
+'#Region Method: Render
+               Method Render()
+                       Cls
+
+                       ScreenPan(0,0)
+
+                       SetTransform
+                       SetAlpha 1.0
+                       SetBlend(SOLIDBLEND)
+                       Self.Stars.Draw()
+
+                       SetColor 255,255,255
+                       SetBlend(ALPHABLEND)
+                       DrawImage(Self.Title,0,40)
+                       DrawImage(Self.LowerTitle,0,660)
+
+                       Local StartPosX:Int = 150
+                       Local StartPosY:Int = 245
+
+                       Select Self.Viewing
+                               Case VIEW_MENU
+                                       ' Showing main menu
+                                       DrawImage(Self.Options,450,330)
+                                       SetRotation -90
+                                       Select Self.HoverOver
+                                               Case VIEW_START
+                                                       DrawImage(Self.Craft,416,352)
+                                                       
+                                               Case VIEW_INSTRUCTIONS
+                                                       DrawImage(Self.Craft,416,352 + 37)
+               
+                                               Case VIEW_HIGHSCORES  
+                                                       DrawImage(Self.Craft,416,352 + 74)
+               
+                                               Case VIEW_QUIT        
+                                                       DrawImage(Self.Craft,416,352 + 145)
+               
+                                       End Select
+
+                               Case VIEW_HIGHSCORES
+                                       Scores.Render(385,310)
+
+                               Case VIEW_ENTERHIGH
+                                       DrawTextCentered("CONGRATULATIONS!",StartPosY)
+                                       DrawTextCentered("You have a new high score!",StartPosY+50)
+                                       DrawTextCentered("Please enter your name (5 characters)",StartPosY+65)
+                                       Local TextX:Int = DrawTextCentered(Self.EnteredText,StartPosY+250)
+                                       DrawRect(TextX + TextWidth(Self.EnteredText), StartPosY+250, 12, 15)
+
+                               Case VIEW_INSTRUCTIONS
+                                       DrawText("Welcome to Digesteroids!",StartPosX,StartPosY)
+                                       DrawText("------------------------",StartPosX,StartPosY+20)
+                                       DrawText("An evil biscuit corporation are using their army of sweet snack food to take over the world.",StartPosX,StartPosY+50)
+                                       DrawText("Fortunately, the ingredients the evil corporation used are vulnerable to big sweaty laser",StartPosX,StartPosY+70)
+                                       DrawText("blasts. Use your ship's cannon to take out the corporation before they infest the world with",StartPosX,StartPosY+90)
+                                       DrawText("sweetmeal dunkables biscuits. But be careful, space is small (just big enough to fit inside",StartPosX,StartPosY+110)
+                                       DrawText("your screen), it is also cyclical, so beware of incoming oval shaped objects.",StartPosX,StartPosY+130)
+
+                                       DrawText("Keys:",StartPosX,StartPosY+180)
+                                       DrawText(" - UP CURSOR ARROW     = Thrust",StartPosX,StartPosY+200)
+                                       DrawText(" - DOWN CURSOR ARROW   = Teleport",StartPosX,StartPosY+220)
+                                       DrawText(" - LEFT CURSOR ARROW   = Rotate Ship Left",StartPosX,StartPosY+240)
+                                       DrawText(" - RIGHT CURSOR ARROW  = Rotate Ship Right",StartPosX,StartPosY+260)
+                                       DrawText(" - ESCAPE              = QUIT",StartPosX,StartPosY+280)
+
+                                       DrawText("Yes, that's right, it's a glorified asteroids game!",StartPosX,StartPosY+320)
+                                       SetColor 255,0,0
+                                       DrawText("Note: Your score is based on the speed at which your ship is travelling when it fired.",StartPosX,StartPosY+340)
+
+                       End Select
+               End Method
+'#End Region
+'#Region Method: Start
+               Method Start()
+                       Self.MusicChannel = AllocChannel()
+                       If Self.Music = Null Then Self.Music = LoadSound("sounds\menu.ogg",True)
+                       PlaySound(Self.Music,Self.MusicChannel)
+                       SetChannelVolume MusicChannel,1.0
+
+                       ' Load GFX..
+                       If Self.Title = Null Then Self.Title = LoadImage("graphics\title.png")
+                       If Self.LowerTitle = Null Then Self.LowerTitle = LoadImage("graphics\lower.png")
+                       If Self.Options = Null Then Self.Options = LoadImage("graphics\options.png")
+                       If Self.Craft = Null Then Self.Craft = LoadImage("graphics\ship.png")
+
+                       ' Add a screen full of stars.
+                       For Local CountStars:Int = 0 To 1000
+                               Local Star:TMenuStar = TMenuStar.Create(World, Self, 10.0)
+                               Star.X = Rnd(WIDTH)
+                               Self.Stars.AddLast(Star)
+                       Next
+               End Method
+'#End Region
+'#Region Method: Finish
+               Method Finish()
+                       Self.Stars.Clear()
+                       Self.MusicChannel.Stop()
+                       Self.MusicChannel = Null
+               End Method
+'#End Region
+       
+       End Type
+'#End Region
+'#Region Scene: MainGame
+       ' Main Game scene
+       Type MainGameScene Extends T2DDynamicGameScene
+
+'#Region Declarations
+               Const STARS_PER_SECOND = 3
+               Const FINISH_AT_LEVEL = 6
+               Field Level:Int = 1
+               Field Completed:Int = False
+               
+               Field DigestiveImage:TImage
+               Field ShipImage:TImage
+               Field StarsImage:TImage
+
+               Field LargeImpactSound:TSound
+
+               Field World:TWorldPhysicsProvider = TWorldPhysicsProvider.Create(0.0, 0.0, 0.0, True)
+
+               Field Digestives:TPhysicsProviderCollection = New TPhysicsProviderCollection
+               Field Bullets:TPhysicsProviderCollection = New TPhysicsProviderCollection
+               Field Stars:TPhysicsProviderCollection = New TPhysicsProviderCollection
+
+               Field Chunks:TFountain
+               Const CHUNK_COUNT = 2
+               Field ChunkImages:TImage[CHUNK_COUNT + 1]
+
+               Field Player:TPlayer
+               Field Shake:Float
+
+               Field Pickups:TList = New TList
+'#End Region
+
+'#Region Method: Update
+               Method Update()
+                       If KeyHit(KEY_ESCAPE) Then Self.TerminateMainLoop = True
+
+                       CheckEndOfLevel()  ' Check if we need to move to the next level (IE, all digestives gone)
+
+                       ' Add new stars..
+                       For Local CountStars:Int = 0 To STARS_PER_SECOND
+                               Local Speed:Float = Self.Player.Speed()
+                               If Speed < 1.0 Then Speed = 1.0
+                               Local Star:TStar = TStar.Create(World, Self, Speed)
+                               Self.Stars.AddLast(Star)
+                       Next
+
+                       ' Update screenshake...
+                       Self.Shake :/ 1.02
+                       If Self.Shake < 0.0 Then Self.Shake = 0.0
+                       If Self.Shake > 6.0 Then Self.Shake = 6.0
+
+                       ' Update all the stars.
+                       Self.Stars.ApplyPhysics()
+
+                       ' Update the chunks
+                       Self.Chunks.UpdateWithFriction(TPhysicsProvider.AxisX | TPhysicsProvider.AxisY)
+
+                       ' Update all the digestives.
+                       Self.Digestives.ApplyPhysics()
+
+                       ' Update all the bullets.
+                       Self.Bullets.ApplyPhysics()
+
+                       ' Update the player.    
+                       Self.Player.Update()
+                       Self.Player.ApplyFriction(TPhysicsProvider.AxisX | TPhysicsProvider.AxisY)
+                       Self.Player.ApplyPhysics()
+               End Method
+'#End Region
+'#Region Method: Render
+               Method Render()
+                       SetClsColor 0,0,0
+                       Cls
+               
+                       If Self.Shake > 0.0 Then
+                               ScreenPan(Rnd(Shake),Rnd(Shake))
+                       EndIf
+
+                       ' Draw the spazzy psychodelic effect if it is enabled.
+                       Self.DrawPsychodelic()
+       
+                       SetAlpha 1
+                       SetTransform
+                       ' Draw all the stars.   
+                       Self.Stars.Draw()
+
+                       Self.Chunks.Draw()
+
+                       ' Draw the digestives.
+                       SetColor 255,255,255
+                       SetBlend(ALPHABLEND)
+                       Digestives.Draw()
+
+                       ' Draw the bullets
+                       SetBlend(LIGHTBLEND)
+                       Bullets.Draw()
+               
+                       ' Draw the player.
+                       SetBlend(ALPHABLEND)
+                       Player.Draw()
+
+                       ' Draw the hud          
+                       DrawHUD()
+               End Method
+'#End Region
+'#Region Method: Start
+               Method Start()
+                       AutoMidHandle True
+
+                       Self.Shake = 0          
+                       Self.Chunks = TFountain.Create(Self.World,TRectangle.Create(0,0,WIDTH,HEIGHT))
+
+                       ' Load in the required Images...                
+                       If Self.DigestiveImage = Null Then Self.DigestiveImage = LoadImage("graphics\digestive.png")
+                       If Self.ShipImage = Null Then Self.ShipImage = LoadImage("graphics\ship.png")
+                       If Self.StarsImage = Null Then Self.StarsImage = LoadImage("graphics\stars.png")
+
+                       For Local LoadCount:Int = 0 To CHUNK_COUNT
+                               Self.ChunkImages[LoadCount] = LoadImage("graphics\piece" + String(LoadCount + 1) + ".png")
+                       Next
+
+                       ' Set up the player
+                       Self.Player = TPlayer.Create(Self.World, Self.ShipImage,Self)
+                       Self.Player.LoadAssets()
+
+                       ' Load up the sounds.
+                       If Self.LargeImpactSound = Null Then Self.LargeImpactSound = LoadSound("Sounds\ImpactLarge.wav")
+
+                       ' Reset the game..
+                       Self.ResetGame()
+
+                       ' Create all the weapons..
+                       Self.Pickups.Clear()
+                       Local Bullet1Image:TImage = LoadImage("graphics\bullet1.png")
+                       Local Fire1Sound:TSound = LoadSound("sounds\fire.wav")
+
+'                      Local Blaster:TWeapon = TWeapon.Create(Speed,Graphic,Size,Radius,Veer,FireRate,MainGame,Sound)
+                       Local Blaster:TWeapon = TWeapon.Create(10, Bullet1Image, 0.65, 4.0, 0,30, Self, Fire1Sound, Bullet1Image, "Blaster")
+                       Local FastBlaster:TWeapon = TWeapon.Create(9, Bullet1Image, 0.3, 4.0, 0.0, 15, Self, Fire1Sound, Bullet1Image, "Blaster Mk2")
+                       Local SprayBlaster:TWeapon = TWeapon.Create(8, Bullet1Image, 0.35, 4.0, 5.0, 1, Self, Fire1Sound, Bullet1Image, "Blaster Mk3")
+
+                       Local BlasterPickup:TPickup = TPickup.Create(TPickup.MODIFIER_WEAPON,0,0,True,Blaster,Bullet1Image,0.01,Bullet1Image)
+                       Local FastBlasterPickup:TPickup = TPickup.Create(TPickup.MODIFIER_WEAPON,0,0,True,FastBlaster,Bullet1Image,0.01,Bullet1Image)
+                       Local SprayBlasterPickup:TPickup = TPickup.Create(TPickup.MODIFIER_WEAPON,0,0,True,SprayBlaster,Bullet1Image,0.008,Bullet1Image)
+
+                       Local Score1000Pickup:TPickup = TPickup.Create(TPickup.MODIFIER_SCORE,1000,0,True,Null,Null,0.02,Bullet1Image)
+                       Local Score500Pickup:TPickup = TPickup.Create(TPickup.MODIFIER_SCORE,500,0,True,Null,Null,0.03,Bullet1Image)
+
+                       Local RotationPickup:TPickup = TPickup.Create(TPickup.MODIFIER_ROTATION,1.1,0,True,Null,Null,0.01,Bullet1Image)
+                       Local PsychodelicPickup:TPickup = TPickup.Create(TPickup.MODIFIER_PSYCHODELIC,0,1000,False,Null,Null,0.04,Bullet1Image)
+
+                       Local LivesPickup:TPickup = TPickup.Create(TPickup.MODIFIER_LIVES,1,0,True,Null,Null,0.001,Bullet1Image)
+
+                       Self.Player.Weapon = Blaster
+
+               End Method
+'#End Region
+'#Region Method: Finish
+               Method Finish()
+                       Self.Player.ThrusterChannel.Stop
+                       Self.Player.ThrusterChannel = Null
+               End Method
+'#End Region
+       
+'#Region Method: CheckEndOfLevel
+       Method CheckEndOfLevel()
+               If Digestives.IsEmpty() = True
+                       ' No more digestives..
+                       Level :+ 1
+                       If Level = FINISH_AT_LEVEL Then 
+                               ' This was the last level.
+                               Self.Completed = True
+                               Self.TerminateMainLoop = True
+                       Else
+                               ' Move to the next level
+                               GotoLevel(Level)
+                       EndIf
+               EndIf
+       End Method
+'#End Region
+'#Region Method: DrawHUD
+       Method DrawHUD()
+               SetColor 255,255,255
+               SetAlpha 1.0
+               SetRotation 0
+               DrawText "Level: " + Level,0,0
+               Local Lives:String = "Lives: " + Player.Lives
+               Local Score:String = "Score: " + Player.Score
+               DrawText Score,(WIDTH / 2) - (TextWidth(Score) / 2) ,0
+               DrawText Lives,(WIDTH - TextWidth(Lives)) ,0
+               
+               Local fr$="000"+Int(Self.Player.Speed()*1000) Mod 1000
+               Local sp$=Int(Self.Player.Speed()*1000)/1000+"."+fr[fr.length-3..]
+               
+               DrawText "Speed: " + sp,0,15
+               DrawText "Teleports: " + Self.Player.Teleports,0,30
+       End Method
+'#End Region
+'#Region Method: ResetGame
+       Method ResetGame()
+               Digestives.Clear()
+               Bullets.Clear()
+               Stars.Clear()
+               Chunks.Particles.Clear()
+               Player.Lives = 5
+               Player.Reset()
+               GotoLevel(1)
+       End Method
+'#End Region
+'#Region Method: GotoLevel
+       Method GotoLevel(ToLevel:Int)
+               Level = ToLevel
+               For Local Count:Int = 1 To ToLevel
+                       Local Digestive:TDigestive = TDigestive.Create(World, DigestiveImage,Self)
+                       Digestive.X = Rnd(0,WIDTH)
+                       Digestive.Y = Rnd(0,HEIGHT)
+                       Digestive.Rotation = Rnd(360)
+                       Digestive.Weight = 5
+                       Digestive.SetVelocityFromAngle(Rnd(360.0),Rnd(0.5,1.5))
+                       Digestive.HitSound = Self.LargeImpactSound
+                       Digestives.AddLast(Digestive)
+               Next
+       End Method
+'#End Region
+'#Region Method: DrawPsychodelic
+       Field PsychoAngle:Float = 0
+       Field Psycho:Int = False
+       
+       Method DrawPsychodelic()
+               If Psycho = True
+                       SetColor Rnd(0.0,255),Rnd(0.0,255),Rnd(0.0,255)
+                       PsychoAngle :+ 8
+                       SetBlend(SOLIDBLEND)
+                       TileImage(StarsImage,Sin(PsychoAngle) * 200,Cos(PsychoAngle) * 200)
+               Else
+                       SetColor 255,255,255
+               EndIf
+       End Method
+'#End Region
+'#Region Method: FindSafeLocation
+       Method FindSafeLocation:TPointD(Radius:Float)
+               While True
+                       Local X:Int = Rnd(0,WIDTH)
+                       Local Y:Int = Rnd(0,HEIGHT)
+                       If Self.IsLocationSafe(X,Y,Radius)
+                               Local Out:TPointD = New TPointD
+                               Out.X = X
+                               Out.Y = Y
+                               Return Out
+                       EndIf
+               Wend
+       End Method
+'#End Region
+'#Region Method: IsLocationSafe
+       Method IsLocationSafe:Int(X:Int,Y:Int,Radius:Float)
+               Local TryCircle:TCircle = New TCircle
+               TryCircle.X = X
+               TryCircle.Y = Y
+               TryCircle.Radius = Radius
+               For Local Item:TDigestive = EachIn Self.Digestives
+                       If Item.Circle.CollidesWith(TryCircle)
+                               Return False
+                       EndIf
+               Next
+               Return True
+       End Method
+'#End Region
+
+       End Type
+'#End Region
+'#Region Scene: Ending
+       ' The ending scene.
+       Type EndingScene Extends T2DDynamicGameScene
+       
+'#Region Declarations
+               Const STARS_PER_SECOND = 0
+               Const MAGNET_COUNT = 5
+               Field ScrollPoint:Float
+               Field Music:TSound
+               Field MusicChannel:TChannel
+               Field Title:TImage
+               Field Time:Int = 1000000
+
+               Field TEXTS_COUNT = 23
+               Field Texts:String[TEXTS_COUNT]
+
+               Field Stars:TPhysicsProviderCollection = New TPhysicsProviderCollection
+               Field World:TWorldPhysicsProvider = TWorldPhysicsProvider.Create(0.2, 0.0, 0.0, True)
+'#End Region
+
+'#Region Method: Update
+               Method Update()
+                       Self.Stars.ApplyPhysics()
+
+                       If KeyHit(KEY_ESCAPE) Then 
+                               Self.TerminateMainLoop = True
+                       EndIf
+
+                       Self.Time :+ 1
+                       If Self.Time > 100 Then
+                               Self.Time = 0
+                               ' Add a new magnet
+                               Local ThisMagnet:TEndMagnet = New TEndMagnet
+                               ThisMagnet.X = Rnd(WIDTH)
+                               ThisMagnet.Y = Rnd(HEIGHT)
+                               ThisMagnet.Radius = Rnd(200,500)
+                               ThisMagnet.Polarity = TMagnet.PositivePolarity
+                               ThisMagnet.Strength = Rnd(0.1,0.5)
+                               Self.World.Magnets.AddLast(ThisMagnet)
+                               Self.World.ApplyMagnets = True
+                       EndIf
+
+
+                       Local X:Int = WIDTH/2
+                       Local Y:Int = HEIGHT/2
+                       For Local Magnet:TEndMagnet = EachIn Self.World.Magnets
+                               For Local Count:Int = 0 To STARS_PER_SECOND
+                                       Local ThisStar:TEndingStar = TEndingStar.Create(Self.World, Self, Rnd(1.0,5.0), Magnet.X + (Sin(Rnd(360.0)) * 5.0), Magnet.Y + (Cos(Rnd(360.0)) * 5.0))
+                                       ThisStar.SetVelocityFromAngle(Rnd(360),Rnd(1.0,5.0))
+                                       Self.Stars.AddLast(ThisStar)
+                                       Magnet.Stars :+ 1
+                               Next
+                               If Magnet.Stars > 500 Then
+                                       Self.World.Magnets.Remove(Magnet)
+                               EndIf
+                       Next
+
+                       ' Update the scoller
+                       Self.ScrollPoint :- 0.5
+                       If Self.Scrollpoint     < -((TEXTS_COUNT * 25) + 100)
+                               Self.ScrollPoint = HEIGHT + 20
+                       EndIf
+                       
+               End Method
+'#End Region
+'#Region Method: Render
+               Method Render()
+                       Cls
+
+                       Self.Stars.Draw()
+
+                       SetColor 255,255,255
+                       For Local Count:Int = 0 To TEXTS_COUNT - 1
+                               MainMenuScene.DrawTextCentered(Self.Texts[Count],Self.ScrollPoint + (25 * Count))
+                       Next
+               End Method
+'#End Region
+'#Region Method: Start
+               Method Start()
+                       Self.MusicChannel = AllocChannel()
+                       If Self.Music = Null Then Self.Music = LoadSound("sounds\ending.ogg",True)
+                       If Self.MusicChannel <> Null
+                               PlaySound(Self.Music,Self.MusicChannel)
+                       EndIf
+
+                       Self.Texts[0] = "Cast of Characters"
+                       Self.Texts[1] = "------------------"
+                       Self.Texts[2] = ""
+                       Self.Texts[3] = "Space Craft.......................Intrepid"
+                       Self.Texts[4] = "Digestive...............Sweet Meal Biscuit"
+                       Self.Texts[5] = "Star...............................Himself"
+                       Self.Texts[6] = ""
+                       Self.Texts[7] = "Written by Rob Hutchinson in roughly 5 days."
+                       Self.Texts[8] = "Email: rob@proteanide.co.uk"
+                       Self.Texts[9] = "Web: http://www.proteanide.co.uk/"
+                       Self.Texts[10] = ""
+                       Self.Texts[11] = "Special Thanks To"
+                       Self.Texts[12] = "-----------------"
+                       Self.Texts[13] = "Richard Makepeace.............Inspiration"
+                       Self.Texts[14] = "James Readman.................Inspiration"
+                       Self.Texts[15] = ""
+                       Self.Texts[16] = "Greets"
+                       Self.Texts[17] = "------"
+                       Self.Texts[18] = "Pickup, Cabsy, Peters, ZanaX, Compona, Helen, + all other family and friends."
+                       Self.Texts[19] = ""
+                       Self.Texts[20] = ""
+                       Self.Texts[21] = ""
+                       Self.Texts[22] = "Thank you for playing."
+
+                       Self.ScrollPoint = HEIGHT + 20
+               End Method
+'#End Region
+'#Region Method: Finish
+               Method Finish()
+                       Self.Stars.Clear()
+                       If Self.MusicChannel <> Null Then
+                               Self.MusicChannel.Stop()
+                               Self.MusicChannel = Null
+                       EndIf
+               End Method
+'#End Region
+
+       End Type
+'#End Region
+
+Type TCircle
+       
+       Field X:Int
+       Field Y:Int
+       Field Radius:Float
+       
+       Method CollidesWith:Int(Circle:TCircle) 
+               Local Distance:Double = TPhysicsUtility.DistanceBetweenPoints(Self.X,Self.Y,Circle.X,Circle.Y)
+               If Distance < (Self.Radius + Circle.Radius) Then Return True
+               Return False
+       End Method
+
+       Method Draw()
+               SetBlend(ALPHABLEND)
+               SetAlpha(0.5)
+               SetRotation 0
+               DrawCircle(X,Y,Int(Radius))
+       End Method
+
+       Function DrawCircle(X,Y,Radius)
+               DrawOval(X - Radius,Y - Radius,Radius * 2,Radius * 2)
+       End Function
+
+End Type
+Type TDigestive Extends TPhysicsProvider
+       Field Image:TImage
+       Field Alpha:Float = 1.0
+       Field Rotation:Float = 0
+       Field Scale:Float = 1.0
+       Field Circle:TCircle = New TCircle
+       Field GameScene:MainGameScene
+       Const InitialRadius:Float = 70.0
+       Field HitSound:TSound
+
+       Method SplitIntoChunks(X:Int,Y:Int,Multiplier:Float)
+               GameScene.Digestives.Remove(Self)
+
+               Local Channel:TChannel = AllocChannel()
+               If Channel <> Null
+                       Channel.SetVolume(Self.Scale)
+                       PlaySound(Self.HitSound, Channel)
+               EndIf
+
+               Self.GameScene.Chunks.X = X
+               Self.GameScene.Chunks.Y = Y
+               
+               Self.GameScene.Player.Score :+ Int(((Self.Scale * 100.0) + 4.0) * Multiplier)
+
+               Self.GameScene.Shake :+ (Self.Scale * 3.5)
+               
+
+               If Self.Scale > 0.2
+                       For Local Count:Int = 0 To Int(Self.Scale * 5)
+                               Local Digestive:TDigestive = TDigestive.Create(Self.World, Self.Image, Self.GameScene)
+                               Digestive.X = Self.X
+                               Digestive.Y = Self.Y
+                               Digestive.Rotation = Rnd(360)
+                               Digestive.Weight = 5
+                               Digestive.SetVelocityFromAngle(Rnd(360.0),Rnd(0.5,1.5))
+                               Digestive.SetDrawScale(Self.Scale / 2)
+                               Digestive.HitSound = Self.HitSound
+                               GameScene.Digestives.AddLast(Digestive)
+                       Next
+
+                       For Local ChunkCount:Int = 0 To 4 * (Self.Scale * 10)
+                               Local Particle:TStaticParticle = Self.GameScene.Chunks.AddStaticParticle(Self.GameScene.ChunkImages[(Int(Rnd(0,MainGameScene.CHUNK_COUNT)))], Rnd(360.0), Rnd(0.5,10.0), 0, 0.01, [255,255,255])
+                               Particle.Friction = 0.97
+                               Particle.Size = Rnd(0.5,1.0)
+                               Particle.Rotation = Rnd(-5.0,5.0)
+                       Next
+               Else
+                       For Local ChunkCount2:Int = 0 To Rnd(3,8)
+                               Local Particle:TStaticParticle = Self.GameScene.Chunks.AddStaticParticle(Self.GameScene.ChunkImages[(Int(Rnd(0,MainGameScene.CHUNK_COUNT)))], Rnd(360.0), Rnd(0.5,10.0), 0, 0.01, [255,255,255])
+                               Particle.Friction = 0.97
+                               Particle.Size = Rnd(0.2,0.5)
+                               Particle.Rotation = Rnd(-5.0,5.0)
+                       Next
+               End If
+       End Method
+
+       Method Draw()
+               SetAlpha Self.ALPHA
+               SetRotation Self.Rotation
+               SetScale Self.Scale,Self.Scale
+               DrawImage(Self.Image, Self.X, Self.Y)
+               SetScale 1,1
+       End Method
+
+       Method SetDrawScale(Scale:Float)
+               Self.Scale = Scale
+               Self.Circle.Radius = Self.InitialRadius * Self.Scale
+       End Method
+
+       Method PhysicsApplied()
+               Rotation:+2
+               Local HalfWidth:Int = ((Image.Width * Self.Scale) / 2)
+               Local HalfHeight:Int = ((Image.Height * Self.Scale) / 2)
+               If X < -HalfWidth Then X = WIDTH + HalfWidth
+               If Y < -HalfHeight Then Y = HEIGHT + HalfHeight
+               If X > WIDTH + HalfWidth Then X = -HalfWidth
+               If Y > HEIGHT + HalfHeight Then Y = -HalfHeight
+               Self.Circle.X = Self.X
+               Self.Circle.Y = Self.Y
+       End Method
+
+       Function Create:TDigestive(World:TWorldPhysicsProvider,Image:TImage,GameScene:MainGameScene)
+               Local Out:TDigestive = New TDigestive
+               Out.GameScene = GameScene
+               Out.Circle.Radius = InitialRadius
+               Out.World = World
+               Out.Image = Image
+               Return Out
+       End Function
+
+End Type
+Type TPlayer Extends TPhysicsProvider
+
+       Field Lives:Int
+       Field Score:Int
+       Field Weapon:TWeapon
+       Field Dead:Int = True
+       Field Teleports:Int = 2
+
+       Field Image:TImage
+       Field Rotation:Float
+       Field Acceleration:Float
+       Field MaxAcceleration:Float = 4.0
+       Field Motion:Float = 0.001
+       Field AccelerationDropMultiplier:Float = 8
+       Field Circle:TCircle = New TCircle
+       Field GameScene:MainGameScene
+
+       Field FireRateCount:Float = 0
+
+       Field Thruster:TFountain
+       Field Death:TFountain
+
+       Field ThrusterImage:TImage
+       Field DeathImage:TImage
+       Field SparkleImage:TImage
+       Field ThrusterSound:TSound
+       Field CrashSound:TSound
+       Field ThrusterChannel:TChannel
+       Field TeleportSound:TSound
+
+       Method Draw()
+               SetTransform
+               ' Render the thruster...
+               SetBlend LIGHTBLEND
+               SetScale 0.6, 0.6
+               SetAlpha 1.0
+               Self.Thruster.Draw()
+               Self.Death.Draw()
+
+               If Not Self.Dead Then
+                       ' Render the player.
+                       SetBlend ALPHABLEND
+                       SetAlpha 1.0
+                       SetScale 1.0,1.0
+                       SetColor 255,255,255
+                       SetRotation 360 - Self.Rotation
+                       DrawImage(Self.Image, Self.X, Self.Y)
+               EndIf
+       End Method
+
+       Method PhysicsApplied()
+               Local HalfWidth:Int = (Image.Width / 2)
+               Local HalfHeight:Int = (Image.Height / 2)
+               If X < -HalfWidth Then X = WIDTH + HalfWidth
+               If Y < -HalfHeight Then Y = HEIGHT + HalfHeight
+               If X > WIDTH + HalfWidth Then X = -HalfWidth
+               If Y > HEIGHT + HalfHeight Then Y = -HalfHeight
+               Self.Circle.X = Self.X
+               Self.Circle.Y = Self.Y
+       End Method
+
+       Method Update()
+               ' Update thruster and death particles.
+               Local Particle:TStaticParticle = Self.Thruster.AddStaticParticle(Self.ThrusterImage, Self.Rotation + 180 + Rnd(-5.0,5.0), 1.0, 1, 0.04, [255,255,255])
+       
+               Local ActualRotation:Float = Self.Rotation + 180
+
+               Self.Thruster.X = Self.X + (Sin(ActualRotation) * 10) 
+               Self.Thruster.Y = Self.Y + (Cos(ActualRotation) * 10) 
+
+               Local ThisSpeed:Float = Self.Speed()
+               
+               If ThisSpeed < 0 Then ThisSpeed = 0 
+               If ThisSpeed > 10.0 Then ThisSpeed = 10.0
+               
+               ' Add particles to the thruster..
+               Particle.Size = (ThisSpeed / 10)
+               Self.ThrusterChannel.SetVolume(ThisSpeed / 10)
+               Self.ThrusterChannel.SetPan(Float(Self.X / Float(WIDTH / 2.0) - 1.0))
+               Self.GameScene.Shake:+ 0.10 * (ThisSpeed / 10.0)
+
+               Self.Thruster.Update()
+               Self.Death.UpdateWithFriction(TPhysicsProvider.AxisX | TPhysicsProvider.AxisY)
+       
+               If Self.Dead
+                       ' Player is currently dead, wait for a nice chance to put them back down.
+                       If Self.Lives < 1 Then
+                               ' Wait for the death particles to become zeroed.
+                               If Self.Death.Particles.IsEmpty() Then
+                                       Self.GameScene.TerminateMainLoop = True
+                               EndIf
+                       Else
+                               ' Check to see if the center spot is safe to plop the ship on.
+                               If Self.GameScene.IsLocationSafe(WIDTH/2, HEIGHT/2, 70)
+                                       Self.Dead = False
+                                       For Local Pops:Int = 0 To 200
+                                               Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.SparkleImage, Rnd(360.0), Rnd(0.5,2.0), 0, Rnd(0.01, 0.03), [255,255,255])
+                                               Particle.X = Self.X
+                                               Particle.Y = Self.Y
+                                               Particle.Rotation = Rnd(-1.0,1.0)
+                                               Particle.Friction = 0.97
+                                               Particle.Size = Rnd(0.1,0.2)
+                                       Next
+                               EndIf
+                       EndIf
+               Else
+                       ' Update fire rate counter...
+                       Self.FireRateCount :- 1
+                       
+                       If KeyDown(KEY_UP)
+                               ' Thrust
+                               Self.Acceleration :+ Self.Motion
+                               ' Clamp the acceleration
+                               If Self.Acceleration > Self.MaxAcceleration Then Self.Acceleration = Self.MaxAcceleration
+                               ' Add acceleration.
+                               Self.IncreaseVelocityFromAngle(Self.Rotation,Self.Acceleration)
+                       Else
+                               Self.Acceleration :- (Self.Motion * Self.AccelerationDropMultiplier)
+                               If Self.Acceleration < 0.0 Then Self.Acceleration = 0
+                       EndIf
+       
+                       If KeyDown(KEY_LEFT)
+                               ' RotateLeft
+                               Self.Rotation :+ 3
+                       EndIf
+       
+                       If KeyDown(KEY_RIGHT)
+                               ' RotateLeft
+                               Self.Rotation :- 3
+                       EndIf
+       
+                       If KeyDown(KEY_SPACE)
+                               ' FIRE! 
+                               If Self.FireRateCount <= 0 Then
+                                       Self.FireRateCount = Self.Weapon.FireRate
+                                       Self.Weapon.Fire(Self)
+                               End If
+                       EndIf
+       
+                       If KeyHit(KEY_DOWN)
+                               ' TELEPORT
+                               If Self.Teleports > 0 Then
+                                       Self.Teleports :- 1
+                                       Local Location:TPointD = Self.GameScene.FindSafeLocation(20)
+
+                                       PlaySound(Self.TeleportSound)
+                                       Self.Death.X = Self.X
+                                       Self.Death.Y = Self.Y
+
+                                       For Local Pops:Int = 0 To 50
+                                               Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.SparkleImage, Rnd(360.0), Rnd(0.5,10.0), 0, 0.02, [255,255,255])
+                                               Particle.X = Self.X
+                                               Particle.Y = Self.Y
+                                               Particle.Rotation = Rnd(-1.0,1.0)
+                                               Particle.Friction = 0.97
+                                               Particle.Size = Rnd(0.1,0.2)
+                                       Next
+
+                                       Self.X = Int(Location.X)
+                                       Self.Y = Int(Location.Y)
+                                       Self.Death.X = Self.X
+                                       Self.Death.Y = Self.Y
+
+                                       For Local Pops:Int = 0 To 20
+                                               Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.SparkleImage, Rnd(360.0), Rnd(0.5,2.0), 0, 0.02, [255,255,255])
+                                               Particle.X = Self.X
+                                               Particle.Y = Self.Y
+                                               Particle.Rotation = Rnd(-1.0,1.0)
+                                               Particle.Friction = 0.97
+                                               Particle.Size = Rnd(0.1,0.2)
+                                       Next
+
+                               EndIf
+                       EndIf
+       
+                       ' COLLISION DETECT AGAINST DIGESTIVES!
+                       ' ---------------------------------------------------------
+                       For Local Item:TDigestive = EachIn Self.GameScene.Digestives
+                               If Item.Circle.CollidesWith(Self.Circle)
+                                       Self.Lives :- 1
+                                       Self.Dead = True
+                                       PlaySound(Self.CrashSound)
+       
+                                       Local PlayerSpeed:Double = Self.Speed()
+
+                                       Self.GameScene.Shake :+ PlayerSpeed / 1.5
+                                       If PlayerSpeed > 10.0
+                                               Item.SplitIntoChunks(Self.X,Self.Y,Self.Speed())
+                                       EndIf
+
+                                       Self.Death.X = Self.X
+                                       Self.Death.Y = Self.Y
+                                       For Local Pops:Int = 0 To 100
+                                               If PlayerSpeed > 10 Then PlayerSpeed = 10
+                                               Local Angle:Double = Self.Angle() + Rnd(-(80 - (8.0 * PlayerSpeed)), 80 - (8.0 * PlayerSpeed))
+                                               Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.DeathImage, Angle, Rnd(0.1, Self.Speed()), 0, 0.03, [255,255,255])
+                                               Particle.Friction = 0.98
+                                               Particle.Size = Rnd(0.1,0.7)
+                                               Particle.Color = [Rand(80,255),24,Rand(24,128)]
+                                       Next
+
+                                       For Local Pops:Int = 0 To 300
+                                               Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.DeathImage, Rnd(360.0), Rnd(0.1, 7.0), 0, Rnd(0.01,0.04), [255,255,255])
+                                               Particle.Friction = 0.99
+                                               Particle.Size = Rnd(0.1,0.4)
+                                               Particle.Color = [Rand(80,255),24,Rand(24,200)]
+                                       Next
+
+                                       Self.Reset()
+                               EndIf
+                       Next
+               EndIf
+
+       End Method
+
+       Method Reset()
+               Self.X = WIDTH / 2
+               Self.Y = HEIGHT / 2
+               Self.Acceleration = 0
+               Self.VelocityX = 0
+               Self.VelocityY = 0
+               Self.Teleports = 2
+               Self.Dead = 2
+       End Method
+
+       Method LoadAssets()
+               If Self.ThrusterImage = Null Then Self.ThrusterImage = LoadImage("graphics\bullet1.png")
+               If Self.DeathImage = Null Then Self.DeathImage = LoadImage("graphics\pop.png")
+               If Self.SparkleImage = Null Then Self.SparkleImage = LoadImage("graphics\sparkle.png")
+
+               ' Load in the sounds...
+               If Self.ThrusterSound = Null Then Self.ThrusterSound = LoadSound("sounds\thrust.wav",True)
+               If Self.CrashSound = Null Then Self.CrashSound = LoadSound("sounds\crash.wav",False)
+               If Self.TeleportSound = Null Then Self.TeleportSound = LoadSound("sounds\teleport.wav",False)
+               
+               Self.ThrusterChannel = AllocChannel()
+               Self.ThrusterChannel.SetVolume(0)
+               PlaySound(Self.ThrusterSound,Self.ThrusterChannel)
+       End Method
+
+       Function Create:TPlayer(World:TWorldPhysicsProvider, Image:TImage, GameScene:MainGameScene)
+               Local Out:TPlayer = New TPlayer
+               Out.Thruster = TFountain.Create(World, TRectangle.Create(0,0,WIDTH,HEIGHT))
+               Out.Death = TFountain.Create(World, TRectangle.Create(0,0,WIDTH,HEIGHT))
+               Out.GameScene = GameScene
+               Out.Circle.Radius = 10
+               Out.World = World
+               Out.Image = Image
+               Out.Friction = 0.985
+               Out.Reset()
+               Return Out
+       End Function
+
+End Type
+Type TBullet Extends TPhysicsProvider
+
+       Field Image:TImage
+       Field Circle:TCircle = New TCircle
+       Field GameScene:MainGameScene
+       Field Size:Float = 1.0
+       Field ScoreMultiplier:Float = 1
+       Field TTL:Int
+       Field Fading:Float = 1.0
+
+       Const TIME_TO_LIVE = 100
+
+       Method Draw()
+               SetScale(Self.Size,Self.Size)
+               SetAlpha(Self.Fading)
+               DrawImage(Self.Image, Self.X, Self.Y)
+       End Method
+
+       Method PhysicsApplied()
+               Local HalfWidth:Int = (Image.Width / 2)
+               Local HalfHeight:Int = (Image.Height / 2)
+               If X < -HalfWidth Then X = WIDTH + HalfWidth
+               If Y < -HalfHeight Then Y = HEIGHT + HalfHeight
+               If X > WIDTH + HalfWidth Then X = -HalfWidth
+               If Y > HEIGHT + HalfHeight Then Y = -HalfHeight
+
+               ' Shall we kill it off?
+               Self.TTL :+ 1
+               If Self.TTL > TIME_TO_LIVE Then
+                       Self.Fading :- 0.015
+                       If Self.Fading < 0.05
+                               Self.GameScene.Bullets.Remove(Self)
+                       EndIf
+               EndIf
+               
+'              If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then 
+       '               ' Bullet went off't screen
+               '       Self.GameScene.Bullets.Remove(Self)
+       '       EndIf
+
+               Self.Circle.X = Self.X
+               Self.Circle.Y = Self.Y
+
+               ' COLLISION DETECT AGAINST DIGESTIVES!
+               ' ---------------------------------------------------------
+               For Local Item:TDigestive = EachIn Self.GameScene.Digestives
+                       If Item.Circle.CollidesWith(Self.Circle)
+                               If Self.Fading > 0.5
+                                       Self.GameScene.Bullets.Remove(Self)
+                                       Item.SplitIntoChunks(Self.Circle.X,Self.Circle.Y,Self.ScoreMultiplier)
+                                       Exit
+                               EndIf
+                       EndIf
+               Next
+       End Method
+
+       Function Create:TBullet(World:TWorldPhysicsProvider, Image:TImage, Player:TPlayer, Speed:Float, GameScene:MainGameScene, Size:Float, Radius:Float, Veer:Float)
+               Local Out:TBullet = New TBullet
+               Out.GameScene = GameScene
+               Out.SetVelocityFromAngle(Player.Rotation + Rnd(-Veer,Veer),Speed)
+               Out.Size = Size
+               Out.Circle.Radius = Radius * Size
+               Out.X = Player.X
+               Out.Y = Player.Y
+               Out.World = World
+               Out.Image = Image
+               Return Out
+       End Function
+
+End Type
+Type TStar Extends TPhysicsProvider
+
+       Field Color[]
+       Field GameScene:MainGameScene
+       
+       Method Draw()
+               SetColor Self.Color[0],Self.Color[1],Self.Color[2]
+               DrawRect(X,Y,1,1)
+       End Method
+
+       Method PhysicsApplied()
+               Self.VelocityX :* 1.01
+               Self.VelocityY :* 1.01
+       
+               Local HalfWidth:Int = 5
+               Local HalfHeight:Int = 5
+               If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then 
+                       ' Bullet went off't screen
+                       Self.GameScene.Stars.Remove(Self)
+               EndIf
+       End Method
+
+       Function Create:TStar(World:TWorldPhysicsProvider,GameScene:MainGameScene, Speed:Float)
+               Local Out:TStar = New TStar
+               Local Pigment = Rand(24,255)
+               Out.GameScene = GameScene
+               Out.Color = [Pigment,Pigment,Pigment]
+               Out.SetVelocityFromAngle(Rnd(360),Rnd(0.2,0.9) * Speed)
+               Out.X = WIDTH / 2
+               Out.Y = HEIGHT / 2
+               Out.World = World
+               Return Out
+       End Function
+
+End Type
+Type TMenuStar Extends TPhysicsProvider
+
+       Field Color[]
+       Field MenuScene:MainMenuScene
+       
+       Method Draw()
+               SetColor Self.Color[0],Self.Color[1],Self.Color[2]
+               DrawRect(X,Y,1,1)
+       End Method
+
+       Method PhysicsApplied()
+'              Self.VelocityX :* 1.01
+'              Self.VelocityY :* 1.01
+       
+               Local HalfWidth:Int = 5
+               Local HalfHeight:Int = 5
+               If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then 
+                       ' Bullet went off't screen
+                       Self.MenuScene.Stars.Remove(Self)
+               EndIf
+       End Method
+
+       Function Create:TMenuStar(World:TWorldPhysicsProvider,MenuScene:MainMenuScene, Speed:Float)
+               Local Out:TMenuStar = New TMenuStar
+               Local Pigment = Rand(24,255)
+               Out.MenuScene = MenuScene
+               Out.Color = [Pigment,Pigment,Pigment]
+               Out.SetVelocityFromAngle(90,Rnd(0.2,0.9) * Speed)
+               Out.X = 0
+               Out.Y = Rnd(HEIGHT)
+               Out.World = World
+               Return Out
+       End Function
+
+End Type
+Type TEndingStar Extends TPhysicsProvider
+
+       Field Color[]
+       Field EndScene:EndingScene
+       
+       Method Draw()
+               SetColor Self.Color[0],Self.Color[1],Self.Color[2]
+               DrawRect(X,Y,1,1)
+       End Method
+
+       Method PhysicsApplied()
+'              Self.VelocityX :* 1.01
+'              Self.VelocityY :* 1.01
+       
+               Local HalfWidth:Int = 5
+               Local HalfHeight:Int = 5
+               If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then 
+                       ' Bullet went off't screen
+                       Self.EndScene.Stars.Remove(Self)
+               EndIf
+       End Method
+
+       Function Create:TEndingStar(World:TWorldPhysicsProvider, EndScene:EndingScene, Speed:Float, X:Int, Y:Int)
+               Local Out:TEndingStar = New TEndingStar
+               Local Pigment = Rand(24,255)
+               Out.EndScene = EndScene
+               Out.Color = [Pigment,Pigment,Pigment]
+               Out.X = X
+               Out.Y = Y
+               Out.World = World
+               Return Out
+       End Function
+
+End Type
+Type TPickup Extends TLink
+
+       Const MODIFIER_SCORE = 0
+       Const MODIFIER_LIVES = 1 
+       Const MODIFIER_ROTATION = 2 
+       Const MODIFIER_PSYCHODELIC = 3
+       Const MODIFIER_WEAPON = 4
+
+       Field Modifies:Int = MODIFIER_SCORE
+       Field ByValue:Float
+       Field LastsFor:Int
+       Field Time:Int
+       Field IsPermanent:Int = False
+       Field Weapon:TWeapon
+       Field Icon:TImage
+       Field Probability:Double
+       Field OwnedIcon:TImage
+
+       Method Clone:TPickup()
+               Local Out:TPickup = New TPickup
+               Out.Modifies = Self.Modifies
+               Out.ByValue = Self.ByValue
+               Out.LastsFor = Self.LastsFor
+               Out.IsPermanent = Self.IsPermanent
+               Out.Weapon = Self.Weapon
+               Out.Icon = Self.Icon
+               Out.Probability = Self.Probability
+               Out.OwnedIcon = Out.OwnedIcon
+               Return Out
+       End Method
+
+       Function Create:TPickup(Modifies:Int,ByValue:Float,LastsFor:Int,IsPermanent:Int,Weapon:TWeapon,Icon:TImage,Probability:Double,OwnedIcon:TImage)
+               Local Out:TPickup = New TPickup
+               Out.Modifies = Modifies
+               Out.ByValue = ByValue
+               Out.LastsFor = LastsFor
+               Out.IsPermanent = IsPermanent
+               Out.Weapon = Weapon
+               Out.Icon = Icon
+               Out.Probability = Probability
+               Out.OwnedIcon = OwnedIcon
+               Return Out
+       End Function
+
+End Type
+Type TWeapon Extends TLink
+
+       Field Speed:Float
+       Field Graphic:TImage
+       Field Size:Float
+       Field Radius:Float
+       Field Veer:Float
+       Field FireRate:Int
+       Field MainGame:MainGameScene
+       Field Sound:TSound
+       Field Name:String
+       Field Icon:TImage
+
+       Method Fire(Player:TPlayer)
+               Local Shot:TBullet = TBullet.Create(MainGame.World, Self.Graphic, Player, Self.Speed + Player.Speed(), Self.MainGame, Self.Size, Self.Radius, Self.Veer)
+               Shot.ScoreMultiplier = (Player.Speed() * 4.0)
+               If Shot.ScoreMultiplier < 1.0 Then Shot.ScoreMultiplier = 1.0
+               Self.MainGame.Bullets.AddLast(Shot)
+               PlaySound(Self.Sound)
+       End Method
+
+       Function Create:TWeapon(Speed:Float,Graphic:TImage,Size:Float,Radius:Float,Veer:Float,FireRate:Int,MainGame:MainGameScene,Sound:TSound,Icon:TImage,Name:String)
+               Local Out:TWeapon = New TWeapon
+               Out.Speed = Speed
+               Out.Graphic = Graphic
+               Out.Size = Size
+               Out.Radius = Radius
+               Out.Veer = Veer
+               Out.FireRate = FireRate
+               Out.MainGame = MainGame
+               Out.Sound = Sound
+               Out.Icon = Icon
+               Out.Name = Name
+               Return Out
+       End Function
+
+End Type
+Type TEndMagnet Extends TMagnet
+       
+       Field Stars:Int
+       
+End Type
+Type THighScores
+
+       Const SCORE_COUNT = 10
+       Field Scores:Int[SCORE_COUNT]
+       Field Names:String[SCORE_COUNT]
+
+       Method Render(X:Int, Y:Int)
+               For Local Count:Int = 0 To SCORE_COUNT - 1
+                       DrawText(Self.Names[Count], X,Y + (Count * 20))
+               Next
+
+               For Local Count2:Int = 0 To SCORE_COUNT - 1
+                       DrawText(Self.Scores[Count2], X + 200,Y + (Count2 * 20))
+               Next
+       End Method
+
+       Method IsHighScore:Int(Score:Int)
+               For Local Count:Int = 0 To SCORE_COUNT - 1
+                       If Score > Self.Scores[Count] Then
+                               Return True
+                       EndIf
+               Next
+               Return False
+       End Method
+       
+       Method Add(Score:Int,Name:String)
+               ' Find out where we should put the score..
+               Local PlaceAt:Int = SCORE_COUNT - 1
+               For Local Count:Int = SCORE_COUNT - 1 To 0 Step -1
+                       If Score > Self.Scores[Count] Then
+                               PlaceAt = Count
+                       EndIf
+               Next
+
+               ' Shuffle them all down..
+               For Local Shuffle:Int = SCORE_COUNT - 2 To PlaceAt Step -1
+                       Self.Scores[Shuffle + 1] = Self.Scores[Shuffle]
+                       Self.Names[Shuffle + 1] = Self.Names[Shuffle]
+               Next
+
+               Self.Scores[PlaceAt] = Score
+               Self.Names[PlaceAt] = Name
+       End Method
+
+       Method Save(File:String)
+               Local Out:TStream = OpenStream(File,False,True)
+               If Out <> Null
+                       For Local Count:Int = 0 To SCORE_COUNT - 1
+                               WriteInt(Out,Self.Scores[Count])
+                               WriteLine(Out,Self.Names[Count])
+                       Next
+                       CloseStream(Out)
+               EndIf
+       End Method
+
+       Function Load:THighScores(File:String)
+               Local In:TStream = OpenStream(File,True,False)
+               Local Out:THighScores = New THighScores
+               If In = Null
+                       ' Fill it full of high scores..
+                       Out.Names[0] = "Loki"
+                       Out.Names[1] = "Booty"
+                       Out.Names[2] = "Rix"
+                       Out.Names[3] = "Jamez"
+                       Out.Names[4] = "Pies"
+                       Out.Names[5] = "Bobny"
+                       Out.Names[6] = "Berty"
+                       Out.Names[7] = "Billy"
+                       Out.Names[8] = "Bonny"
+                       Out.Names[9] = "Boxer"
+
+                       Out.Scores[0] = 100000
+                       Out.Scores[1] = 80000
+                       Out.Scores[2] = 50000
+                       Out.Scores[3] = 40000
+                       Out.Scores[4] = 30000
+                       Out.Scores[5] = 20000
+                       Out.Scores[6] = 10000
+                       Out.Scores[7] = 5000
+                       Out.Scores[8] = 4000
+                       Out.Scores[9] = 1000
+               Else
+                       For Local Count:Int = 0 To SCORE_COUNT - 1
+                               Out.Scores[Count] = ReadInt(In)
+                               Out.Names[Count] = ReadLine(In)
+                       Next
+                       CloseStream(In)
+               EndIf
+               Return Out
+       End Function
+
+End Type
+
+' Main game setup.
+' ------------------------
+Local Game:T2DDynamicGame = T2DDynamicGame.Create(WIDTH, HEIGHT, DEPTH, REFRESHRATE)
+Global Scores:THighScores = THighScores.Load("hi.dat")
+Game.DynamicTiming = DYNAMICTIMING
+Game.DesiredFPS = DESIREDFPS
+Game.Initialize()      ' Go into graphics mode.
+
+HideMouse
+
+' Create the main game scene.
+Local MenuScene:MainMenuScene = New MainMenuScene
+Local GameScene:MainGameScene = New MainGameScene
+Local EndScene:EndingScene = New EndingScene
+
+Local QuitFlag:Int = False
+
+While Not QuitFlag
+       ' Attach The Game Scene To The Dynamic Game.
+       Game.Setscene(Menuscene)
+       
+       ' Start The Main Loop.
+       Game.Mainloop()
+
+       If Not MenuScene.Exitgame
+               If MenuScene.ShowCredits
+                       MenuScene.ShowCredits = False
+                       Game.SetScene(EndScene)
+                       Game.Mainloop()
+               Else
+                       Game.Setscene(GameScene)
+                       Game.Mainloop()
+
+                       QFlushKeys()
+
+                       If GameScene.Completed
+                               GameScene.Completed = False
+                               Game.SetScene(EndScene)
+                               Game.Mainloop()
+                       EndIf
+
+                       QFlushKeys()
+
+                       ' Check for high score.
+                       If Scores.IsHighScore(GameScene.Player.Score) Then
+                               ' We got a high score.
+                               MenuScene.ViewMenu(MenuScene.VIEW_ENTERHIGH)
+                               MenuScene.LastHighScore = GameScene.Player.Score
+                               MenuScene.EnteredText = ""
+                       EndIf
+
+               EndIf
+       Else
+               QuitFlag = True
+       EndIf
+Wend
+
+Scores.Save("hi.dat")
+
+' Clean up after we shut down.
+Game.ShutDown()
+
+' Fin
+
+Const DEBUG = True
+Function DebugLog(Text:String)
+       If DEBUG Then Print Text
+End Function
+
+
+
+
+
+
diff --git a/samples/digesteroids/dynamicgame.bmx b/samples/digesteroids/dynamicgame.bmx
new file mode 100644 (file)
index 0000000..652826c
--- /dev/null
@@ -0,0 +1,203 @@
+' *******************************************************************
+' Source: Dynamic Game 
+' Version: 1.00
+' Author: Rob Hutchinson 2004
+' Email: rob@proteanide.co.uk
+' WWW: http://www.proteanide.co.uk/
+' -------------------------------------------------------------------
+' This include provides an OO approach to game creation. You must
+' first instantiate the T2DDynamicGame class with the Create()
+' method. This controls the game itself, including the main loop.
+' You do not need to inherit T2DDynamicGame. Instead, create types
+' and inherit from T2DDynamicGameScene, this class is used to process
+' a single game scene, such as the main menu or the game itself. You
+' might have types that inherit T2DDynamicGame for the Main Menu,
+' Levels of your game, Bonus levels, credits, menu screens, etc. 
+' The functionality is built into each type in the Update and Render
+' methods. Always perform logic operations in the Update method and
+' draw your graphics in the standard way inside Render(). This way
+' your game will automatically benefit from dynamic game timing. To
+' Swap the scene from say, the Main Menu to the game itself, simply 
+' call the SetScene() Method on T2DDynamicGame with your new scene.
+' -------------------------------------------------------------------
+' Benefits/Features:
+'  - The T2DDynamicGame class handles pretty much everything to do
+'    with the game loop for you, it has a dynamic timing routine 
+'    built into it which will catch up with missing frames.
+'  - Allows you to easily run at a specific visual framerate 
+'    (DesiredFPS) regardless of the refresh rate.
+' -------------------------------------------------------------------
+' Required:
+'  - minitimer.bmx   - Timer framework.
+' *******************************************************************
+
+Import "minitimer.bmx"
+
+Type T2DDynamicGame
+
+       ' PRIVATE
+       Field Scene:T2DDynamicGameScene
+       Field EndMainLoop:Int = False
+       Field DesiredFPS:Int = 60
+       Field TerminateMainLoop:Int = False
+       Field DynamicTiming:Int = True       ' If true dynamic timing is uses, else frame limited timing is used.
+
+       ' PUBLIC
+       Field Width:Int = 1024
+       Field Height:Int = 768
+       Field Depth:Int = 32
+       Field RefreshRate:Int = 60
+
+'#Region Constructor: Create
+       Function Create:T2DDynamicGame(Width:Int,Height:Int,Depth:Int,RefreshRate:Int)
+               Local Out:T2DDynamicGame = New T2DDynamicGame
+               Out.Width = Width
+               Out.Height = Height
+               Out.Depth = Depth
+               Out.RefreshRate = RefreshRate
+               Return Out
+       End Function
+'#End Region
+
+'#Region Method: Initialize
+       Method Initialize()
+               ' Set up the graphics.
+               Graphics(Self.Width, Self.Height, Self.Depth, Self.RefreshRate)
+       End Method
+'#End Region
+'#Region Method: ShutDown
+       Method ShutDown()
+               ' Close down the graphics.
+               Self.FlushScene()
+               EndGraphics()
+       End Method
+'#End Region
+'#Region Method: SetScene
+       Method SetScene(Scene:T2DDynamicGameScene)
+               ' Set a new scene into the game.
+               Self.FlushScene()
+               Self.Scene = Scene
+               Self.Scene.Start()
+       End Method
+'#End Region
+'#Region Method: MainLoop
+       Method MainLoop()
+               ' Repeat the main loop until termination is required.
+               ' Taken from my .NET game framework codenamed: Lita, for more info drop me a line! :) </PLUG>
+               If Self.DynamicTiming = True
+                       ' Dynamic timing.
+               Local WaitUntil:Int
+                       Local Timer:MiniTimer = New MiniTimer
+               Timer.Reset()
+
+                       Local Period:Int = 1000 / Self.DesiredFPS
+               Local Gap:Int
+               Local UpdatesUntil:Float
+       
+               WaitUntil = MilliSecs() + Period
+               While (Not TerminateMainLoop) And (Not Self.IsTerminated())
+       
+                   ' Loop until time has passed.
+                   Repeat
+                   Until MilliSecs() > WaitUntil
+
+                   ' Update for as many times frames were missed.
+                               ' First we need to calculate some stats.
+                   Gap = (MilliSecs() - Timer.TimeStarted)
+                   UpdatesUntil = Float(Gap) / Float(Period)
+
+                               ' Perform the updates.
+                   If UpdatesUntil > 1.0 Then
+                       For Local Count:Int = 1 To Int(UpdatesUntil)
+                           Self.Update()
+                       Next
+                               End If
+       
+                               ' Reset our timer to start the next run.
+                   Timer.Reset()
+                   WaitUntil = MilliSecs() + Period
+                   Self.Render()
+                               Flip()
+'                              GCCollect
+                   'Application.DoEvents()
+               Wend
+               Else
+                       ' Frame limited tbiming.
+               While (Not TerminateMainLoop) And (Not Self.IsTerminated())
+                               Self.Update()
+                               Self.Render()
+                               Flip()
+'                              GCCollect
+               Wend
+               EndIf
+               Self.TerminateMainLoop = False
+
+       End Method
+'#End Region
+'#Region Method: FlushScene
+       Method FlushScene()
+               ' If there is a scene then we need to kill it off..
+               Self.Finish()
+               Self.Scene = Null
+       End Method
+'#End Region
+'#Region Method: Start
+       Method Start()
+               ' Call start on the scene.
+               If Self.Scene <> Null Then Self.Scene.Start()
+       End Method
+'#End Region
+'#Region Method: Finish
+       Method Finish()
+               ' Call start on the scene.
+               If Self.Scene <> Null Then 
+                       Self.Scene.Finish()
+               EndIf
+       End Method
+'#End Region
+'#Region Method: Update
+       Method Update()
+               ' Call update on the scene.
+               If Self.Scene <> Null Then Self.Scene.Update()
+       End Method
+'#End Region
+'#Region Method: Render
+       Method Render()
+               ' Call render on the scene.
+               If Self.Scene <> Null Then Self.Scene.Render()
+       End Method
+'#End Region
+'#Region Method: IsTerminated
+       Method IsTerminated:Int()
+               ' Check to see if the scene wants to terminate the main loop.
+               If Self.Scene <> Null Then
+                       If Self.Scene.TerminateMainLoop Then
+                               Self.Scene.TerminateMainLoop = False
+                               Return True
+                       EndIf
+                       Return False
+               EndIf
+               Return True
+       End Method
+'#End Region
+
+End Type
+
+Type T2DDynamicGameScene
+
+       Field TerminateMainLoop:Int = False     
+
+       Method Update() Abstract
+       Method Render() Abstract
+       Method Start() Abstract
+       Method Finish() Abstract
+
+End Type
+
+
+
+
+
+
+
+
diff --git a/samples/digesteroids/graphics/bullet1.png b/samples/digesteroids/graphics/bullet1.png
new file mode 100644 (file)
index 0000000..46e2e2a
Binary files /dev/null and b/samples/digesteroids/graphics/bullet1.png differ
diff --git a/samples/digesteroids/graphics/bullet2.png b/samples/digesteroids/graphics/bullet2.png
new file mode 100644 (file)
index 0000000..e09794e
Binary files /dev/null and b/samples/digesteroids/graphics/bullet2.png differ
diff --git a/samples/digesteroids/graphics/digestive.png b/samples/digesteroids/graphics/digestive.png
new file mode 100644 (file)
index 0000000..eb5ee48
Binary files /dev/null and b/samples/digesteroids/graphics/digestive.png differ
diff --git a/samples/digesteroids/graphics/lower.png b/samples/digesteroids/graphics/lower.png
new file mode 100644 (file)
index 0000000..602e96f
Binary files /dev/null and b/samples/digesteroids/graphics/lower.png differ
diff --git a/samples/digesteroids/graphics/options.png b/samples/digesteroids/graphics/options.png
new file mode 100644 (file)
index 0000000..436c76c
Binary files /dev/null and b/samples/digesteroids/graphics/options.png differ
diff --git a/samples/digesteroids/graphics/piece1.png b/samples/digesteroids/graphics/piece1.png
new file mode 100644 (file)
index 0000000..f790943
Binary files /dev/null and b/samples/digesteroids/graphics/piece1.png differ
diff --git a/samples/digesteroids/graphics/piece2.png b/samples/digesteroids/graphics/piece2.png
new file mode 100644 (file)
index 0000000..51e72e0
Binary files /dev/null and b/samples/digesteroids/graphics/piece2.png differ
diff --git a/samples/digesteroids/graphics/piece3.png b/samples/digesteroids/graphics/piece3.png
new file mode 100644 (file)
index 0000000..dae3207
Binary files /dev/null and b/samples/digesteroids/graphics/piece3.png differ
diff --git a/samples/digesteroids/graphics/pop.png b/samples/digesteroids/graphics/pop.png
new file mode 100644 (file)
index 0000000..0d768a7
Binary files /dev/null and b/samples/digesteroids/graphics/pop.png differ
diff --git a/samples/digesteroids/graphics/ship.png b/samples/digesteroids/graphics/ship.png
new file mode 100644 (file)
index 0000000..53cc063
Binary files /dev/null and b/samples/digesteroids/graphics/ship.png differ
diff --git a/samples/digesteroids/graphics/sparkle.png b/samples/digesteroids/graphics/sparkle.png
new file mode 100644 (file)
index 0000000..7dd3851
Binary files /dev/null and b/samples/digesteroids/graphics/sparkle.png differ
diff --git a/samples/digesteroids/graphics/stars.png b/samples/digesteroids/graphics/stars.png
new file mode 100644 (file)
index 0000000..c4ededa
Binary files /dev/null and b/samples/digesteroids/graphics/stars.png differ
diff --git a/samples/digesteroids/graphics/title.png b/samples/digesteroids/graphics/title.png
new file mode 100644 (file)
index 0000000..ec26ff9
Binary files /dev/null and b/samples/digesteroids/graphics/title.png differ
diff --git a/samples/digesteroids/minitimer.bmx b/samples/digesteroids/minitimer.bmx
new file mode 100644 (file)
index 0000000..e2f6746
--- /dev/null
@@ -0,0 +1,72 @@
+' *******************************************************************
+' Source: Mini Timer 
+' Version: 1.00
+' Author: Rob Hutchinson 2004
+' Email: rob@proteanide.co.uk
+' WWW: http://www.proteanide.co.uk/
+' -------------------------------------------------------------------
+' This include provides a class for a timer object. The class works
+' in milliseconds. First of all the object can be enabled and 
+' disabled at will by setting the Enabled field
+' to true or false. The Interval field can be set
+' to mark a milliseconds interval that, when reached, IntervalReached
+' will become true. You can use the Reset() method to reset the timer
+' and MiillisecondsElapsed() will tell you the number of milliseconds
+' that have passed since you called Reset. Enabled field only has
+' any effect on the IntervalReached function of the timer. If false
+' then the method will always return false.
+' Ported directly from my .NET Framework game library: Lita.
+' -------------------------------------------------------------------
+' Required:
+'  - Nothing.
+' *******************************************************************
+
+Type MiniTimer
+
+'#Region Declarations
+        Field TimeStarted:Int
+        Field Interval:Int
+        Field Enabled:Int = True
+'#End Region
+
+'#Region Method: Reset
+        '''-----------------------------------------------------------------------------
+        ''' <summary>
+        ''' Resets the timer.
+        ''' </summary>
+        '''-----------------------------------------------------------------------------
+        Method Reset()
+            Self.TimeStarted = MilliSecs()
+        End Method
+'#End Region
+'#Region Method: MiillisecondsElapsed
+        '''-----------------------------------------------------------------------------
+        ''' <summary>
+        ''' Gets the number of milliseconds that have passed since a call to Reset.
+        ''' </summary>
+        '''-----------------------------------------------------------------------------
+        Method MiillisecondsElapsed:Int()
+            If Self.TimeStarted = 0 Then Return 0
+            Local TimeNow:Int = MilliSecs()
+            Return TimeNow - Self.TimeStarted
+        End Method
+'#End Region
+'#Region Method: IntervalReached
+        '''-----------------------------------------------------------------------------
+        ''' <summary>
+        ''' Returns true if the given interval has been reached.
+        ''' </summary>
+        '''-----------------------------------------------------------------------------
+        Method IntervalReached:Int()
+            If Self.Enabled Then Return (Self.MiillisecondsElapsed() > Self.Interval)
+        End Method
+'#End Region
+
+End Type
+
+
+
+
+
+
+
diff --git a/samples/digesteroids/simplephysics.bmx b/samples/digesteroids/simplephysics.bmx
new file mode 100644 (file)
index 0000000..65c0196
--- /dev/null
@@ -0,0 +1,593 @@
+' Simple Physics Engine - V1.0
+' --------------------------------------------------------
+' Written By: Rob Hutchinson 2004
+
+Strict
+
+Type TRectangle
+
+'#Region Declarations
+       Field X:Int,Y:Int,Width:Int,Height:Int
+'#End Region
+
+'#Region Method: Bottom
+       Method Bottom:Int()
+               Return Y + Height
+       End Method
+'#End Region
+'#Region Method: Right
+       Method Right:Int()
+               Return X + Width
+       End Method
+'#End Region
+'#Region Method: Create
+       Function Create:TRectangle(X:Int,Y:Int,Width:Int,Height:Int)
+               Local Out:TRectangle = New TRectangle
+               Out.X = X
+               Out.Y = Y
+               Out.Width = Width
+               Out.Height = Height
+               Return Out
+       End Function
+'#End Region
+
+'#Region Method: IntersectsWith
+       Method IntersectsWith:Int(Rectangle:TRectangle)
+               If (((Rectangle.X < (Self.X + Self.Width)) And (Self.X < (Rectangle.X + Rectangle.Width))) And (Rectangle.Y < (Self.Y + Self.Height))) Then
+                       Return (Self.Y < (Rectangle.Y + Rectangle.Height)) 
+               End If
+               Return False
+       End Method
+'#End Region
+
+End Type
+
+Type TPhysicsUtility
+
+'#Region Method: DistanceBetweenPoints
+    Function DistanceBetweenPoints:Double(X1:Int, Y1:Int, X2:Int, Y2:Int)
+        Local DeltaX:Int = X2 - X1
+        Local DeltaY:Int = Y2 - Y1
+        Local Calculation:Int = ((DeltaX * DeltaX) + (DeltaY * DeltaY))
+        Return Sqr(Double(Calculation))
+    End Function
+'#End Region
+
+    Function DegreesBetweenPoints(X1:Double, Y1:Double, X2:Double, Y2:Double)
+               Local Out:Double = ATan2(X2 - X1,-(Y2 - Y1))
+        Return 180.0 - Out
+    End Function
+
+End Type
+
+Type TPointD
+       
+'#Region Declarations
+       Field X:Double = 0
+       Field Y:Double = 0
+'#End Region
+
+End Type
+
+Type TMagnetCollection Extends TList
+
+'#Region Method: Draw
+       Method Draw()
+               Local Item:TMagnet
+               For Item=EachIn Self
+                       Item.Draw()
+               Next
+       End Method      
+'#End Region
+
+End Type
+
+Type TPhysicsProviderCollection Extends TList
+
+'#Region Method: Draw
+       Method Draw()
+               Local Item:TPhysicsProvider
+               For Item=EachIn Self
+                       Item.Draw()
+               Next
+End Method
+'#End Region
+'#Region Method: ApplyPhysics
+       Method ApplyPhysics:Int()
+               Local Item:TPhysicsProvider
+               Local Count:Int
+               For Item=EachIn Self
+                       Item.ApplyPhysics()
+                       Count:+1
+               Next
+               Return Count
+       End Method
+'#End Region
+'#Region Method: ApplyPhysicsAndFriction
+       Method ApplyPhysicsAndFriction:Int(Axis:Int)
+               Local Item:TPhysicsProvider
+               Local Count:Int
+               For Item=EachIn Self
+            Item.ApplyFriction(Axis)
+                       Item.ApplyPhysics()
+                       Item.Draw()
+                       Count:+1
+               Next
+               Return Count
+       End Method
+'#End Region
+'#Region Method: ApplyPhysicsAndDraw
+       Method ApplyPhysicsAndDraw()
+               Local Item:TPhysicsProvider
+               For Item=EachIn Self
+                       Item.ApplyPhysics()
+                       Item.Draw()
+               Next
+End Method
+'#End Region
+
+End Type
+
+Type TMagnet
+'#Region Declarations
+       Field X:Int, Y:Int
+       Field Radius:Double
+
+       Const NegativePolarity = -1
+       Const PositivePolarity = 1
+
+       Field Strength:Double
+       Field Polarity:Int = 1
+'#End Region
+
+
+
+'#Region Method: GetStrengthOfPull
+       Method GetStrengthOfPull:Double(Orbit:Double)
+        If Orbit > Self.Radius Then Return 0
+
+        ' First work out the percentage...
+        Local PercentOfPull:Double = (Orbit / Self.Radius) * 100
+        Return Self.Strength - ((PercentOfPull / 100) * Self.Strength)
+       End Method
+'#End Region
+'#Region Method: GetForces
+       Method GetForces:TPointD(X:Int, Y:Int)
+        Local Out:TPointD=New TPointD
+               Out.X = 0
+               Out.Y = 0
+
+               ' Get Distance Between Points...
+               Local Distance:Double = TPhysicsUtility.DistanceBetweenPoints(X, Y, Self.X, Self.Y)
+               Local Strength:Double = Self.GetStrengthOfPull(Distance)
+        If Strength = 0 Then Return Out
+
+               ' Get the degrees between points..
+               Local Angle:Double = TPhysicsUtility.DegreesBetweenPoints(X, Y,Self.X, Self.Y)
+
+               ' Reverse strength if using negative polarity.        
+        If Self.Polarity = NegativePolarity Then Strength = -Strength
+
+               Out.X = Sin(Angle) * Strength
+        Out.Y = Cos(Angle) * Strength
+
+        Return Out
+       End Method
+'#End Region
+'#Region Method: Draw
+    Method Draw()
+               Local Degrees
+               SetColor 255,255,255
+               For Degrees = 0 To 360
+                       DrawRect Self.X + (Sin(Degrees) * Self.Radius), Self.Y + (Cos(Degrees) * Self.Radius),1,1
+               Next
+    End Method
+'#End Region
+'#Region Method: Create
+       Function Create:TMagnet(X:Int,Y:Int,Radius:Double,Polarity:Int,Strength:Double)
+               Local Out:TMagnet = New TMagnet
+               Out.X = X
+               Out.Y = Y
+               Out.Radius = Radius
+               Out.Polarity = Polarity
+               Out.Strength = Strength
+               Return Out
+       End Function
+'#End Region
+'#Region Method: SetPosition
+       Method SetPosition(X:Int,Y:Int)
+               Self.X = X
+               Self.Y = Y
+       End Method
+'#End Region
+
+End Type
+
+Type TWorldPhysicsProvider 
+
+       Field Loc = 0
+
+'#Region Declarations
+       Field Gravity:Double
+       Field Wind:Double
+       Field Drag:Double
+       Field ApplyMagnets:Int = True
+       Field Magnets:TMagnetCollection = New TMagnetCollection
+'#End Region
+
+'#Region Method: Initialize
+       Method Initialize(Gravity:Double, Wind:Double = 0.0, Drag:Double = 0.0, ApplyMagnets:Int = False)
+               Self.Gravity = Gravity
+               Self.Wind = Wind
+               Self.Drag = Drag
+               Self.ApplyMagnets = ApplyMagnets
+       End Method
+'#End Region
+'#Region Method: Create
+       Function Create:TWorldPhysicsProvider(Gravity:Double, Wind:Double = 0.0, Drag:Double = 0.0, ApplyMagnets:Int = False)
+               Local Out:TWorldPhysicsProvider = New TWorldPhysicsProvider
+               Out.Gravity = Gravity
+               Out.Wind = Wind
+               Out.Drag = Drag
+               Out.ApplyMagnets = ApplyMagnets
+               Return Out
+       End Function
+'#End Region
+
+End Type
+
+Type TPhysicsProvider Extends TLink
+'#Region Declarations
+       ' Location.
+       Field X:Double, Y:Double
+       Field World:TWorldPhysicsProvider = New TWorldPhysicsProvider
+
+       ' Terminal Velocity
+       Field TerminalVelocityX:Double = 40.0, TerminalVelocityY:Double = 40.0
+
+       ' Velocity
+       Field VelocityX:Double, VelocityY:Double
+
+       ' Weight
+       Field Weight:Double = 10.0
+       Field SurfaceArea:Double = 10.0
+
+       ' Bounce Values.
+    Field BounceCoefficientX:Double = 1.0
+    Field BounceCoefficientY:Double = 0.75
+
+       ' The friction being applied to this object.
+    Field Friction:Double = 1.0
+
+       ' Whether or not to apply magnets to the individual object.
+       Field ApplyMagnets:Int = True
+
+       Const AxisX:Int = 1
+       Const AxisY:Int = 2
+
+       Const VerticalPlane = 1
+       Const HorizontalPlane = 2
+'#End Region
+
+'      Method remove()
+'              World.remove Self
+'      End Method
+
+'#Region Method: Double
+       Method Speed:Double()
+               Return Sqr((Self.VelocityX * Self.VelocityX) + (Self.VelocityY * Self.VelocityY))
+       End Method
+'#End Region
+'#Region Method: Momentum
+       Method Momentum:Double()
+               Return Self.Speed() * Self.Weight
+       End Method
+'#End Region
+'#Region Method: ReverseVelocityX
+       Method ReverseVelocityX()
+               Self.VelocityX = -Self.VelocityX
+       End Method
+'#End Region
+'#Region Method: ReverseVelocityY
+       Method ReverseVelocityY()
+               Self.VelocityY = -Self.VelocityY
+       End Method
+'#End Region
+'#Region Method: SnapWithinRectangle
+       Method SnapWithinRectangle(Area:TRectangle)
+        If Self.X < Area.X Then Self.X = Area.X
+        If Self.Y < Area.Y Then Self.Y = Area.Y
+               Local Right:Int  = Area.X + Area.Width
+               Local Bottom:Int = Area.Y + Area.Height
+        If Self.X > Right Then Self.X = Right
+        If Self.Y > Bottom Then Self.Y = Bottom
+       End Method
+'#End Region
+'#Region Method: SnapWithinRectangleAndReverseVelocity
+       Method SnapWithinRectangleAndReverseVelocity:Int(Area:TRectangle)
+               Local Out:Int = False
+        If Self.X < Area.X Then
+            Self.X = Area.X
+            Self.ReverseVelocityX()
+            Out = True
+        End If
+        If Self.Y < Area.Y Then
+            Self.Y = Area.Y
+            Self.ReverseVelocityY()
+            Out = True
+        End If
+               Local Right:Int  = Area.X + Area.Width
+               Local Bottom:Int = Area.Y + Area.Height
+        If Self.X > Right Then
+            Self.X = Right
+            Self.VelocityX = -Self.VelocityX
+            Out = True
+        End If
+        If Self.Y > Bottom Then
+            Self.Y = Bottom
+            Self.VelocityY = -Self.VelocityY
+            Out = True
+        End If
+        Return Out
+       End Method
+'#End Region
+'#Region Method: ApplyFriction
+       Method ApplyFriction(Axis:Int)
+        If ((Axis & AxisX) = AxisX) Then Self.VelocityX:*Self.Friction
+        If ((Axis & AxisY) = AxisY) Then Self.VelocityY:*Self.Friction
+       End Method
+'#End Region
+'#Region Method: ApplyFrictionX
+       Method ApplyFrictionX()
+               Self.VelocityX:*Self.Friction
+       End Method
+'#End Region
+'#Region Method: ApplyFrictionY
+       Method ApplyFrictionY()
+               Self.VelocityY:*Self.Friction
+       End Method
+'#End Region
+'#Region Method: Bounce
+       Method Bounce(Planes:Int)
+        If ((Planes & HorizontalPlane) = HorizontalPlane)
+            Self.VelocityY = -Self.VelocityY
+            Self.VelocityY:*Self.BounceCoefficientY
+        End If
+
+        If ((Planes & VerticalPlane) = VerticalPlane)
+            Self.VelocityX = -Self.VelocityX
+            Self.VelocityX:*Self.BounceCoefficientX
+        End If
+       End Method
+'#End Region
+'#Region Method: Draw
+       Method Draw() Abstract
+'#End Region
+'#Region Method: PhysicsApplied
+       Method PhysicsApplied() Abstract
+'#End Region
+'#Region Method: ApplyPhysics
+       Method ApplyPhysics()
+        ' Gravity
+        Self.VelocityY:+Self.World.Gravity - (Self.World.Drag * Self.SurfaceArea)
+
+        ' Wind
+        Self.VelocityX:+(Self.World.Wind / Self.Weight) * Self.SurfaceArea
+
+        ' Apply the magnets?
+        If (Self.World.ApplyMagnets = True) And (Self.ApplyMagnets = True) Then
+                       Local Magnet:TMagnet
+                       For Magnet=EachIn Self.World.Magnets
+                               Local Pull:TPointD = Magnet.GetForces(Self.X,Self.Y)
+
+                               Self.VelocityX = Self.VelocityX + Pull.X
+                               Self.VelocityY = Self.VelocityY + Pull.Y
+                       Next
+        End If
+
+        ' Terminal Velocity
+        If Self.VelocityX > Self.TerminalVelocityX Then Self.VelocityX = Self.TerminalVelocityX
+        If Self.VelocityY > Self.TerminalVelocityY Then Self.VelocityY = Self.TerminalVelocityY
+        If Self.VelocityX < -Self.TerminalVelocityX Then Self.VelocityX = -Self.TerminalVelocityX
+        If Self.VelocityY < -Self.TerminalVelocityY Then Self.VelocityY = -Self.TerminalVelocityY
+
+        ' Update
+        Self.Y:+Self.VelocityY
+        Self.X:+Self.VelocityX
+
+        ' Raise the event...
+        Self.PhysicsApplied()
+
+       End Method
+'#End Region
+'#Region Method: SetVelocityFromAngle
+    Method SetVelocityFromAngle(Angle!, Speed!)
+        Self.VelocityX = Sin(Angle) * Speed
+        Self.VelocityY = Cos(Angle) * Speed
+    End Method
+'#End Region
+'#Region Method: IncreaseVelocityFromAngle
+    Method IncreaseVelocityFromAngle(Angle!, Speed!)
+        Self.VelocityX :+ Sin(Angle) * Speed
+        Self.VelocityY :+ Cos(Angle) * Speed
+    End Method
+'#End Region
+'#Region Method: Angle
+    Method Angle!()
+               Return TPhysicsUtility.DegreesBetweenPoints(Self.X, Self.Y, Self.X + Self.VelocityX, Self.Y + Self.VelocityY)
+    End Method
+'#End Region
+
+End Type
+
+' Particle Engine.
+Type TParticleEmitter Extends TLink
+
+'#Region Declarations
+    Field World:TWorldPhysicsProvider
+    Field X:Int, Y:Int
+       Field Particles:TPhysicsProviderCollection = New TPhysicsProviderCollection
+'#End Region
+
+'#Region Method: Update
+       Method Update()
+        Self.Particles.ApplyPhysics()
+       End Method
+'#End Region
+'#Region Method: UpdateWithFriction
+    Method UpdateWithFriction(Axis:Int)
+        Self.Particles.ApplyPhysicsAndFriction(Axis)
+    End Method
+'#End Region
+'#Region Method: Draw
+    Method Draw()
+        Self.Particles.Draw()
+    End Method
+'#End Region
+'#Region Method: UpdateAndDraw
+    Method UpdateAndDraw()
+        Self.Particles.ApplyPhysics()
+        Self.Particles.Draw()
+    End Method
+'#End Region
+'#Region Method: AddParticle
+       Method AddParticle(Particle:IParticle)
+               Self.Particles.AddLast(Particle)
+       End Method
+'#End Region
+'#Region Method: RemoveParticle
+       Method RemoveParticle(Particle:IParticle)
+               Self.Particles.Remove(Particle)
+       End Method
+'#End Region
+
+End Type
+Type IParticle Extends TPhysicsProvider
+
+       Field Angle:Float
+       Field Speed:Float
+       Field Region:TRectangle
+
+    Method Initialize() Abstract
+
+End Type
+Type TStaticParticle Extends IParticle
+
+'#Region Declarations
+    Field LastX:Int
+    Field LastY:Int
+       Field Emitter:TParticleEmitter
+
+    Field LifeTime:Int = -1
+    Field LifeAmount:Int
+    Field FadeSpeed:Float = -1.0
+    Field Color[] = [255,255,255]
+    Field FadeAmount:Float
+       Field Size:Float = 1.0
+       Field ActualRotation:Float = 0.0
+       Field Rotation:Float = 0.0
+
+    Field Graphic:TImage
+'#End Region
+'#Region Constructor
+       Function Create:TStaticParticle(World:TWorldPhysicsProvider, Graphic:TImage, Region:TRectangle)
+               Local Out:TStaticParticle = New TStaticParticle
+        Out.Graphic = Graphic
+        Out.Region = Region
+               Return Out
+    End Function
+'#End Region
+
+'#Region Method: Draw
+    Method Draw()
+               SetColor(Self.Color[0],Self.Color[1],Self.Color[2])
+               SetScale(Self.Size, Self.Size)
+               SetAlpha(1.0 - Self.FadeAmount)
+               Self.ActualRotation :+ Self.Rotation
+               SetRotation(Self.ActualRotation)
+               DrawImage(Self.Graphic, Int(Self.X), Int(Self.Y))
+    End Method
+'#End Region
+
+'#Region Method: Initialize
+    Method Initialize()
+        Self.SetVelocityFromAngle(Self.Angle, Self.Speed)
+    End Method
+'#End Region
+
+'#Region Override: PhysicsApplied
+    Method PhysicsApplied()
+        Local ImageRect:TRectangle = New TRectangle
+               ImageRect.Width = Self.Graphic.Width
+               ImageRect.Height = Self.Graphic.Height
+        ImageRect.X = Int(Self.X - Self.Graphic.handle_x)
+        ImageRect.Y = Int(Self.Y - Self.Graphic.handle_y)
+
+               Local RemoveThis:Int = False
+        If Not Self.Region.IntersectsWith(ImageRect) Then 
+                       RemoveThis = True
+               Else
+               If Self.LifeTime > -1 Then
+                   If Self.LifeAmount >= Self.LifeTime Then
+                       ' Start fade out?
+                       If Self.FadeSpeed > -1 Then
+                           Self.FadeAmount :+ FadeSpeed
+                           If Self.FadeAmount >= 1.0 Then
+                                                       RemoveThis = True
+                           EndIf
+                       Else
+                                               RemoveThis = True
+                       EndIf
+                   Else
+                       Self.LifeAmount :+ 1 ' its lived a bit longer now.
+                       EndIf
+                       Else
+                               RemoveThis = True
+               EndIf
+               EndIf   
+
+               If RemoveThis Then
+            Self.Emitter.RemoveParticle(Self)
+                       Self.Emitter = Null
+               EndIf
+       End Method
+'#End Region
+       
+End Type
+Type TFountain Extends TParticleEmitter
+
+'#Region Declarations
+       Field Region:TRectangle
+'#End Region
+'#Region Constructor
+    Function Create:TFountain(World:TWorldPhysicsProvider, Region:TRectangle)
+        Local Out:TFountain = New TFountain
+               Out.World = World
+        Out.Region = Region
+               Return Out
+    End Function
+'#End Region
+
+'#Region Method: AddStaticParticle
+    Method AddStaticParticle:TStaticParticle(Image:TImage, Angle:Float, Velocity:Float, LifeTime:Int, FadeSpeed:Float, Color[])
+        Local Particle:TStaticParticle = TStaticParticle.Create(Self.World, Image, Self.Region)
+        Particle.X = Self.X
+        Particle.Y = Self.Y
+        Particle.Angle = Angle
+        Particle.Speed = Velocity
+               Particle.Emitter = Self
+               Particle.FadeSpeed = FadeSpeed
+               Particle.LifeTime = LifeTime
+               Particle.Color = Color
+        Particle.Initialize()
+        Self.AddParticle(Particle)
+        Return Particle
+    End Method
+'#End Region
+
+End Type
+
+
+
+
+
diff --git a/samples/digesteroids/sounds/crash.wav b/samples/digesteroids/sounds/crash.wav
new file mode 100644 (file)
index 0000000..cc8fe20
Binary files /dev/null and b/samples/digesteroids/sounds/crash.wav differ
diff --git a/samples/digesteroids/sounds/ending.ogg b/samples/digesteroids/sounds/ending.ogg
new file mode 100644 (file)
index 0000000..7120d63
Binary files /dev/null and b/samples/digesteroids/sounds/ending.ogg differ
diff --git a/samples/digesteroids/sounds/fire.wav b/samples/digesteroids/sounds/fire.wav
new file mode 100644 (file)
index 0000000..9e08490
Binary files /dev/null and b/samples/digesteroids/sounds/fire.wav differ
diff --git a/samples/digesteroids/sounds/impactlarge.wav b/samples/digesteroids/sounds/impactlarge.wav
new file mode 100644 (file)
index 0000000..33af1a7
Binary files /dev/null and b/samples/digesteroids/sounds/impactlarge.wav differ
diff --git a/samples/digesteroids/sounds/menu.ogg b/samples/digesteroids/sounds/menu.ogg
new file mode 100644 (file)
index 0000000..95bb202
Binary files /dev/null and b/samples/digesteroids/sounds/menu.ogg differ
diff --git a/samples/digesteroids/sounds/teleport.wav b/samples/digesteroids/sounds/teleport.wav
new file mode 100644 (file)
index 0000000..fe8109d
Binary files /dev/null and b/samples/digesteroids/sounds/teleport.wav differ
diff --git a/samples/digesteroids/sounds/thrust.wav b/samples/digesteroids/sounds/thrust.wav
new file mode 100644 (file)
index 0000000..214f8fc
Binary files /dev/null and b/samples/digesteroids/sounds/thrust.wav differ
diff --git a/samples/firepaint/bullet.png b/samples/firepaint/bullet.png
new file mode 100644 (file)
index 0000000..05d28ca
Binary files /dev/null and b/samples/firepaint/bullet.png differ
diff --git a/samples/firepaint/color.bmx b/samples/firepaint/color.bmx
new file mode 100644 (file)
index 0000000..542651b
--- /dev/null
@@ -0,0 +1,276 @@
+
+Strict
+
+Type TColor
+
+       Method RGBColor:TRGBColor() Abstract
+       Method CMYColor:TCMYColor() Abstract
+       Method HSVColor:THSVColor() Abstract
+
+End Type
+
+Type TRGBColor Extends TColor
+
+       Field _red#,_grn#,_blu#
+
+       Method RGBColor:TRGBColor()
+               Return Self
+       End Method
+
+       Method CMYColor:TCMYColor()
+               Return TCMYColor.CreateCMY( 1-_red,1-_grn,1-_blu )
+       End Method
+
+       Method HSVColor:THSVColor()
+               Local hmin#=_red
+               If _grn<hmin hmin=_grn
+               If _blu<hmin hmin=_blu
+               Local hmax#=_red
+               If _grn>hmax hmax=_grn
+               If _blu>hmax hmax=_blu
+               If hmax-hmin=0 Return THSVColor.CreateHSV( 0,0,hmax )
+               Local hue#,delta#=hmax-hmin
+               Select hmax
+               Case _red hue=(_grn-_blu)/delta
+               Case _grn hue=2+(_blu-_red)/delta
+               Case _blu hue=4+(_red-_grn)/delta
+               End Select
+               hue=hue*60
+               If hue<0 hue=hue+360
+               Return THSVColor.CreateHSV( hue,delta/hmax,hmax )
+       End Method
+
+       Method RED#()
+               Return _red
+       End Method
+
+       Method GREEN#()
+               Return _grn
+       End Method
+
+       Method BLUE#()
+               Return _blu
+       End Method
+       
+       Method Set(r#,g#,b#)
+               _red=r
+               _grn=g
+               _blu=b
+       End Method
+
+       Function CreateRGB:TRGBColor( RED#,grn#,blu# )
+               Local color:TRGBColor=New TRGBColor
+               color._red=RED
+               color._grn=grn
+               color._blu=blu
+               Return color
+       End Function
+
+End Type
+
+Type TCMYColor Extends TColor
+       
+       Field _cyn#,_mag#,_yel#
+
+       Method RGBColor:TRGBColor()
+               Return TRGBColor.CreateRGB( 1-_cyn,1-_mag,1-_yel )
+       End Method
+
+       Method CMYColor:TCMYColor()
+               Return Self
+       End Method
+
+       Method HSVColor:THSVColor()
+               Return RGBColor().HSVColor()
+       End Method
+
+       Method CYAN#()
+               Return _cyn
+       End Method
+
+       Method MAGENTA#()
+               Return _mag
+       End Method
+
+       Method YELLOW#()
+               Return _yel
+       End Method
+
+       Function CreateCMY:TCMYColor( cyn#,mag#,yel# )
+               Local color:TCMYColor=New TCMYColor
+               color._cyn=cyn
+               color._mag=mag
+               color._yel=yel
+               Return color
+       End Function
+
+End Type
+
+Type THSVColor Extends TColor
+
+       Field _hue#,_sat#,_val#
+
+       Method RGBColor:TRGBColor()
+               If _sat<=0 Return TRGBColor.CreateRGB( _val,_val,_val )
+               Local h#=_hue/60
+               Local i#=Floor( h )
+               Local f#=h-i
+               Local p#=_val*(1-_sat)
+               Local q#=_val*(1-(_sat*f))
+               Local t#=_val*(1-(_sat*(1-f)))
+               Select Int(i)
+               Case 0 Return TRGBColor.CreateRGB( _val,t,p )
+               Case 1 Return TRGBColor.CreateRGB( q,_val,p )
+               Case 2 Return TRGBColor.CreateRGB( p,_val,t )
+               Case 3 Return TRGBColor.CreateRGB( p,q,_val )
+               Case 4 Return TRGBColor.CreateRGB( t,p,_val )
+               Case 5 Return TRGBColor.CreateRGB( _val,p,q )
+               End Select
+       End Method
+
+       Method CMYColor:TCMYColor()
+               Return RGBColor().CMYColor()
+       End Method
+
+       Method HSVColor:THSVColor()
+               Return Self
+       End Method
+
+       Method Hue#()
+               Return _hue
+       End Method
+
+       Method Saturation#()
+               Return _sat
+       End Method
+
+       Method Value#()
+               Return _val
+       End Method
+
+       Function CreateHSV:THSVColor( hue#,sat#,val# )
+               If hue<0 hue=hue+360
+               If hue>=360 hue=hue-360
+               Local color:THSVColor=New THSVColor
+               color._hue=hue
+               color._sat=sat
+               color._val=val
+               Return color
+       End Function
+
+End Type
+
+Global RED:TColor=RGBColor( 1,0,0 )
+Global GREEN:TColor=RGBColor( 0,1,0 )
+Global BLUE:TColor=RGBColor( 0,0,1 )
+
+Global ORANGE:TColor=RGBColor( 1,1,0 )
+
+Global CYAN:TColor=CMYColor( 1,0,0 )
+Global MAGENTA:TColor=CMYColor( 0,1,0 )
+Global YELLOW:TColor=CMYColor( 0,0,1 )
+
+Global BLACK:TColor=HSVColor( 0,0,0 )
+Global WHITE:TColor=HSVColor( 0,0,1 )
+Global GRAY:TColor=HSVColor( 0,0,.5 )
+Global DARKGRAY:TColor=HSVColor( 0,0,.25 )
+Global LIGHTGRAY:TColor=HSVColor( 0,0,.75 )
+
+Rem
+bbdoc: Create a red, green, blue color
+returns: A new color object
+about: @red, @grn and @blu should be in the range 0 to 1.
+End Rem
+Function RGBColor:TRGBColor( RED#,grn#,blu# )
+       Return TRGBColor.CreateRGB( RED,grn,blu )
+End Function
+
+Rem
+bbdoc: Create a cyan, magenta, yellow color
+returns: A new color object
+about: @cyn, @mag and @yel should be in the range 0 to 1.
+End Rem
+Function CMYColor:TCMYColor( cyn#,mag#,yel# )
+       Return TCMYColor.CreateCMY( cyn,mag,yel )
+End Function
+
+Rem
+bbdoc: Create a hue, saturation, value color
+returns: A new color object
+about: @hue should be in the range 0 to 360, @sat and @val should be in the range 0 to 1.
+End Rem
+Function HSVColor:THSVColor( hue#,sat#,val# )
+       Return THSVColor.CreateHSV( hue,sat,val )
+End Function
+
+Rem
+bbdoc: Get red component of a color
+returns: Red component of @color in the range 0 to 1
+End Rem
+Function ColorRed#( color:TColor )
+       Return color.RGBColor().RED()
+End Function
+
+Rem
+bbdoc: Get green component of a color
+returns: Green component of @color in the range 0 to 1
+End Rem
+Function ColorGreen#( color:TColor )
+       Return color.RGBColor().GREEN()
+End Function
+
+Rem
+bbdoc: Get blue component of a color
+returns: Blue component of @color in the range 0 to 1
+End Rem
+Function ColorBlue#( color:TColor )
+       Return color.RGBColor().BLUE()
+End Function
+
+Rem
+bbdoc: Get cyan component of a color
+returns: Cyan component of @color in the range 0 to 1
+End Rem
+Function ColorCyan#( color:TColor )
+       Return color.CMYColor().CYAN()
+End Function
+
+Rem
+bbdoc: Get magenta component of a color
+returns: Magenta component of @color in the range 0 to 1
+End Rem
+Function ColorMagenta#( color:TColor )
+       Return color.CMYColor().MAGENTA()
+End Function
+
+Rem
+bbdoc: Get yellow component of a color
+returns: Yellow component of @color in the range 0 to 1
+End Rem
+Function ColorYellow#( color:TColor )
+       Return color.CMYColor().YELLOW()
+End Function
+
+Rem
+bbdoc: Get hue component of a color
+returns: Hue component of @color in the range 0 to 360
+End Rem
+Function ColorHue#( color:TColor )
+       Return color.HSVColor().Hue()
+End Function
+
+Rem
+bbdoc: Get saturation component of a color
+returns: Saturation component of @color in the range 0 to 1
+End Rem
+Function ColorSaturation#( color:TColor )
+       Return color.HSVColor().Saturation()
+End Function
+
+Rem
+bbdoc: Get value component of a color
+returns: Value component of @color in the range 0 to 1
+End Rem
+Function ColorValue#( color:TColor )
+       Return color.HSVColor().Value()
+End Function
diff --git a/samples/firepaint/firepaint.bmx b/samples/firepaint/firepaint.bmx
new file mode 100644 (file)
index 0000000..b2f0d3e
--- /dev/null
@@ -0,0 +1,191 @@
+Rem
+
+Firepaint demo:
+
+Hold down mouse button to emit *FIRE*!
+
+EndRem 
+
+Strict
+
+'For minimal build...
+Rem
+Framework BRL.D3D7Max2D
+Import BRL.Basic
+Import BRL.System
+Import BRL.PNGLoader 
+Import BRL.FreeAudioAudio
+Import BRL.WAVLoader
+End Rem
+
+Import "color.bmx"
+
+Incbin "stars.png"
+Incbin "player.png"
+Incbin "bullet.png"
+Incbin "shoot.wav"
+
+Const WIDTH=640,HEIGHT=480
+Const DEPTH=32,HERTZ=60
+
+Const GRAVITY#=.15,SPARKS_PER_FRAME=55
+
+Global sparks:TList=New TList
+Global bullets:TList=New TList
+
+Type TEntity
+
+       Field link:TLink
+
+       Method remove()
+               link.remove
+       End Method
+
+       Method AddLast( list:TList )
+               link=list.AddLast( Self )
+       End Method
+
+       Method Update() Abstract
+
+End Type
+
+Type TSpark Extends TEntity
+
+       Field x#,y#,xs#,ys#
+       Field color[3],rot#,rots#
+
+       Method Update()
+
+               ys:+GRAVITY
+               x:+xs
+               y:+ys
+
+               If x<0 Or x>=WIDTH Or y>=HEIGHT
+                       remove
+                       Return
+               EndIf
+
+               rot=rot+rots
+               SetHandle 8,8
+               SetRotation rot#
+               SetAlpha 1-y/HEIGHT
+               SetColor color[0],color[1],color[2]
+               DrawRect x,y,17,17
+               SetHandle 0,0
+
+       End Method
+
+       Function CreateSpark:TSpark( x#,y#,color[] )
+               Local spark:TSpark=New TSpark
+               Local an#=Rnd(360),sp#=Rnd(3,5)
+               spark.x=x
+               spark.y=y
+               spark.xs=Cos(an)*sp
+               spark.ys=Sin(an)*sp
+               spark.rots=Rnd(-15,15)
+               spark.color=color
+               spark.AddLast sparks
+               Return spark
+       End Function
+
+End Type
+
+Type TBullet Extends TEntity
+
+       Field x#,y#,ys#
+       Field rot#,img:TImage
+
+       Method Update()
+               ys:-.01
+               y:+ys
+               If y<0
+                       remove
+                       Return
+               EndIf
+               rot:+3
+               SetRotation rot
+               DrawImage img,x,y
+       End Method
+
+       Function CreateBullet:TBullet( x#,y#,img:TImage )
+               Local bullet:TBullet=New TBullet
+               bullet.x=x
+               bullet.y=y
+               bullet.ys=-1 
+               bullet.img=img
+               bullet.AddLast bullets
+               Return bullet
+       End Function
+
+End Type
+
+Function UpdateEntities( list:TList )
+       For Local entity:TEntity=EachIn list
+               entity.Update
+       Next
+End Function
+
+Graphics WIDTH,HEIGHT,DEPTH,HERTZ
+
+AutoMidHandle True
+
+Local fire:TSound=LoadSound( "incbin::shoot.wav" )
+Local dude:TImage=LoadImage( "incbin::player.png" ),dude_x=WIDTH/2,dude_y=HEIGHT-30
+Local bull:TImage=LoadImage( "incbin::bullet.png" ),bull_x,bull_y
+Local stars:TImage=LoadImage( "incbin::stars.png" ),stars_x,stars_y
+
+Local show_debug,color_rot#
+
+While Not KeyHit( KEY_ESCAPE )
+
+       Cls
+       
+       stars_y:+1
+       SetBlend MASKBLEND
+       TileImage stars,stars_x,stars_y
+       TileImage stars,stars_x+7,stars_y*2
+       TileImage stars,stars_x+7,stars_y*3
+       
+       If KeyDown( KEY_LEFT )
+               dude_x:-5
+       Else If  KeyDown( KEY_RIGHT )
+               dude_x:+5
+       EndIf
+
+       SetBlend MASKBLEND
+       DrawImage dude,dude_x,dude_y
+
+       If KeyHit( KEY_SPACE )
+               PlaySound fire
+               TBullet.CreateBullet dude_x,dude_y-16,bull
+       EndIf
+
+       If MouseDown(1)
+               color_rot:+1.5
+               color_rot:Mod 360
+               Local color:TRGBColor=HSVColor( color_rot,1,1 ).RGBColor()
+               Local rgb[]=[Int(color.Red()*255),Int(color.Green()*255),Int(color.Blue()*255)]
+               For Local k=1 To SPARKS_PER_FRAME
+                       TSpark.CreateSpark MouseX(),MouseY(),rgb
+               Next
+       EndIf
+
+       SetBlend MASKBLEND
+       UpdateEntities bullets
+       SetRotation 0
+
+       SetBlend LIGHTBLEND
+       UpdateEntities sparks
+       SetAlpha 1
+       SetRotation 0
+       SetColor 255,255,255
+       
+       If KeyHit( Asc("D") ) show_debug=1-show_debug
+       
+       If show_debug
+               DrawText "MemAlloced="+GCMemAlloced(),0,0
+       EndIf
+
+       Flip
+       
+Wend
diff --git a/samples/firepaint/player.png b/samples/firepaint/player.png
new file mode 100644 (file)
index 0000000..cf8f76b
Binary files /dev/null and b/samples/firepaint/player.png differ
diff --git a/samples/firepaint/shoot.wav b/samples/firepaint/shoot.wav
new file mode 100644 (file)
index 0000000..0bea437
Binary files /dev/null and b/samples/firepaint/shoot.wav differ
diff --git a/samples/firepaint/stars.png b/samples/firepaint/stars.png
new file mode 100644 (file)
index 0000000..16e7539
Binary files /dev/null and b/samples/firepaint/stars.png differ
diff --git a/samples/flameduck/circlemania/anim0.png b/samples/flameduck/circlemania/anim0.png
new file mode 100644 (file)
index 0000000..0858c19
Binary files /dev/null and b/samples/flameduck/circlemania/anim0.png differ
diff --git a/samples/flameduck/circlemania/anim1.png b/samples/flameduck/circlemania/anim1.png
new file mode 100644 (file)
index 0000000..0858c19
Binary files /dev/null and b/samples/flameduck/circlemania/anim1.png differ
diff --git a/samples/flameduck/circlemania/anim10.png b/samples/flameduck/circlemania/anim10.png
new file mode 100644 (file)
index 0000000..2551453
Binary files /dev/null and b/samples/flameduck/circlemania/anim10.png differ
diff --git a/samples/flameduck/circlemania/anim11.png b/samples/flameduck/circlemania/anim11.png
new file mode 100644 (file)
index 0000000..c8e9c59
Binary files /dev/null and b/samples/flameduck/circlemania/anim11.png differ
diff --git a/samples/flameduck/circlemania/anim12.png b/samples/flameduck/circlemania/anim12.png
new file mode 100644 (file)
index 0000000..9e286d3
Binary files /dev/null and b/samples/flameduck/circlemania/anim12.png differ
diff --git a/samples/flameduck/circlemania/anim13.png b/samples/flameduck/circlemania/anim13.png
new file mode 100644 (file)
index 0000000..e80fffc
Binary files /dev/null and b/samples/flameduck/circlemania/anim13.png differ
diff --git a/samples/flameduck/circlemania/anim14.png b/samples/flameduck/circlemania/anim14.png
new file mode 100644 (file)
index 0000000..833ba05
Binary files /dev/null and b/samples/flameduck/circlemania/anim14.png differ
diff --git a/samples/flameduck/circlemania/anim15.png b/samples/flameduck/circlemania/anim15.png
new file mode 100644 (file)
index 0000000..577f791
Binary files /dev/null and b/samples/flameduck/circlemania/anim15.png differ
diff --git a/samples/flameduck/circlemania/anim2.png b/samples/flameduck/circlemania/anim2.png
new file mode 100644 (file)
index 0000000..0895006
Binary files /dev/null and b/samples/flameduck/circlemania/anim2.png differ
diff --git a/samples/flameduck/circlemania/anim3.png b/samples/flameduck/circlemania/anim3.png
new file mode 100644 (file)
index 0000000..62637e7
Binary files /dev/null and b/samples/flameduck/circlemania/anim3.png differ
diff --git a/samples/flameduck/circlemania/anim4.png b/samples/flameduck/circlemania/anim4.png
new file mode 100644 (file)
index 0000000..a7e4af6
Binary files /dev/null and b/samples/flameduck/circlemania/anim4.png differ
diff --git a/samples/flameduck/circlemania/anim5.png b/samples/flameduck/circlemania/anim5.png
new file mode 100644 (file)
index 0000000..244a7a9
Binary files /dev/null and b/samples/flameduck/circlemania/anim5.png differ
diff --git a/samples/flameduck/circlemania/anim6.png b/samples/flameduck/circlemania/anim6.png
new file mode 100644 (file)
index 0000000..96657cf
Binary files /dev/null and b/samples/flameduck/circlemania/anim6.png differ
diff --git a/samples/flameduck/circlemania/anim7.png b/samples/flameduck/circlemania/anim7.png
new file mode 100644 (file)
index 0000000..e333488
Binary files /dev/null and b/samples/flameduck/circlemania/anim7.png differ
diff --git a/samples/flameduck/circlemania/anim8.png b/samples/flameduck/circlemania/anim8.png
new file mode 100644 (file)
index 0000000..7be7a9d
Binary files /dev/null and b/samples/flameduck/circlemania/anim8.png differ
diff --git a/samples/flameduck/circlemania/anim9.png b/samples/flameduck/circlemania/anim9.png
new file mode 100644 (file)
index 0000000..7b12a07
Binary files /dev/null and b/samples/flameduck/circlemania/anim9.png differ
diff --git a/samples/flameduck/circlemania/circlebob.png b/samples/flameduck/circlemania/circlebob.png
new file mode 100644 (file)
index 0000000..2be24b0
Binary files /dev/null and b/samples/flameduck/circlemania/circlebob.png differ
diff --git a/samples/flameduck/circlemania/cmania.bmx b/samples/flameduck/circlemania/cmania.bmx
new file mode 100644 (file)
index 0000000..397a0b6
--- /dev/null
@@ -0,0 +1,235 @@
+Rem
+
+Another Oldskool demo thingy, by FlameDuck and Razorien of Binary Therapy
+
+End Rem
+
+Strict
+
+Type rasterBar
+       Field angle:Double,angleadd:Double,color[],freq:Double
+
+       Function addRasterBar(aSpeed:Double, aFreq:Double, aColor[], aList:TList)
+               Local temp:rasterBar = New rasterBar
+               temp.angle=0
+               temp.angleadd=aSpeed
+               temp.freq=aFreq
+               temp.color = aColor
+               aList.addLast(temp)
+       End Function
+
+       Method drawRasterBar(xstart:Int, ycenter:Int, scale:Double)
+               SetBlend LIGHTBLEND
+               SetColor(color[0],color[1],color[2])
+               angle:+angleadd
+
+               For Local i:Int = 0 To 736
+                       Local temp:Int = i+xstart
+                       If temp > 0 Or temp < 799
+                               DrawImage rastaImage, temp, ycenter + Sin((i+angle)*freq)*scale
+                       End If
+               Next
+       End Method
+
+End Type
+
+Type polarVector
+       Field length:Double, angle:Double
+
+       Function Create:polarVector(aLength:Double, anAngle:Double)
+               Local temp:polarVector = New polarVector
+               temp.length=aLength;temp.angle=anAngle
+               Return temp
+       End Function
+End Type
+
+Type baseEntity
+       Field offset:polarVector, angvel:Double
+
+       Method update(anx:Double, any:Double) Abstract
+End Type
+
+Type circleBob
+       Field velocity:polarVector
+       Field x:Double,y:Double
+       Field life:Int
+
+       Function CreateCircleBob:circleBob(anx:Double, any:Double, avelocity:polarVector)
+               Local temp:circleBob = New circleBob
+               temp.x=anx;temp.y=any;temp.velocity=avelocity
+               temp.life=20
+               Return temp
+       End Function
+
+       Method update()
+               x:+Cos(velocity.angle)*velocity.length
+               y:+Sin(velocity.angle)*velocity.length*yaspect
+               life:-1
+               SetAlpha life/40!
+               DrawImage cmBob, x, y
+       End Method
+
+       Method isDead:Int()
+               If life < 1
+                       Return True
+               Else If x < 0 Or x > 799
+                       Return True
+               Else If y < 0 Or y > 599
+                       Return True
+               End If
+               Return False
+       End Method
+
+End Type
+
+Type spawn Extends baseEntity
+       Field cBobs:TList
+
+       Method update(anx:Double,any:Double)
+               offset.angle:+ angvel
+
+               anx:+Cos(offset.angle)*offset.length
+               any:+Sin(offset.angle)*offset.length*yaspect
+               Local temp:circleBob = circleBob.createCircleBob(anx,any, polarVector.Create(Rnd(4,8),ATan2((320-any),(368-anx))))
+               cBobs.addlast(temp)
+
+               For Local mycBob:circleBob = EachIn cBobs
+                       mycBob.update()
+                       If myCBob.isDead()
+                               cBobs.remove(mycBob)
+                       End If
+               Next
+
+       End Method
+
+       Function Create:spawn(anAngle:Double, anAngvel:Double, aRadius:Double)
+               Local temp:spawn = New spawn
+               temp.cBobs = New TList
+               temp.offset = polarVector.Create(aRadius, anAngle)
+               temp.angvel=anAngvel
+               Return temp
+       End Function
+
+End Type
+
+Type anchor Extends baseEntity
+       Field spawns:TList
+
+       Method update(anx:Double, any:Double)
+               offset.angle:-angvel
+               For Local mySpawn:spawn = EachIn spawns
+                       mySpawn.update(anx+Cos(offset.angle)*offset.length, any+Sin(offset.angle)*offset.length*yaspect)
+               Next
+
+       End Method
+
+       Function Create:anchor(anAngle:Double, anAngvel:Double, aRadius:Double, numSpawns:Int)
+
+               Local ddeg:Double = 360:Double/numSpawns
+               Local myAnchor:anchor = New anchor
+               myAnchor.spawns=New TList
+               myAnchor.offset = PolarVector.Create(aRadius, anAngle)
+               myAnchor.angvel=anAngvel
+               For Local i = 1 To numSpawns
+                       Local temp:spawn = spawn.Create(ddeg*i, anAngvel, aRadius/2)
+                       myAnchor.spawns.addlast temp
+               Next
+               Return myAnchor
+       End Function
+End Type
+
+Type root
+       Field anchors:TList
+
+       Method update()
+               For Local myAnchor:anchor = EachIn anchors
+                       myanchor.update(368,320)
+               Next
+               SetAlpha 1
+
+       End Method
+
+       Function Create:root(anAngvel:Double, aRadius:Double, numAnchors:Int, numSpawns:Int)
+               Local ddeg:Double = 360:Double/numSpawns
+               Local myRoot:root=New root
+               myRoot.anchors = New TList
+               For Local i = 1 To numAnchors
+                       Local temp:anchor = anchor.Create(ddeg*i, anAngvel, aRadius, numSpawns)
+                       myRoot.anchors.addlast temp
+               Next
+               Return myRoot
+       End Function
+
+
+End Type
+
+Type imageStrip
+       Field effectImages:TImage[16]
+       Field counter:Int
+
+
+       Function loadImages:imageStrip(name:String)
+               Local temp:imageStrip = New imageStrip
+               For Local i:Int = 0 To 15
+                       Local fname:String = name+String(i)+".png"
+                       temp.effectImages[i] = LoadImage(fname)
+               Next
+               temp.counter = 0
+               Return temp
+       End Function
+
+       Method update(x:Int,y:Int)
+               counter:-1
+               If counter < 0
+                       counter=15
+               EndIf
+
+               DrawImage effectImages[counter],x,y
+       End Method
+
+End Type
+
+Graphics 800,600,32
+
+Global yaspect:Double = 3/5!
+Global rastaImage:TImage = LoadImage("rasta.png")
+Global logo:TImage = LoadImage("cmanialogo.png")
+Global cmBob:TImage = LoadImage("circlebob.png")
+MidHandleImage logo
+
+Global maskEffect:imageStrip = imageStrip.LoadImages("anim")
+
+Local myRBList:TList = New TList
+rasterBar.addRasterBar(3!,2!, [255,0,0], myRBList)
+rasterBar.addRasterBar(5!,1.5!, [0,255,0], myRBList)
+rasterBar.addRasterBar(7!,1!, [0,0,255], myRBList)
+
+Local angle:Double = 0
+Local effectRoot:root = root.Create(4, 200, 6, 6)
+
+While Not KeyHit(KEY_ESCAPE)
+
+       Cls
+
+       Local xpos:Int = 124 * Sin(angle)
+
+       For Local i:rasterBar = EachIn myRBList
+               i.drawRasterBar(xpos+32 , 28!, 28!)
+       Next
+
+       SetBlend ALPHABLEND
+
+       DrawImage logo, 400 + xpos,58
+       angle:+4
+       angle:Mod 360
+
+       Local temp = 255*Abs((-180+angle)/180!)
+
+       SetColor temp,temp,temp
+       DrawLine 0,116,799,116
+       SetColor 255,255,255
+       effectRoot.update
+       Flip
+
+End While
+
diff --git a/samples/flameduck/circlemania/cmanialogo.png b/samples/flameduck/circlemania/cmanialogo.png
new file mode 100644 (file)
index 0000000..31ba9c0
Binary files /dev/null and b/samples/flameduck/circlemania/cmanialogo.png differ
diff --git a/samples/flameduck/circlemania/rasta.png b/samples/flameduck/circlemania/rasta.png
new file mode 100644 (file)
index 0000000..beaab97
Binary files /dev/null and b/samples/flameduck/circlemania/rasta.png differ
diff --git a/samples/flameduck/oldskool2/binarytherapy.png b/samples/flameduck/oldskool2/binarytherapy.png
new file mode 100644 (file)
index 0000000..e96cb89
Binary files /dev/null and b/samples/flameduck/oldskool2/binarytherapy.png differ
diff --git a/samples/flameduck/oldskool2/bouncy.ogg b/samples/flameduck/oldskool2/bouncy.ogg
new file mode 100644 (file)
index 0000000..c507b47
Binary files /dev/null and b/samples/flameduck/oldskool2/bouncy.ogg differ
diff --git a/samples/flameduck/oldskool2/circlefont.png b/samples/flameduck/oldskool2/circlefont.png
new file mode 100644 (file)
index 0000000..6ef6ea0
Binary files /dev/null and b/samples/flameduck/oldskool2/circlefont.png differ
diff --git a/samples/flameduck/oldskool2/oldskool.png b/samples/flameduck/oldskool2/oldskool.png
new file mode 100644 (file)
index 0000000..6200f9f
Binary files /dev/null and b/samples/flameduck/oldskool2/oldskool.png differ
diff --git a/samples/flameduck/oldskool2/oldskool2.bmx b/samples/flameduck/oldskool2/oldskool2.bmx
new file mode 100644 (file)
index 0000000..9180632
--- /dev/null
@@ -0,0 +1,241 @@
+Rem
+
+Another Oldskool demo thingy, by FlameDuck and Razorien of Binary Therapy
+
+It started as a simple circle scroller example but got somewhat out of hand. :o>
+
+End Rem
+
+Strict
+
+Incbin "circlefont.png"
+Incbin "oldskool.png"
+Incbin "bouncy.ogg"
+Incbin "binarytherapy.png"
+
+Global scrollSpeed:Double = .6
+Global rotangl:Double = 0
+Global osLogo:TImage = LoadImage( "incbin::oldskool.png" )
+Global myFont:TImage = LoadAnimImage( "incbin::circlefont.png",32,32,0,90 )
+Global myBT:TImage = LoadImage( "incbin::binarytherapy.png" )
+
+MidHandleImage myFont
+
+Global scrollytext$ = " In 2004       Binary Therapy       Proudly Presents       Oldskool 2       Programmed by: FlameDuck       Logo by: Razorien ( http://www.razorien.se/ )       Font courtesy of FONText by: Beaker ( http://www.playerfactory.co.uk/ )       Music by:  Dr Av ( http://www.mentalillusion.co.uk/ )       This demo was written in the beta phase of BlitzMAX development, the source code is 237 lines total including empty lines and comments ....."
+Global sp = 0; 'The scrollytext pointer.
+Global ld = 0; 'The letter delay counter.
+Global muzak:TSound = LoadSound( "incbin::bouncy.ogg",True )
+
+Type scrollyLetter
+
+       Field rad:Double, angl:Double, letter:Byte, rados:Double
+       Field myList:TList
+
+       Function createScrollyLetter:scrollyLetter(myChar:Byte)
+               Local myLetter:scrollyLetter = New scrollyLetter
+               myLetter.rad = 170
+               myLetter.angl = -90
+               myLetter.letter = myChar
+               Return myLetter
+       End Function
+
+       Method setList(aList:TList)
+               myList = aList
+       End Method
+
+       Method moveScrollyLetter()
+               angl :+ scrollSpeed
+               rados = Cos(angl*3 + rotangl) * 40
+               If angl > 270
+                       myList.remove(Self)
+               End If
+
+       End Method
+
+       Method drawLetter()
+               Local x = Cos(angl) * (rad + rados)
+               Local y = Sin(angl) * (rad + rados)
+
+               SetRotation ATan2 ( y , x )
+
+               Local myAlpha:Double = 1
+               If angl < -45
+                       myAlpha:Double = (90.0+angl)/45.0
+               Else If angl > 225
+                       myAlpha:Double = (270.0-angl)/45.0
+               End If
+
+               SetAlpha myAlpha
+               DrawImage myFont, x + 400 , -y + 240 , letter
+
+       End Method
+
+End Type
+
+Type circleScroller Extends TList
+
+       Method doScroller()
+               rotangl :+ scrollSpeed; rotangl :Mod 360
+
+               ld :+ 1
+               If  ld > 20
+                       If scrollytext[sp]-33 > 0 And scrollytext[sp]-33 < 90
+                               Local myLetter:scrollyLetter = scrollyLetter.createScrollyLetter( scrollytext[sp]-33 )
+                               myLetter.setList(Self)
+                               addLast myLetter
+                       End If
+                       sp = (sp+1) Mod Len(scrollytext)
+                       ld = 0
+               End If
+
+               SetBlend ALPHABLEND
+
+               Local cLetter:scrollyLetter
+               For cLetter = EachIn Self
+
+                       cLetter.moveScrollyLetter
+                       cLetter.drawLetter
+
+
+               Next
+               SetBlend MASKBLEND
+
+               SetRotation 0
+               SetAlpha 1
+
+       End Method
+
+End Type
+
+Type star
+       Field x:Double, y:Double, z:Double, angl:Double, anglv:Double, zv:Double
+
+       Function createStar:star()
+               Local myStar:star = New star
+               myStar.x = Rnd(-240,240)
+               myStar.y = Rnd(-240,240)
+               myStar.z = 100
+               myStar.angl = Rnd(0,360)
+               myStar.anglv = Rnd(-5,5)
+               myStar.zv = Rnd(0.5,2)
+               Return myStar
+       End Function
+
+       Method moveStar()
+               z :- zv
+               Local myx = x / z *100
+               Local myy = y / z *100
+
+               If myx < -240 Or myx > 240 Or myy < -240 Or myx > 240 Or z < 1
+                       x = Rnd(-240,240)
+                       y = Rnd(-240,240)
+                       z = 100
+                       angl = Rnd(0,360)
+                       anglv = Rnd(-5,5)
+                       zv = Rnd(0.5,3)
+               End If
+
+               angl = angl + anglv
+       End Method
+
+       Method drawStar()
+               Local myx = x / z *100
+               Local myy = y / z *100
+
+               Local cols = 255*(100-z)/100
+
+               SetColor(cols,cols,cols)
+               Plot myx+400 , myy+240
+
+       End Method
+
+
+End Type
+
+Type starField Extends TList
+
+       Method doStarField()
+
+               Local cStar:star
+               For cStar = EachIn Self
+
+                       cStar.moveStar
+                       cStar.drawStar
+
+               Next
+               SetColor 255,255,255
+
+       End Method
+
+End Type
+
+Local myCS:circleScroller = New circleScroller
+Local mySF:starField = New starField
+
+Local ba = 0
+Local intro = 0
+Local i = 0
+Local term:Double = 0
+
+Local dd=32
+
+Graphics 640,480,dd
+
+HideMouse
+
+Local myChannel:TChannel = PlaySound (muzak)
+
+While term < 1
+
+       If KeyHit( KEY_ENTER )
+               dd=32-dd
+               Graphics 640,480,dd
+               HideMouse
+               FlushKeys
+       EndIf
+
+       Cls
+
+       mySF.doStarField
+
+       If intro < 80
+               intro :+2
+       Else
+               myCS.doScroller
+               If i < 400
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       mySF.addLast star.createStar()
+                       i :+ 1
+               End If
+       End If
+
+       SetBlend SOLIDBLEND
+       DrawImage osLogo,-160+intro*2,0
+
+       SetBlend MASKBLEND
+       DrawImage myBT, 640-myBT.width * intro/80.0, 480-myBT.height - Sin(ba)*20
+
+       SetBlend ALPHABLEND
+       SetAlpha term
+       SetChannelVolume myChannel,1-term
+       SetColor 0,0,0
+       DrawRect 0,0,640,480
+       SetAlpha 1
+       SetColor 255,255,255
+
+       If KeyHit(KEY_ESCAPE) Or term > 0
+               term :+ 0.01
+       End If
+
+       ba :+6; ba :Mod 180
+       Flip
+
+Wend
diff --git a/samples/flameduck/oldskool2/readme.txt b/samples/flameduck/oldskool2/readme.txt
new file mode 100644 (file)
index 0000000..edd62ba
--- /dev/null
@@ -0,0 +1,32 @@
+**** Oldskool2 -- BlitzMAX Edition ****
+
+INTRODUCTION:
+
+This small demo was put together by Binary Therapy for BlitzMAX. It is written
+entirely in BlitzMAX during the course of a few days.
+
+FILES & CREDITS:
+
+This archive should contain the following files:
+
+Size           Name                            Author
+------------------------------------------------
+  4.832        oldskool2.bmx           Mikkel Løkke
+  1.036                readme.txt                      Mikkel Løkke
+ 22.740                circlefont.png          Mikkel Løkke
+  1.078                binarytherapy.png       Mikkel Løkke
+ 25.841                oldskool.png            Andreas Engström
+546.218                bouncy.ogg                      Rob Farley
+
+COPYRIGHT:
+
+The works contained in this archive have been released into the public domain
+by Binary Therapy in 2004.
+
+AKNOWLEDGEMENTS:
+
+The developement team would like to thank Mark Sibly, Simon Armstrong and
+James L. Boyd of Blitz Research Ltd. ( http://www.blitzbasic.com/ ) for
+BlitzMAX, Robin Shackford of Playerfactory ( http://www.playerfactory.co.uk/ )
+for the excellent FONText tool and Rob Farley of Mental Illusion
+( http://www.mentalillusion.co.uk/ ) for the awesome tune.
\ No newline at end of file
diff --git a/samples/hitoro/arraysort.bmx b/samples/hitoro/arraysort.bmx
new file mode 100644 (file)
index 0000000..35e65e5
--- /dev/null
@@ -0,0 +1,44 @@
+
+' Create an array of (nonsense) strings, one for each letter of the alphabet...
+
+Local drivel:String [26]
+
+' Fill all 26 strings in (remember we include 0, so the last is 25)...
+
+drivel [0] = "Hello"
+drivel [1] = "Golly, Miss Lane"
+drivel [2] = "I like whippets"
+drivel [3] = "Oink"
+drivel [4] = "Apparently not"
+drivel [5] = "Tell me when, Lord, tell me when"
+drivel [6] = "Flat Harry is alive and well"
+drivel [7] = "North, Miss Teschmacher, north!"
+drivel [8] = "Egg-shaped boy"
+drivel [9] = "Say it again"
+drivel [10] = "Krazy Kat is a heppy, heppy kitty"
+drivel [11] = "Death to the Pixies!"
+drivel [12] = "You're wrong"
+drivel [13] = "Maybe tomorrow I'll wanna settle down"
+drivel [14] = "Jumpin' junipers!"
+drivel [15] = "Rock out!"
+drivel [16] = "Brilliant!"
+drivel [17] = "Victoria was my queen"
+drivel [18] = "Leaving so soon?"
+drivel [19] = "Quatermass rules"
+drivel [20] = "C sucks"
+drivel [21] = "Under the stars"
+drivel [22] = "Xylophone solo"
+drivel [23] = "Zebra hell"
+drivel [24] = "Well I never"
+drivel [25] = "Perhaps some other time?"
+
+' Sort the array of strings (type String has a Sort method)...
+
+drivel.Sort
+
+' Print 'em out in alphabetical order...
+
+For a = 0 Until Len (drivel)
+    Print a + " : " + drivel [a]
+Next
+
diff --git a/samples/hitoro/bench.bmx b/samples/hitoro/bench.bmx
new file mode 100644 (file)
index 0000000..ff684d0
--- /dev/null
@@ -0,0 +1,39 @@
+
+' Ported from another Basic for benchmarking purposes...
+
+Const ITERATIONS = 10000
+
+Local Flags [8191]
+Print "SIEVE OF ERATOSTHENES - " + ITERATIONS + " iterations"
+
+X = MilliSecs ()
+
+For Iter = 1 To ITERATIONS
+
+  Count = 0
+
+  For I = 0 To 8190
+    Flags[I] = 1
+  Next
+
+  For I = 0 To 8190
+    If Flags[I]=1 Then
+       Prime = I + I
+       Prime = Prime + 3
+       K = I + Prime
+       While K <= 8190
+         Flags[K] = 0
+         K = K + Prime
+       Wend
+       Count = Count + 1
+    EndIf
+  Next
+
+Next
+
+X = MilliSecs () - X
+
+Print "1000 iterations took "+(X/1000.0)+" seconds."
+Print "Primes: "+Count
+End
+
diff --git a/samples/hitoro/debugprintq.bmx b/samples/hitoro/debugprintq.bmx
new file mode 100644 (file)
index 0000000..79a452f
--- /dev/null
@@ -0,0 +1,78 @@
+
+' Debug Print Queue...
+
+' Copy and paste the DebugQ type and the PrintQ/UpdateQ functions. Use
+' PrintQ to add a debug message to your game, and UpdateQ in your main
+' loop to display/update messages...
+
+Type DebugQ
+
+     Global DebugQList:TList
+
+     Field message$
+     Field alpha# = 1
+
+     Function Print (message$)
+              If DebugQList = Null Then DebugQList= New TList
+              p:DebugQ = New DebugQ
+              p.message = message$
+              DebugQList.AddLast p
+     End Function
+
+     Function Update (alphacut# = 0.01)
+              If DebugQList = Null Then Return
+                 y = 0
+                For p:DebugQ = EachIn DebugQList
+                    SetBlend ALPHABLEND
+                    SetAlpha p.alpha
+                    DrawText p.message$, 0, y
+                    y = y + TextHeight("")
+                    p.alpha = p.alpha - alphacut; If p.alpha < 0 Then DebugQList.Remove p
+                Next
+                 SetBlend SOLID ' Need to get old values!
+                SetAlpha 1 ' Need to get old values!
+     End Function
+
+End Type
+
+' Functional interfaces for non-OO'ers...
+
+Function PrintQ (message$)
+         DebugQ.Print message$
+End Function
+
+Function UpdateQ ()
+         DebugQ.Update
+End Function
+
+' D E M O . . .
+
+Graphics 640, 480
+
+Repeat
+
+      Cls
+
+      x = MouseX ()
+      y = MouseY ()
+
+      DrawRect x, y, 32, 32
+
+      ' Add items to debug print queue...
+
+      If MouseHit (1) Then PrintQ "Left mouse button hit!"
+      If MouseHit (2) Then PrintQ "Right mouse button hit!"
+
+      ' Print/remove all debug items...
+
+      UpdateQ
+
+      DrawText "Click mouse...", 0, GraphicsHeight () - 20
+
+      Flip
+
+Until KeyHit (KEY_ESCAPE)
+
+End
+
+
diff --git a/samples/hitoro/extendednewtest.bmx b/samples/hitoro/extendednewtest.bmx
new file mode 100644 (file)
index 0000000..e67a953
--- /dev/null
@@ -0,0 +1,41 @@
+
+' This just shows that when you create an object of type 'Tester',
+' it inherits the New method of 'Test'...
+
+' Base type...
+
+Type Test
+
+     Global Oink
+
+     Field x
+     Field y
+
+     Method New ()
+            x = 100
+            y = 200
+            Oink = Oink + 1
+     End Method
+
+End Type
+
+' Another type extending the base type above...
+
+Type Tester Extends Test
+
+     Field z = 99
+
+End Type
+
+' Create a 'Tester' object...
+
+t:Tester = New Tester
+
+' As well as the 'z' field of 't', x and y have values, demonstrating
+' that they must have been set by the Test.New () method...
+
+Print t.x
+Print t.y
+Print t.z
+
+
diff --git a/samples/hitoro/fireworks.bmx b/samples/hitoro/fireworks.bmx
new file mode 100644 (file)
index 0000000..a5651c9
--- /dev/null
@@ -0,0 +1,219 @@
+
+' Global variables tracking number of Firework objects and
+' number of Particle objects. These are increased and decreased
+' as objects are created/destroyed.
+
+Global Fireworks, Particles
+
+' Force pulling particles down...
+
+Global Gravity# = 0.025
+
+' Global list of Particle objects...
+
+Global ParticleList:TList = New TList
+
+' Particle object definition ('class')...
+
+Type Particle
+
+' Particle properties...
+
+       Field x#              ' x position
+       Field y#              ' y position
+       Field xs#             ' x speed
+       Field ys#             ' y speed
+       Field size            ' particle size (size x size)
+
+       Field r#               ' particle colour (red component)
+       Field g#               ' particle colour (green component)
+       Field b#               ' particle colour (blue component)
+
+       Field ditch
+
+       ' Particle actions...
+
+       ' The function below is a 'constructor'. Methods work on
+       ' existing objects, so we can't use a method to create an
+       ' object. Instead, we use a function belonging to this object
+       ' type, and call it like so to return a Particle object:
+       
+       '       p:Particle = Particle.Create (blah blah)...
+
+       Function Create:Particle (x#, y#, xs#, ys#, size, r#, g#, b#)
+               Local p:Particle = New Particle
+               p.x = x
+               p.y = y
+               p.xs = xs
+               p.ys = ys
+               p.size = size
+               p.r = r
+               p.g = g
+               p.b = b
+               ParticleList.Addlast p
+               Particles = Particles + 1
+               Return p
+       End Function
+
+       ' This function updates all particles by iterating through the
+       ' global Particle list (ParticleList) and calling the Update
+       ' method on each one...
+
+       Function UpdateAll ()
+                 For p:Particle = EachIn ParticleList
+                     p.Update
+                 Next
+       End Function
+
+       ' Updates current particle...
+
+       Method Update ()
+               ApplyForces
+               Draw
+       End Method
+
+       ' Apply x and y speeds, apply gravity and apply position limits...
+
+       Method ApplyForces ()
+               x = x + xs
+               ys = ys + Gravity * size
+               y = y + ys
+               LimitParticle
+       End Method
+
+       ' Draws the particle. This has been kept separate so it can be
+       ' 'over-ridden' in the Firework type below...
+
+       Method Draw ()
+               SetColor r, g, b
+               DrawRect x, y, size, size
+       End Method
+
+       ' Apply limits (if the particle goes off the left or right of
+       ' the screen, we reverse its direction, and if it goes off the
+       ' bottom (as it must, since gravity is pulling it down), we
+       ' remove the particle from the global list. We're also fading
+       ' the particle to black by reducing r, g and b; once they all
+       ' reach zero, we remove it from the list.
+
+       Method LimitParticle ()
+               If x < 0 Or x + size > GraphicsWidth ()
+                       xs = -xs
+                       x = x + xs
+               EndIf
+               If y + size > GraphicsHeight ()
+                       ParticleList.Remove Self
+                       Particles = Particles - 1
+               Else
+                       r = r - 2; If r < 0 Then r = 0
+               g = g - 2; If g < 0 Then g = 0
+            b = b - 2; If b < 0 Then b = 0
+            If r + b + g = 0 ParticleList.Remove Self; Particles = Particles - 1
+               EndIf
+       End Method
+
+End Type
+
+' This object definition takes the 'Particle' definition and 'extends' it,
+' meaning that it has all of the same fields and methods/functions as the
+' Particle type, but you can add new fields and 'over-ride' methods by
+' simply redefining them...
+
+Type Firework Extends Particle
+
+       ' Here, I've over-ridden the Create function to return a
+       ' Firework type. Note that the parameters must be the same
+       ' as for Particle.Create and that it is added to the global
+       ' list of Particle objects; this is possible because Firework
+       ' objects are still Particle objects, just more souped-up!
+
+       Function Create:Firework (x#, y#, xs#, ys#, size, r#, g#, b#)
+               Local p:Firework = New Firework
+               p.x = x
+               p.y = y
+               p.xs = xs
+               p.ys = ys
+               p.size = size
+               p.r = r
+               p.g = g
+               p.b = b
+               ParticleList.Addlast p
+               Fireworks = Fireworks + 1
+               Return p
+       End Function
+
+       ' Here I've over-ridden the Update method so that when a
+       ' Firework starts to fall (ys > 0.5) it's deleted and spawns
+       ' a random number of normal Particle objects. Note the use of
+       ' the ApplyForces and Draw methods that are 'inherited' from
+       ' the Particle definition (as are the fields such as x, y,
+       ' xs, ys, etc)...
+
+       Method Update ()
+
+               If ys > 0.5
+                       ParticleList.Remove Self
+                       Fireworks = Fireworks - 1
+                       For p = 1 To Rand (100,1000)'50, 150)
+                               Particle.Create (x, y, Rnd (-4, 4), Rnd (0, -4), Rnd (1, 2), Rand (120, 255), Rand (120, 255), Rand (120, 255))
+                       Next
+               Else
+                       ApplyForces
+                       Draw
+               EndIf
+
+       End Method
+
+       ' This version of LimitParticle over-rides that defined in the
+       ' plain Particle type. It's interesting to note that although
+       ' the Update method above calls the original ApplyForces method
+       ' defined in the Particle type, that actually calls this over-ridden
+       ' version of LimitParticle.
+
+       Method LimitParticle ()
+               If x < 0 Or x + size > GraphicsWidth ()
+                       xs = -xs
+                       x = x + xs
+               EndIf
+       End Method
+
+End Type
+
+' D E M O . . .
+
+Graphics 640, 480
+
+SetClsColor 1, 1, 10
+
+astep# = 2 ' Used for the positioning of the spawn point, x, below...
+
+Repeat
+
+       Cls
+
+       ' This is plotting a circle but only using the x position...
+
+       ang# = ang + astep; If ang > (360 - astep) Then ang = 0
+       x# = (GraphicsWidth () / 2) + (GraphicsWidth () / 2) * Sin (ang)
+
+       ' No timers in Blitz Max yet!
+
+       If Rand (0, 1000) > 800
+               Firework.Create (x, GraphicsHeight (), Rnd (-1, 1), Rnd (-4, -12), 4, 255, 255, 255)
+       EndIf
+
+       ' Update all particle (both Particle and Firework objects from
+       ' the global list)...
+
+       Particle.UpdateAll ()
+
+       SetColor 255, 255, 255
+       DrawText "Fireworks: " + Fireworks, 20, 20
+       DrawText "Particles: " + Particles, 20, 40
+
+       Flip
+
+Until KeyHit(KEY_ESCAPE)
+
+End
+
diff --git a/samples/hitoro/gfx/bg.png b/samples/hitoro/gfx/bg.png
new file mode 100644 (file)
index 0000000..b6f5fdf
Binary files /dev/null and b/samples/hitoro/gfx/bg.png differ
diff --git a/samples/hitoro/gfx/block.png b/samples/hitoro/gfx/block.png
new file mode 100644 (file)
index 0000000..13283d1
Binary files /dev/null and b/samples/hitoro/gfx/block.png differ
diff --git a/samples/hitoro/gfx/boing.png b/samples/hitoro/gfx/boing.png
new file mode 100644 (file)
index 0000000..4ff8a6b
Binary files /dev/null and b/samples/hitoro/gfx/boing.png differ
diff --git a/samples/hitoro/gfx/flame.png b/samples/hitoro/gfx/flame.png
new file mode 100644 (file)
index 0000000..f284a93
Binary files /dev/null and b/samples/hitoro/gfx/flame.png differ
diff --git a/samples/hitoro/gfx/grass.png b/samples/hitoro/gfx/grass.png
new file mode 100644 (file)
index 0000000..cf34f2c
Binary files /dev/null and b/samples/hitoro/gfx/grass.png differ
diff --git a/samples/hitoro/gfx/land.png b/samples/hitoro/gfx/land.png
new file mode 100644 (file)
index 0000000..6ad1976
Binary files /dev/null and b/samples/hitoro/gfx/land.png differ
diff --git a/samples/hitoro/gfx/rock.png b/samples/hitoro/gfx/rock.png
new file mode 100644 (file)
index 0000000..4f91435
Binary files /dev/null and b/samples/hitoro/gfx/rock.png differ
diff --git a/samples/hitoro/gfx/shot.png b/samples/hitoro/gfx/shot.png
new file mode 100644 (file)
index 0000000..f2bf8f9
Binary files /dev/null and b/samples/hitoro/gfx/shot.png differ
diff --git a/samples/hitoro/gfx/sky.png b/samples/hitoro/gfx/sky.png
new file mode 100644 (file)
index 0000000..16e4673
Binary files /dev/null and b/samples/hitoro/gfx/sky.png differ
diff --git a/samples/hitoro/gfx/water.png b/samples/hitoro/gfx/water.png
new file mode 100644 (file)
index 0000000..08190de
Binary files /dev/null and b/samples/hitoro/gfx/water.png differ
diff --git a/samples/hitoro/info.txt b/samples/hitoro/info.txt
new file mode 100644 (file)
index 0000000..aa01f45
--- /dev/null
@@ -0,0 +1,13 @@
+
+This stuff...
+
+The 'graphical examples' folder contains a bunch of demos that show things flying all over the screen, and are mostly quite heavily commented.
+
+The 'language examples' folder shows various aspects of object-oriented code, Blitz's array handling, etc, all commented. They're pretty dry, but provide text output that should help to understand them.
+
+The 'game examples' folder contains 'RockOut', the piece-de-resistance as far as I'm concerned! (Note that once it's compiled it can be copied anywhere with no external files required.)
+
+Enjoy!
+--
+James L Boyd,
+Blitz Support.
diff --git a/samples/hitoro/listextendedtypes.bmx b/samples/hitoro/listextendedtypes.bmx
new file mode 100644 (file)
index 0000000..9b481e7
--- /dev/null
@@ -0,0 +1,85 @@
+
+' -----------------------------------------------------------------------------
+' An example of listing a type and (just) its sub-types...
+' -----------------------------------------------------------------------------
+
+' List to which all objects are added...
+
+Global TestList:TList = New TList
+
+' Base type...
+
+Type Base
+     Field x
+     Field desc$
+End Type
+
+' Example 1...
+
+Type Test1 Extends Base
+     Field y
+End Type
+
+' Example 2...
+
+Type Test2 Extends Base
+     Field z
+End Type
+
+' -----------------------------------------------------------------------------
+' Create objects of all three types...
+' -----------------------------------------------------------------------------
+
+For a = 1 To 10
+
+    t:Base = New Base
+    t.desc = "Base Object " + a
+    TestList.AddLast t
+
+    t1:Test1 = New Test1
+    t1.desc = "Test1 Object " + a
+    TestList.AddLast t1
+
+    t2:Test2 = New Test2
+    t2.desc = "Test2 Object " + a
+    TestList.AddLast t2
+
+Next
+
+' -----------------------------------------------------------------------------
+' List all objects of Base AND Base-extended types...
+' -----------------------------------------------------------------------------
+
+Print ""
+Print "All Base and Base-extended objects..."
+Print ""
+
+For all:Base = EachIn TestList
+    Print all.desc
+Next
+
+' -----------------------------------------------------------------------------
+' List only Test1 objects from Base.TestList...
+' -----------------------------------------------------------------------------
+
+Print ""
+Print "Only Test1 objects..."
+Print ""
+
+For onlyt1:Test1 = EachIn TestList
+    Print onlyt1.desc
+Next
+
+' -----------------------------------------------------------------------------
+' List only Test2 objects from Base.TestList...
+' -----------------------------------------------------------------------------
+
+Print ""
+Print "Only Test2 objects..."
+Print ""
+
+For onlyt2:Test2 = EachIn TestList
+    Print onlyt2.desc
+Next
+
+
diff --git a/samples/hitoro/newmethod.bmx b/samples/hitoro/newmethod.bmx
new file mode 100644 (file)
index 0000000..c548544
--- /dev/null
@@ -0,0 +1,24 @@
+
+' Here's an example of using the optional New () method. You could just
+' set the x field to have a default anyway (Field x = 100) but this shows
+' that you can do other things too (in this case, print a message)...
+
+Type Oink
+
+     Field x
+
+     Method New ()
+            Print "Setting the value of x..."
+            x = 100
+     End Method
+
+End Type
+
+' Create an Oink object...
+
+o:Oink = New Oink
+
+' Print out the value of x...
+
+Print o.x
+
diff --git a/samples/hitoro/passvarptr.bmx b/samples/hitoro/passvarptr.bmx
new file mode 100644 (file)
index 0000000..d788763
--- /dev/null
@@ -0,0 +1,21 @@
+
+' This function takes the pointer to an integer variable
+' and adds 1 by treating the variable's memory as an array...
+
+Function AddToVariable (addee:Int Ptr)
+         addee [0] = addee [0] + 1
+End Function
+
+' Test variable, looking forward to a brave new world...
+
+a = 5
+
+' Pass the address of 'a' to function...
+
+AddToVariable (VarPtr (a))
+
+' The result...
+
+Print "Variable a was 5... now it's " + a
+
+
diff --git a/samples/hitoro/rockout.bmx b/samples/hitoro/rockout.bmx
new file mode 100644 (file)
index 0000000..dd9b2df
--- /dev/null
@@ -0,0 +1,1161 @@
+' -----------------------------------------------------------------------------
+' RockOut -- Rocket BlockOut
+' -----------------------------------------------------------------------------
+' Public domain source code by James L Boyd (support @ blitzbasic . com)
+' -----------------------------------------------------------------------------
+' Rocket image Â© 2004 James L Boyd, with permission granted for freeware/PD use,
+' not that anyone'd really want it anyway...!
+' -----------------------------------------------------------------------------
+
+' -----------------------------------------------------------------------------
+' Constants...
+' -----------------------------------------------------------------------------
+
+' Sizes used for blocks...
+
+Const BLOCKWIDTH = 32
+Const BLOCKHEIGHT = 16
+
+Const GRAPHICS_WIDTH = 640
+Const GRAPHICS_HEIGHT = 480
+
+Const GW2 = GRAPHICS_WIDTH / 2
+Const GH2 = GRAPHICS_HEIGHT / 2
+
+Graphics 800,600,32,60
+
+SetVirtualResolution GRAPHICS_WIDTH,GRAPHICS_HEIGHT
+
+' Pre-calc half of graphics width...
+
+' -----------------------------------------------------------------------------
+' Include media...
+' -----------------------------------------------------------------------------
+
+' Sounds (all from Yamaha RM1X!)...
+
+Incbin "sounds/shot.ogg"               ' Player shot
+Incbin "sounds/fall.ogg"               ' Block fall
+Incbin "sounds/hit.ogg"                        ' Block/player hit
+Incbin "sounds/beep.ogg"               ' 'Press space' sound
+Incbin "sounds/gameover.ogg"           ' Guess...
+
+' Graphics...
+
+Incbin "gfx/boing.png"                 ' Rocket
+Incbin "gfx/land.png"                  ' Background (used to be land, now a grid)
+Incbin "gfx/shot.png"                  ' Player's shot
+Incbin "gfx/block.png"                 ' Guess...
+
+' -----------------------------------------------------------------------------
+' Types (object definitions)...
+' -----------------------------------------------------------------------------
+
+' GravityItem: all objects affected by gravity are based upon this...
+
+Type GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific globals...
+     ' ------------------------------------------------------------------------
+
+     ' Why not make these truly global? It's cleaner -- you can just copy and
+     ' paste the type definition into a completely different program without
+     ' having to remember which globals are related...
+
+     Global GCount                     ' Count of all GravityItems (for debugging)
+     Global GravityItemList:TList      ' List used for all GravityItem objects
+     Global Gravity# = 0.05            ' Gravity applied to all GravityItems
+
+     ' ------------------------------------------------------------------------
+     ' Type fields...
+     ' ------------------------------------------------------------------------
+
+     Field x#                          ' x position of object
+     Field y#                          ' y position of object
+     Field xs#                         ' x speed of object
+     Field ys#                         ' y speed of object
+
+     Field width                       ' Width of object
+     Field height                      ' Height of object
+
+     Field damage                      ' Damage caused by this item if it hits player
+     Field fixed = False               ' Is object fixed in place? Blocks are, at first...
+
+     Field r, g, b
+
+     ' ------------------------------------------------------------------------
+     ' Type functions...
+     ' ------------------------------------------------------------------------
+
+     Function UpdateAll ()
+              If GravityItemList = Null Then Return
+              If Shadows_On Then Block.DrawShadows ' Shadows_On is a global...
+              For g:GravityItem = EachIn GravityItemList
+                  g.Update
+                  g.Draw
+              Next
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type methods...
+     ' ------------------------------------------------------------------------
+
+     ' The New method is special -- Blitz calls it whenever a new object is
+     ' created...
+
+     ' Every time a new GravityItem is created -- including objects that extend
+     ' GravityItem -- this is called. In this case, it creates the type-global
+       ' list if it doesn't yet exist (only happens once), and adds the item to it...
+
+     Method New ()
+            If GravityItemList = Null Then GravityItemList = New TList
+            GravityItemList.AddLast Self
+            GCount = GCount + 1
+     End Method
+
+     ' Destroy current object and remove from list
+     Method Destroy ()
+            GravityItemList.Remove Self
+            GCount = GCount - 1
+     End Method
+
+     ' Rectangle-based collision test of current object and player.
+     
+     ' 'The multiplier' parameter controls how much of an object's
+     ' 'damage' field applies to the player -- in the case of Block
+     ' objects, the more they're faded out, the less damage they do...
+
+     ' The 'posyonly' parameter is a hack to stop Shot objects damaging
+     ' the player while going up...
+
+     Method PlayerCollide (multiplier# = 1, posyonly = 0)
+
+            ' Offset x/y position of shots (all images' handles are centered)...
+
+            ox = x - width / 2
+            oy = y - height / 2
+
+            ' Offset x/y position of player...
+
+            opx = PlayerOne.x - PlayerOne.width / 2
+            opy = PlayerOne.y - PlayerOne.height / 2
+
+            ' Hack to stop Shot objects damaging player while going up...
+
+            check = 1
+
+            If posyonly
+               If ys < 0
+                  check = 0
+               EndIf
+            EndIf
+
+            ' Test for collision, apply damage and make explosion...
+
+            If check
+               If OverLap (ox, oy, ox + width, oy + height, opx, opy, opx + PlayerOne.width, opy + PlayerOne.height)
+                  PlayerOne.shields = PlayerOne.shields - damage * multiplier
+                  ExplosionParticle.Explode x, y, damage * 5 * multiplier
+                  PlayerOne.damaged = MilliSecs ()
+                  Return True
+               EndIf
+            EndIf
+
+     End Method
+
+     ' There is no default Draw method here, as it's different for each extended type
+     ' of GravityItem, so I've defined it as Abstract...
+
+     ' Abstract forces every type that extends GravityItem to have a Draw () method defined
+     ' or the code simply won't compile...
+
+     ' One practical use for this is that you can call Draw from any random GravityItem,
+     ' regardless of which extended type it is, and this will call the correct Draw ()
+     ' for the type of object in question...
+
+     Method Draw () Abstract
+
+     ' Abstract Update method for GravityItems. See Draw () explanation...
+
+     Method Update () Abstract
+
+End Type
+
+' Particles created in an explosion. This type extends GravityItem, meaning all
+' properties of GravityItem apply, except where methods are over-ridden
+' (ie. re-defined) here...
+
+Type ExplosionParticle Extends GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type fields...
+     ' ------------------------------------------------------------------------
+
+     ' No need to define, x, y, xs, ys, etc as they're part of the GravityItem definition...
+
+     Field alph# = 1.0          ' Alpha level of particle (translucency)
+
+     ' ------------------------------------------------------------------------
+     ' Type functions...
+     ' ------------------------------------------------------------------------
+
+     ' Create explosion of particles, and play sound...
+
+     Function Explode (x#, y#, particles)
+
+              ' NB. GW2 is a global set to half of GRAPHICS_WIDTH...
+
+              If Sounds_On
+                 pan# = x / GW2 - 1.0
+                 play = CueSound (hit)
+                 SetChannelPan play, pan
+                 ResumeChannel play
+              EndIf
+
+              For loop = 1 To particles
+                  ExplosionParticle.Create (x, y)
+              Next
+
+     End Function
+
+     ' Create single explosion particle. Note that any items extending GravityItem
+     ' will call the New () method from GravityItem upon creation, so these will
+     ' be added to the GravityItem list automatically...
+
+     Function Create:ExplosionParticle (x, y)
+
+              e:ExplosionParticle = New ExplosionParticle
+              e.x = x
+              e.y = y
+              e.xs = Rnd (-8, 8)
+              e.ys = Rnd (-8, 8)
+
+              ' Random colour...
+
+              Select Rand (0, 3)
+                     Case 0
+                          e.r = 255
+                          e.g = 255
+                          e.b = 255
+                     Case 1
+                          e.r = 255
+                          e.g = 127
+                          e.b = 0
+                     Case 2
+                          e.r = 255
+                          e.g = 255
+                          e.b = 0
+                     Case 3
+                          e.r = 255
+                          e.g = 0
+                          e.b = 0
+              End Select
+
+              ' Random size...
+
+              size = Rand (1, 8)
+              e.width = size
+              e.height = size
+
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type methods...
+     ' ------------------------------------------------------------------------
+
+     ' Update () over-rides the GravityItem Update () method...
+
+     Method Update ()
+
+        ' Reduce alpha level of particle...
+
+        alph = alph - 0.01
+
+        ' Apply Gravity global (see GravityItem) to y speed...
+
+        ys = ys + Gravity
+
+        ' Move particle by current speed...
+
+        x = x + xs
+        y = y + ys
+        
+        ' If off-screen or reduced to invisible, remove from list by
+        ' calling the Destroy method (inherited from GravityItem)...
+
+        If y > GRAPHICS_HEIGHT Or alph = 0 Then Destroy
+
+     End Method
+
+     ' Draw particle...
+
+     Method Draw ()
+
+            SetScale 1, 1
+
+            SetBlend ALPHABLEND
+
+            SetAlpha alph
+            SetColor r, g, b
+            DrawRect x, y, width, height
+
+     End Method
+
+End Type
+
+' Block definition. Again, Block is a kind of GravityItem...
+
+Type Block Extends GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific globals...
+     ' ------------------------------------------------------------------------
+
+     Global BCount            ' Number of blocks
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific fields...
+     ' ------------------------------------------------------------------------
+
+     Field alph# = 1.0        ' Alpha level of block
+     Field ang#               ' Rotation of block
+     Field angspeed#          ' Rotation speed of block
+     Field desty#
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific function...
+     ' ------------------------------------------------------------------------
+
+     ' Create a Block object (added to GravityItem list automatically)...
+
+     Function Create:Block (x, y)
+              blk:Block = New Block
+              blk.x = x
+              blk.y = y
+              blk.desty = y
+              blk.width = BLOCKWIDTH
+              blk.height = BLOCKHEIGHT
+              blk.fixed = True
+              blk.damage = 20
+              BCount = BCount + 1
+              Return blk
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     ' Update () method for Block objects...
+
+     Method Update ()
+
+            ' Check for collision (passing alpha level of block to apply
+            ' appropriate damage), and remove from GravityItem list if hit...
+
+            If PlayerCollide (alph) Then BCount = BCount - 1; Destroy; Return
+
+            ' If the block has been freed (by being hit), make it fall...
+
+            If Not fixed
+
+               alph = alph - 0.0075; If alph < 0 Then alph = 0
+               ang = ang + angspeed; If ang > 359 Then ang = 0
+               ys = ys + Gravity
+               x = x + xs
+               y = y + ys
+
+               If y > GRAPHICS_HEIGHT Or alph = 0 Destroy; BCount = BCount - 1
+
+            Else
+
+                ' When blocks are lowered in main loop, they are just set to 'desty',
+                ' their new y-position destination. This moves them towards that...
+
+                ydist# = desty - y
+                ys = ydist / 12.0
+                y = y + ys
+
+            EndIf
+
+     End Method
+
+     ' Block-specific Draw () method...
+
+     Method Draw ()
+
+            SetBlend ALPHABLEND
+            SetRotation ang
+
+            SetColor r, g, b
+            SetAlpha alph
+
+            DrawImage BlockImage, x, y
+
+            SetRotation 0
+
+     End Method
+
+     Function DrawShadows ()
+              SetBlend ALPHABLEND
+              For blk:Block = EachIn GravityItemList
+                   SetRotation blk.ang
+                   SetColor 0, 0, 0
+                   SetAlpha blk.alph * 0.25
+                   DrawImage BlockImage, blk.x + 8, blk.y + 8
+              Next
+     End Function
+
+End Type
+
+' Player object. Only one player possible right now, but this keeps everything
+' together for easy reference...
+
+Type Player
+
+     Field damaged    ' Set to MilliSecs () when hit (used for flashing effect)
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific fields...
+     ' ------------------------------------------------------------------------
+
+       ' The shields field is a float so I can reduce by small amounts, but I use
+       ' Int (PlayerOne.shields) to display/evaluate it...
+
+     Field shields# = 100
+
+     Field x#
+     Field y#
+     Field xs#
+     Field ys#
+
+     Field image      ' Player image...
+
+     Field width
+     Field height
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific functions...
+     ' ------------------------------------------------------------------------
+
+       ' Create () is a function that creates & returns a :Player type object...
+
+     Function Create:Player (x, y, image)
+              PlayerOne:Player = New Player
+              PlayerOne.image = image
+              PlayerOne.x = x
+              PlayerOne.y = y
+              PlayerOne.width = ImageWidth (PlayerOne.image) * 0.2     ' Image is scaled in Draw ()
+              PlayerOne.height = ImageHeight (PlayerOne.image) * 0.2
+              Return PlayerOne
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     ' This is passed the MouseX () and MouseY () positions in the main game
+       ' loop, and hence moves the player toward the mouse cursor...
+
+     Method Move (destx#, desty#, div#)
+            xdist# = destx - x
+            ydist# = desty - y
+            xs = xdist / div
+            ys = ydist / div
+            x = x + xs
+            y = y + ys
+     End Method
+
+     Method Draw (alpha# = 1, r = 255, g = 255, b = 255)
+
+            SetBlend ALPHABLEND
+            SetScale 0.2, 0.2
+
+            If Shadows_On
+               SetColor 0, 0, 0
+               SetAlpha alpha * 0.4
+               DrawImage image, x + 8, y + 8
+            EndIf
+
+            SetAlpha alpha
+
+               ' If player is damaged, rgb will be RED...
+
+            SetColor r, g, b
+            DrawImage image, x, y
+            SetScale 1, 1
+
+     End Method
+
+End Type
+
+Type Shot Extends GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific functions...
+     ' ------------------------------------------------------------------------
+
+     Function Create:Shot (x#, y#, ys#, xs#, soundpan#)
+            If Sounds_On
+               play = CueSound (shoot)
+               SetChannelPan play, soundpan
+               ResumeChannel play
+            EndIf
+            s:Shot = New Shot
+            s.x = x
+            s.y = y
+            s.xs = xs
+            s.ys = ys
+            s.width = 6
+            s.height = 6
+            s.damage = 2
+            Return s
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     ' Over-ride standard GravityItem Update () method...
+
+     Method Update ()
+
+        ' Hit the player (note 'posyonly', 2nd parameter, of PlayerCollide)...
+
+        If PlayerCollide (1, 1) Then Destroy; Return
+
+        ys = ys + Gravity
+        x = x + xs
+        y = y + ys
+
+        ' Remove if below bottom of screen...
+
+        If y > GRAPHICS_HEIGHT
+
+           Destroy
+
+        Else
+
+            ' Check current Shot against all Blocks...
+
+            ' (Notice that this only checks Block objects in the list!)
+
+            For blk:Block = EachIn GravityItemList
+
+                ' Get x offset (rectangles are mid-handled)...
+
+                ox = x - width / 2
+                oy = y - height / 2
+
+                ogx = blk.x - blk.width / 2
+                ogy = blk.y - blk.width / 2
+
+                ' Check collision...
+
+                If OverLap (ox, oy, ox + width, oy + height, ogx, ogy, ogx + blk.width, ogy + blk.height)
+
+                   ' If Block is already dead (ie. falling), reflect Shot, otherwise
+                   ' un-fix block and create explosion...
+
+                   ' Note: ys is current Shot object's y speed...
+
+                   If blk.fixed = False
+                      ys = -ys
+                   Else
+                      blk.fixed = False
+                      blk.ys = ys / Rnd (1, 4)
+                      blk.angspeed = Rnd (-4, 4)
+                      ExplosionParticle.Explode ogx, ogy, 4
+                   EndIf
+
+                EndIf
+
+            Next
+
+        EndIf
+
+     End Method
+
+     Method Draw ()
+            SetBlend MASKBLEND
+            SetAlpha 1
+            SetColor 255, 255, 255
+            DrawImage ShotImage, x, y
+     End Method
+
+End Type
+
+' The random debris that falls 'down' the screen...
+
+Type DebrisItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific fields...
+     ' ------------------------------------------------------------------------
+
+     Field x# = Rand (0, GRAPHICS_WIDTH - 1)
+     Field y# = Rand (0, GRAPHICS_HEIGHT - 1)
+     Field ys# = Rnd (0.01, 8)
+     Field size = Rand (1, 2)
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     Method Update ()
+            If y > GRAPHICS_HEIGHT y = 0
+            y = y + ys
+            SetColor Rnd (127, 255), Rnd (127, 255), 255
+            SetBlend SOLIDBLEND
+            DrawRect x, y, size, size
+     End Method
+
+End Type
+
+' -----------------------------------------------------------------------------
+' Functions...
+' -----------------------------------------------------------------------------
+
+' Draw simple text with shadow...
+
+Function DrawShadowText (t$, x, y)
+       SetHandle 0,0
+      SetRotation 0
+      SetColor 0, 0, 0
+      DrawText t$, x + 1, y + 1
+      SetColor 255, 255, 255
+      DrawText t$, x, y
+       SetHandle .5,.5
+End Function
+
+' Draw stuff in wireframe mode...
+
+Function WireFrame (enable = True)
+         If enable
+            glPolygonMode (GL_FRONT_AND_BACK, GL_LINE)
+         Else
+            glPolygonMode (GL_FRONT_AND_BACK, GL_FILL)
+         EndIf
+End Function
+
+' Draw stuff in point mode...
+
+Function Point (enable = True)
+         If enable
+            glPolygonMode (GL_FRONT_AND_BACK, GL_POINT)
+         Else
+            glPolygonMode (GL_FRONT_AND_BACK, GL_FILL)
+         EndIf
+End Function
+
+' Returns "Off" if 'status' is 0, otherwise "On"...
+
+Function OnOff$ (status)
+         If status Then Return "On" Else Return "Off"
+End Function
+
+' Phew! Thanks, Birdie! Rectangular overlap function. Should have been so easy...
+
+Function OverLap (x0, y0, x1, y1, x2, y2, x3, y3)
+       If x0 > x3 Or x1 < x2 Then Return False
+       If y0 > y3 Or y1 < y2 Then Return False
+       Return True
+End Function
+
+' Distance between two points...
+
+Function Dist# (x0#, y0#, x1#, y1#)
+         Return Sqr (((x1 - x0) * (x1 - x0)) + ((y1 - y0) * (y1 - y0)))
+End Function
+
+' -----------------------------------------------------------------------------
+' Main game. This is where it all goes pear-shaped!
+' -----------------------------------------------------------------------------
+
+' Open display...
+
+' Set Cls colour (used when background turned off)...
+
+SetClsColor 64, 96, 128
+
+' All images' and rectangles' handles should be set to the centre...
+
+AutoMidHandle True
+SetHandle 0.5, 0.5
+
+' All images mipped...
+
+AutoImageFlags MASKEDIMAGE|FILTEREDIMAGE|MIPMAPPEDIMAGE
+
+' Mask colour for loaded images (will be transparent)...
+
+SetMaskColor 255, 0, 255
+
+' Mouse position -- used in some type methods and functions, hence global...
+
+Global mx, my
+
+' Player object...
+
+Global PlayerOne:Player
+
+' Draw shadows?
+
+Global Shadows_On = True
+
+' Turn off sound?
+
+Global Sounds_On = True
+
+' Load media -- sounds, from included binaries (see start of code)...
+
+Global shoot = LoadSound ("incbin::sounds/shot.ogg")
+Global hit   = LoadSound ("incbin::sounds/hit.ogg")
+Global beep  = LoadSound ("incbin::sounds/beep.ogg")
+Global over  = LoadSound ("incbin::sounds/gameover.ogg")
+
+' Load media -- images, from included binaries...
+
+' Shots...
+
+Global ShotImage = LoadImage ("incbin::gfx/shot.png")
+
+' Blocks...
+
+' Note there is only one image for all blocks -- they are altered by SetColorRGB before
+' drawing (WHITE gives normal image)...
+
+Global BlockImage = LoadImage ("incbin::gfx/block.png")
+
+' Player...
+
+pimage = LoadImage ("incbin::gfx/boing.png")           ',MASKEDIMAGE|MIPMAPPEDIMAGE)
+
+' Background...
+
+' Note that bgscale stores the length of the screen diagonal, and this value is used
+' for the image height, so it doesn't get chopped when it rotates...
+
+bg = LoadImage ("incbin::gfx/land.png")
+bgscale# = Dist (0, 0, GRAPHICS_WIDTH - 1, GRAPHICS_HEIGHT - 1) / ImageHeight (bg)
+
+' Background angle/speed of rotation...
+
+bgang# = 0
+bgangspeed# = 0
+
+' Create an array of 100 debris particles...
+
+Local debris:DebrisItem [100]
+For loop = 0 Until 100
+    debris [loop] = New DebrisItem
+Next
+
+' This should probably read 'rows' -- the number of rows of blocks at startup...
+
+layers = 5
+
+' Toggle variables for drawing background, debris and wireframe mode...
+
+bgtoggle = 1
+debristoggle = 1
+wftoggle = 0
+
+' Delay before adding another row of blocks (this is decreased as the game progresses)...
+
+rowdelay = 10000 ' 10 seconds (10000 milliseconds)...
+
+' Background colour and first target colour...
+
+backr# = 64
+backg# = 96
+backb# = 180
+
+backtr# = 128
+backtg# = 32
+backtb# = 48
+
+' Delay between colour increments...
+
+backstep# = 5000
+
+' Colour increments...
+
+backstepr# = (backtr - backr) / backstep
+backstepg# = (backtg - backg) / backstep
+backstepb# = (backtb - backb) / backstep
+
+' Direction of increment to target colour...
+
+backsgn = Sgn (backtr - backr)
+
+' This is the point where the game is re-started from, whenever a level is completed or game ended...
+
+#ResetLevel ' $name signifies a label now...
+
+' Increase level number (level is 0 on startup, so becomes 1 for first level)...
+
+level = level + 1
+
+' Reset the 'new row' delay timer to the current time...
+
+rowtimer = MilliSecs ()
+
+' Set fire rate limiter to current time...
+
+firetimer = MilliSecs ()
+
+' Create rows of blocks...
+
+For y = 0 To layers - 1
+    For x = 0 Until GRAPHICS_WIDTH Step BLOCKWIDTH
+        b:Block = Block.Create (x + BLOCKWIDTH / 2, (y * BLOCKHEIGHT) + BLOCKHEIGHT / 2)
+        b.r = Rnd (127, 255)
+        b.g = Rnd (127, 255)
+        b.b = Rnd (127, 255)
+    Next
+Next
+
+' Minimum number of blocks left before we *stop* dropping them down (equivalent of 2 rows)...
+
+lowblocks = 2 * (GRAPHICS_WIDTH / BLOCKWIDTH)
+
+' When a level is completed, we delete the player object for simplicity of resetting
+' all its values. This creates it (same for game startup)...
+
+If PlayerOne = Null Then PlayerOne = Player.Create (VirtualMouseX (), VirtualMouseY (), pimage)
+
+' Don't show the mouse pointer; gonna draw our own...
+
+HideMouse
+
+' Game text and precalculated x offsets...
+
+go$ = "G A M E   O V E R   --   H I T   S P A C E   O R   R M B"
+wd$ = "W E L L   D O N E   --   H I T   S P A C E   O R   R M B"
+
+gox = (GRAPHICS_WIDTH / 2) - (TextWidth (go$) / 2)
+wdx = (GRAPHICS_WIDTH / 2) - (TextWidth (wd$) / 2)
+
+Repeat
+
+      ' Clear the screen...
+
+      Cls
+
+      ' Store mouse position in these global variables...
+
+      mx = VirtualMouseX ()
+      my = VirtualMouseY ()
+
+      ' -----------------------------------------------------------------------
+      ' Toggles...
+      ' -----------------------------------------------------------------------
+
+      If KeyHit (KEY_F1) Then bgtoggle = 1 - bgtoggle                            ' Background
+      If KeyHit (KEY_F2) Then debristoggle = 1 - debristoggle                    ' Debris
+      If KeyHit (KEY_F3) Then wftoggle = 1 - wftoggle; WireFrame wftoggle        ' Wireframe *
+      If KeyHit (KEY_F4) Then Sounds_On = 1 - Sounds_On                          ' Sound
+      If KeyHit (KEY_F5) Then Shadows_On = 1 - Shadows_On                        ' Shadows
+
+      ' * Wireframe worked when the game used rectangles instead of images for blocks!
+      
+      ' -----------------------------------------------------------------------
+      ' Background...
+      ' -----------------------------------------------------------------------
+
+      ' Update background rotation...
+
+      bgang = bgang + bgangspeed; If bgang > 359 - bgangspeed Then bgang = 0
+      bgangspeed = bgangspeed + 0.0001
+
+      ' The bgtoggle variable controls whether the background should be drawn or not...
+
+      If bgtoggle
+
+              ' Turn off wireframe mode (if it's on)...
+
+              If wftoggle Then WireFrame False
+
+              ' Change colour by pre-calculated increment...
+
+              backr = backr + backstepr
+              backg = backg + backstepg
+              backb = backb + backstepb
+
+              ' Reached target colour? Set a new target/increments/increment-direction...
+
+              If backr => backtr * backsgn
+                  backtr = Rnd (255)
+                  backtg = Rnd (255)
+                  backtb = Rnd (255)
+                  backstepr# = (backtr - backr) / backstep
+                  backstepg# = (backtg - backg) / backstep
+                  backstepb# = (backtb - backb) / backstep
+                  backsgn = Sgn (backtr - backr)
+              EndIf
+
+              ' Set colour of background image (applied to the greyscale default)...
+
+              SetColor backr, backg, backb
+
+              ' Set the background's pre-calculated scale...
+
+              SetScale bgscale, bgscale
+              SetRotation bgang
+              SetAlpha 1
+
+              DrawImage bg, GW2, GH2
+
+              ' Reset this stuff so next drawn items don't have to...
+
+              SetRotation 0
+              SetScale 1, 1
+
+              ' Put back to wireframe/non-wireframe mode, depending on value of 'wftoggle'...
+
+              WireFrame wftoggle
+
+      EndIf
+
+      ' -----------------------------------------------------------------------
+      ' Debris...
+      ' -----------------------------------------------------------------------
+
+      ' Draw debris particles if 'debristoggle' is True...
+
+      If debristoggle
+         For loop = 0 Until 100
+             debris [loop].Update
+         Next
+      EndIf
+
+      ' -----------------------------------------------------------------------
+      ' Cursor...
+      ' -----------------------------------------------------------------------
+
+      SetColor 255, 255, 255
+      DrawLine mx - 8, my, mx + 8, my
+      DrawLine mx, my - 8, mx, my + 8
+
+      ' -----------------------------------------------------------------------
+      ' Move and draw player...
+      ' -----------------------------------------------------------------------
+
+      ' Move the player object based on mouse position (the '20' controls the
+      ' speed at which the player moves toward the mouse -- play with it;
+      ' lower is faster)...
+
+      PlayerOne.Move (mx, my, 12)
+
+       ' Turn wireframe off if still on, before drawing player...
+
+      If wftoggle Then WireFrame False
+
+      ' When the player is hit, the 'damaged' field is set to the current time.
+      ' This code checks if a second has passed since 'damaged'. If so, it draws
+       ' the player normally; if not, the player is drawn in red, with varying
+       ' transparency...
+
+      If MilliSecs () > PlayerOne.damaged + 1000 ' Damage timeout has passed...
+
+         ' Draw normally...
+
+         PlayerOne.damaged = 0 ' Resetting damage time...
+         alpha# = 1
+         rcol = 255; gcol = 255; bcol = 255
+
+      Else
+
+          ' Flash player for 1 second if hit...
+
+          alpha# = Sin (MilliSecs ())
+          rcol = 255; gcol = 0; bcol = 0
+
+      EndIf
+
+      ' Draw the player using the above values...
+
+      PlayerOne.Draw (alpha, rcol, gcol, bcol)
+
+      ' Reset the wireframe mode according to 'w'...
+
+      WireFrame wftoggle
+
+      ' -----------------------------------------------------------------------
+      ' If player is alive, do stuff...
+      ' -----------------------------------------------------------------------
+
+      If Int (PlayerOne.shields) > 0 ' Shields is a float, so gotta round it...
+
+         ' Player is alive...
+
+         ' If more than 'lowblocks' left on screen, add a row and lower all
+         ' blocks. Reset drop-down timer and reduce delay for next drop-down...
+
+         If Block.BCount > lowblocks And MilliSecs () > rowtimer + rowdelay
+
+            ' Add a row of blocks, above top of screen...
+
+            For x = 0 Until GRAPHICS_WIDTH Step BLOCKWIDTH
+                b:Block = Block.Create (x + BLOCKWIDTH / 2, -BLOCKHEIGHT / 2)
+                b.r = Rnd (127, 255)
+                b.g = Rnd (127, 255)
+                b.b = Rnd (127, 255)
+            Next
+
+            ' Set all blocks' target y position down by block height. When blocks
+            ' are updated, they get moved towards this new position...
+
+            For b:Block = EachIn GravityItem.GravityItemList
+                b.desty = b.desty + BLOCKHEIGHT
+            Next
+
+            ' Reset timeout until a new row is added...
+
+            rowtimer = MilliSecs ()
+
+            ' Reduce row-down timeout a bit...
+
+            If rowdelay => 1100 Then rowdelay = rowdelay - 100 ' Minimum 1 sec interval!
+
+         EndIf
+
+         ' --------------------------------------------------------------------
+         ' Fire shot (maximum fire rate 75 milliseconds)...
+         ' --------------------------------------------------------------------
+
+         If MouseDown (1)
+            If MilliSecs () > firetimer + 75
+               pan# = PlayerOne.x / GW2 - 1.0
+               s:Shot = Shot.Create (PlayerOne.x, PlayerOne.y - (PlayerOne.height / 2 + 5), -5, PlayerOne.xs / 5.0, pan)
+               firetimer = MilliSecs ()
+            EndIf
+         EndIf
+
+         ' --------------------------------------------------------------------
+         ' No blocks left?
+         ' --------------------------------------------------------------------
+
+         ' Set 'welldone' flag (text shows "Well done" below if True);
+
+         ' If there are no blocks and Space is hit, delete all GravityItems,
+         ' reduce block count, increase number of block rows and reset level...
+
+         If Block.BCount = 0
+
+            ' Will display 'well done' message further down...
+
+            welldone = True
+
+            ' Remove all items (and reduce block count)...
+
+            For g:GravityItem = EachIn GravityItem.GravityItemList
+                If Block (g) Then Block.BCount = Block.BCount - 1
+                g.Destroy
+            Next
+
+            ' If space is hit, add some layers and reset everything (new level)...
+
+            If KeyHit (KEY_SPACE) Or MouseHit (2)
+               If Sounds_On Then PlaySound beep
+               layers = layers + 3
+               Goto ResetLevel
+            EndIf
+
+         EndIf
+
+      Else
+
+          If gameoverplayed = 0
+             If Sounds_On Then PlaySound over
+             gameoverplayed = 1
+          EndIf
+
+          ' Player is dead...
+
+          PlayerOne.shields = 0 ' Force to zero as can be reduced after game is over...
+
+          gameover = True
+
+          ' Remove all blocks...
+
+          For b:Block = EachIn GravityItem.GravityItemList
+              b.Destroy
+              Block.BCount = Block.BCount - 1
+          Next
+
+          ' -------------------------------------------------------------------
+          ' If player is dead and Space hit...
+          ' -------------------------------------------------------------------
+
+          ' Space hit... remove everything else and reset to inital settings...
+
+          If KeyHit (KEY_SPACE) Or MouseHit (2)
+
+             If Sounds_On Then PlaySound beep
+
+             For g:GravityItem = EachIn GravityItem.GravityItemList
+                 g.Destroy
+             Next
+
+             ' Delete player (recreated when level is reset)...
+
+             PlayerOne = Null
+             layers = 5
+             bgang = 0
+             bgangspeed = 0
+             level = 0
+             rowdelay = 10000
+
+             gameoverplayed = 0
+
+             Goto ResetLevel
+
+          Else
+
+              ' Quit if ESC hit...
+
+              If KeyHit (KEY_ESCAPE) Then End
+
+          EndIf
+
+      EndIf
+
+      ' -----------------------------------------------------------------------
+      ' Update everything...
+      ' -----------------------------------------------------------------------
+
+      GravityItem.UpdateAll
+
+      ' -----------------------------------------------------------------------
+      ' Draw text on top of everything...
+      ' -----------------------------------------------------------------------
+
+      SetAlpha 1
+
+      DrawShadowText "Level: " + level + " | Shields: " + Int (PlayerOne.shields) + "%", 20, GRAPHICS_HEIGHT - 80
+      DrawShadowText "GCMemAlloced:"+GCMemAlloced(),20,GRAPHICS_HEIGHT - 60
+      DrawShadowText "F1: Toggle background | F3: Wireframe mode | F5: Toggle shadows", 20, GRAPHICS_HEIGHT - 40
+      DrawShadowText "F2: Toggle debris     | F4: Toggle audio (" + OnOff (Sounds_On) + ")", 20, GRAPHICS_HEIGHT - 20
+
+      ' Draw extra text if appropriate...
+
+      If gameover
+         DrawShadowText go$, gox, GRAPHICS_HEIGHT / 2
+         gameover = False
+      Else
+         If welldone
+            DrawShadowText wd$, wdx, GRAPHICS_HEIGHT / 2
+            welldone = False
+         EndIf
+      EndIf
+
+      ' Display everything that's been drawn to the hidden back buffer...
+
+       GCCollect
+       Flip True
+
+Until KeyHit (KEY_ESCAPE)
+
+End
diff --git a/samples/hitoro/rockout_gui.bmx b/samples/hitoro/rockout_gui.bmx
new file mode 100644 (file)
index 0000000..8f2cfc5
--- /dev/null
@@ -0,0 +1,1229 @@
+
+' Hacked-into-GUI version! It's not pretty, but still, it's only meant to
+' demonstrate a windowed game with GUI!
+
+' -----------------------------------------------------------------------------
+' RockOut -- Rocket BlockOut
+' -----------------------------------------------------------------------------
+' Public domain source code by James L Boyd (support @ blitzbasic . com)
+' -----------------------------------------------------------------------------
+' Rocket image Â© 2004 James L Boyd, with permission granted for freeware/PD use,
+' not that anyone'd really want it anyway...!
+' -----------------------------------------------------------------------------
+
+' -----------------------------------------------------------------------------
+' Constants...
+' -----------------------------------------------------------------------------
+
+' Sizes used for blocks...
+Import MaxGUI.Drivers
+
+Const BLOCKWIDTH = 32
+Const BLOCKHEIGHT = 16
+
+' -----------------------------------------------------------------------------
+' Include media...
+' -----------------------------------------------------------------------------
+
+' Sounds (all from Yamaha RM1X!)...
+
+Incbin "sounds/shot.ogg"               ' Player shot
+Incbin "sounds/fall.ogg"               ' Block fall
+Incbin "sounds/hit.ogg"                        ' Block/player hit
+Incbin "sounds/beep.ogg"               ' 'Press space' sound
+Incbin "sounds/gameover.ogg"           ' Guess...
+
+' Graphics...
+
+Incbin "gfx/boing.png"                 ' Rocket
+Incbin "gfx/land.png"                  ' Background (used to be land, now a grid)
+Incbin "gfx/shot.png"                  ' Player's shot
+Incbin "gfx/block.png"                 ' Guess...
+
+' -----------------------------------------------------------------------------
+' Types (object definitions)...
+' -----------------------------------------------------------------------------
+
+' GravityItem: all objects affected by gravity are based upon this...
+
+Type GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific globals...
+     ' ------------------------------------------------------------------------
+
+     ' Why not make these truly global? It's cleaner -- you can just copy and
+     ' paste the type definition into a completely different program without
+     ' having to remember which globals are related...
+
+     Global GCount                     ' Count of all GravityItems (for debugging)
+     Global GravityItemList:TList      ' List used for all GravityItem objects
+     Global Gravity# = 0.05            ' Gravity applied to all GravityItems
+
+     ' ------------------------------------------------------------------------
+     ' Type fields...
+     ' ------------------------------------------------------------------------
+
+     Field x#                          ' x position of object
+     Field y#                          ' y position of object
+     Field xs#                         ' x speed of object
+     Field ys#                         ' y speed of object
+
+     Field width                       ' Width of object
+     Field height                      ' Height of object
+
+     Field damage                      ' Damage caused by this item if it hits player
+     Field fixed = False               ' Is object fixed in place? Blocks are, at first...
+
+     Field r, g, b
+
+     ' ------------------------------------------------------------------------
+     ' Type functions...
+     ' ------------------------------------------------------------------------
+
+     Function UpdateAll ()
+              If GravityItemList = Null Then Return
+              If Shadows_On Then Block.DrawShadows ' Shadows_On is a global...
+              For g:GravityItem = EachIn GravityItemList
+                  g.Update
+                  g.Draw
+              Next
+     End Function
+
+'      Function DrawAll ()
+'              If Shadows_On Then Block.DrawShadows ' Shadows_On is a global...
+'              For g:GravityItem = EachIn GravityItemList
+'                  g.Draw
+'              Next
+'      End Function
+       
+     ' ------------------------------------------------------------------------
+     ' Type methods...
+     ' ------------------------------------------------------------------------
+
+     ' The New method is special -- Blitz calls it whenever a new object is
+     ' created...
+
+     ' Every time a new GravityItem is created -- including objects that extend
+     ' GravityItem -- this is called. In this case, it creates the type-global
+       ' list if it doesn't yet exist (only happens once), and adds the item to it...
+
+     Method New ()
+            If GravityItemList = Null Then GravityItemList = New TList
+            GravityItemList.AddLast Self
+            GCount = GCount + 1
+     End Method
+
+     ' Destroy current object and remove from list
+     Method Destroy ()
+            GravityItemList.Remove Self
+            GCount = GCount - 1
+     End Method
+
+     ' Rectangle-based collision test of current object and player.
+     
+     ' 'The multiplier' parameter controls how much of an object's
+     ' 'damage' field applies to the player -- in the case of Block
+     ' objects, the more they're faded out, the less damage they do...
+
+     ' The 'posyonly' parameter is a hack to stop Shot objects damaging
+     ' the player while going up...
+
+     Method PlayerCollide (multiplier# = 1, posyonly = 0)
+
+            ' Offset x/y position of shots (all images' handles are centered)...
+
+            ox = x - width / 2
+            oy = y - height / 2
+
+            ' Offset x/y position of player...
+
+            opx = PlayerOne.x - PlayerOne.width / 2
+            opy = PlayerOne.y - PlayerOne.height / 2
+
+            ' Hack to stop Shot objects damaging player while going up...
+
+            check = 1
+
+            If posyonly
+               If ys < 0
+                  check = 0
+               EndIf
+            EndIf
+
+            ' Test for collision, apply damage and make explosion...
+
+            If check
+               If OverLap (ox, oy, ox + width, oy + height, opx, opy, opx + PlayerOne.width, opy + PlayerOne.height)
+                  PlayerOne.shields = PlayerOne.shields - damage * multiplier
+                  ExplosionParticle.Explode x, y, damage * 5 * multiplier
+                  PlayerOne.damaged = MilliSecs ()
+                  Return True
+               EndIf
+            EndIf
+
+     End Method
+
+     ' There is no default Draw method here, as it's different for each extended type
+     ' of GravityItem, so I've defined it as Abstract...
+
+     ' Abstract forces every type that extends GravityItem to have a Draw () method defined
+     ' or the code simply won't compile...
+
+     ' One practical use for this is that you can call Draw from any random GravityItem,
+     ' regardless of which extended type it is, and this will call the correct Draw ()
+     ' for the type of object in question...
+
+     Method Draw () Abstract
+
+     ' Abstract Update method for GravityItems. See Draw () explanation...
+
+     Method Update () Abstract
+
+End Type
+
+' Particles created in an explosion. This type extends GravityItem, meaning all
+' properties of GravityItem apply, except where methods are over-ridden
+' (ie. re-defined) here...
+
+Type ExplosionParticle Extends GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type fields...
+     ' ------------------------------------------------------------------------
+
+     ' No need to define, x, y, xs, ys, etc as they're part of the GravityItem definition...
+
+     Field alph# = 1.0          ' Alpha level of particle (translucency)
+
+     ' ------------------------------------------------------------------------
+     ' Type functions...
+     ' ------------------------------------------------------------------------
+
+     ' Create explosion of particles, and play sound...
+
+     Function Explode (x#, y#, particles)
+
+              ' NB. GW2 is a global set to half of GraphicsWidth ()...
+
+              If Sounds_On
+                 pan# = x / GW2 - 1.0
+                 play = CueSound (hit)
+                 SetChannelPan play, pan
+                 ResumeChannel play
+              EndIf
+
+              For loop = 1 To particles
+                  ExplosionParticle.Create (x, y)
+              Next
+
+     End Function
+
+     ' Create single explosion particle. Note that any items extending GravityItem
+     ' will call the New () method from GravityItem upon creation, so these will
+     ' be added to the GravityItem list automatically...
+
+     Function Create:ExplosionParticle (x, y)
+
+              e:ExplosionParticle = New ExplosionParticle
+              e.x = x
+              e.y = y
+              e.xs = Rnd (-8, 8)
+              e.ys = Rnd (-8, 8)
+
+              ' Random colour...
+
+              Select Rand (0, 3)
+                     Case 0
+                          e.r = 255
+                          e.g = 255
+                          e.b = 255
+                     Case 1
+                          e.r = 255
+                          e.g = 127
+                          e.b = 0
+                     Case 2
+                          e.r = 255
+                          e.g = 255
+                          e.b = 0
+                     Case 3
+                          e.r = 255
+                          e.g = 0
+                          e.b = 0
+              End Select
+
+              ' Random size...
+
+              size = Rand (1, 8)
+              e.width = size
+              e.height = size
+
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type methods...
+     ' ------------------------------------------------------------------------
+
+     ' Update () over-rides the GravityItem Update () method...
+
+     Method Update ()
+
+        ' Reduce alpha level of particle...
+
+        alph = alph - 0.01
+
+        ' Apply Gravity global (see GravityItem) to y speed...
+
+        ys = ys + Gravity
+
+        ' Move particle by current speed...
+
+        x = x + xs
+        y = y + ys
+        
+        ' If off-screen or reduced to invisible, remove from list by
+        ' calling the Destroy method (inherited from GravityItem)...
+
+        If y > GraphicsHeight () Or alph = 0 Then Destroy
+
+     End Method
+
+     ' Draw particle...
+
+     Method Draw ()
+
+            SetScale 1, 1
+
+            SetBlend ALPHABLEND
+
+            SetAlpha alph
+            SetColor r, g, b
+            DrawRect x, y, width, height
+
+     End Method
+
+End Type
+
+' Block definition. Again, Block is a kind of GravityItem...
+
+Type Block Extends GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific globals...
+     ' ------------------------------------------------------------------------
+
+     Global BCount            ' Number of blocks
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific fields...
+     ' ------------------------------------------------------------------------
+
+     Field alph# = 1.0        ' Alpha level of block
+     Field ang#               ' Rotation of block
+     Field angspeed#          ' Rotation speed of block
+     Field desty#
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific function...
+     ' ------------------------------------------------------------------------
+
+     ' Create a Block object (added to GravityItem list automatically)...
+
+     Function Create:Block (x, y)
+              blk:Block = New Block
+              blk.x = x
+              blk.y = y
+              blk.desty = y
+              blk.width = BLOCKWIDTH
+              blk.height = BLOCKHEIGHT
+              blk.fixed = True
+              blk.damage = 20
+              BCount = BCount + 1
+              Return blk
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     ' Update () method for Block objects...
+
+     Method Update ()
+
+            ' Check for collision (passing alpha level of block to apply
+            ' appropriate damage), and remove from GravityItem list if hit...
+
+            If PlayerCollide (alph) Then BCount = BCount - 1; Destroy; Return
+
+            ' If the block has been freed (by being hit), make it fall...
+
+            If Not fixed
+
+               alph = alph - 0.0075; If alph < 0 Then alph = 0
+               ang = ang + angspeed; If ang > 359 Then ang = 0
+               ys = ys + Gravity
+               x = x + xs
+               y = y + ys
+
+               If y > GraphicsHeight () Or alph = 0 Destroy; BCount = BCount - 1
+
+            Else
+
+                ' When blocks are lowered in main loop, they are just set to 'desty',
+                ' their new y-position destination. This moves them towards that...
+
+                ydist# = desty - y
+                ys = ydist / 12.0
+                y = y + ys
+
+            EndIf
+
+     End Method
+
+     ' Block-specific Draw () method...
+
+     Method Draw ()
+
+            SetBlend ALPHABLEND
+            SetRotation ang
+
+            SetColor r, g, b
+            SetAlpha alph
+
+            DrawImage BlockImage, x, y
+
+            SetRotation 0
+
+     End Method
+
+     Function DrawShadows ()
+              SetBlend ALPHABLEND
+              For blk:Block = EachIn GravityItemList
+                   SetRotation blk.ang
+                   SetColor 0, 0, 0
+                   SetAlpha blk.alph * 0.25
+                   DrawImage BlockImage, blk.x + 8, blk.y + 8
+              Next
+     End Function
+
+End Type
+
+' Player object. Only one player possible right now, but this keeps everything
+' together for easy reference...
+
+Type Player
+
+     Field damaged    ' Set to MilliSecs () when hit (used for flashing effect)
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific fields...
+     ' ------------------------------------------------------------------------
+
+       ' The shields field is a float so I can reduce by small amounts, but I use
+       ' Int (PlayerOne.shields) to display/evaluate it...
+
+     Field shields# = 100
+
+     Field x#
+     Field y#
+     Field xs#
+     Field ys#
+
+     Field image      ' Player image...
+
+     Field width
+     Field height
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific functions...
+     ' ------------------------------------------------------------------------
+
+       ' Create () is a function that creates & returns a :Player type object...
+
+     Function Create:Player (x, y, image)
+              PlayerOne:Player = New Player
+              PlayerOne.image = image
+              PlayerOne.x = x
+              PlayerOne.y = y
+              PlayerOne.width = ImageWidth (PlayerOne.image) * 0.2     ' Image is scaled in Draw ()
+              PlayerOne.height = ImageHeight (PlayerOne.image) * 0.2
+              Return PlayerOne
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     ' This is passed the MouseX () and MouseY () positions in the main game
+       ' loop, and hence moves the player toward the mouse cursor...
+
+     Method Move (destx#, desty#, div#)
+            xdist# = destx - x
+            ydist# = desty - y
+            xs = xdist / div
+            ys = ydist / div
+            x = x + xs
+            y = y + ys
+     End Method
+
+     Method Draw (alpha# = 1, r = 255, g = 255, b = 255)
+
+            SetBlend ALPHABLEND
+            SetScale 0.2, 0.2
+
+            If Shadows_On
+               SetColor 0, 0, 0
+               SetAlpha alpha * 0.4
+               DrawImage image, x + 8, y + 8
+            EndIf
+
+            SetAlpha alpha
+
+               ' If player is damaged, rgb will be RED...
+
+            SetColor r, g, b
+            DrawImage image, x, y
+            SetScale 1, 1
+
+     End Method
+
+End Type
+
+Type Shot Extends GravityItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific functions...
+     ' ------------------------------------------------------------------------
+
+     Function Create:Shot (x#, y#, ys#, xs#, soundpan#)
+            If Sounds_On
+               play = CueSound (shoot)
+               SetChannelPan play, soundpan
+               ResumeChannel play
+            EndIf
+            s:Shot = New Shot
+            s.x = x
+            s.y = y
+            s.xs = xs
+            s.ys = ys
+            s.width = 6
+            s.height = 6
+            s.damage = 2
+            Return s
+     End Function
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     ' Over-ride standard GravityItem Update () method...
+
+     Method Update ()
+
+        ' Hit the player (note 'posyonly', 2nd parameter, of PlayerCollide)...
+
+        If PlayerCollide (1, 1) Then Destroy; Return
+
+        ys = ys + Gravity
+        x = x + xs
+        y = y + ys
+
+        ' Remove if below bottom of screen...
+
+        If y > GraphicsHeight ()
+
+           Destroy
+
+        Else
+
+            ' Check current Shot against all Blocks...
+
+            ' (Notice that this only checks Block objects in the list!)
+
+            For blk:Block = EachIn GravityItemList
+
+                ' Get x offset (rectangles are mid-handled)...
+
+                ox = x - width / 2
+                oy = y - height / 2
+
+                ogx = blk.x - blk.width / 2
+                ogy = blk.y - blk.width / 2
+
+                ' Check collision...
+
+                If OverLap (ox, oy, ox + width, oy + height, ogx, ogy, ogx + blk.width, ogy + blk.height)
+
+                   ' If Block is already dead (ie. falling), reflect Shot, otherwise
+                   ' un-fix block and create explosion...
+
+                   ' Note: ys is current Shot object's y speed...
+
+                   If blk.fixed = False
+                      ys = -ys
+                   Else
+                      blk.fixed = False
+                      blk.ys = ys / Rnd (1, 4)
+                      blk.angspeed = Rnd (-4, 4)
+                      ExplosionParticle.Explode ogx, ogy, 4
+                   EndIf
+
+                EndIf
+
+            Next
+
+        EndIf
+
+     End Method
+
+     Method Draw ()
+            SetBlend MASKBLEND
+            SetAlpha 1
+            SetColor 255, 255, 255
+            DrawImage ShotImage, x, y
+     End Method
+
+End Type
+
+' The random debris that falls 'down' the screen...
+
+Type DebrisItem
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific fields...
+     ' ------------------------------------------------------------------------
+
+     Field x# = Rand (0, GraphicsWidth () - 1)
+     Field y# = Rand (0, GraphicsHeight () - 1)
+     Field ys# = Rnd (0.01, 8)
+     Field size = Rand (1, 2)
+
+     ' ------------------------------------------------------------------------
+     ' Type-specific methods...
+     ' ------------------------------------------------------------------------
+
+     Method Update ()
+            If y > GraphicsHeight () y = 0
+            y = y + ys
+     End Method
+
+       Method Draw ()
+            SetColor Rnd (127, 255), Rnd (127, 255), 255
+            SetBlend SOLIDBLEND
+            DrawRect x, y, size, size
+       End Method
+       
+End Type
+
+' -----------------------------------------------------------------------------
+' Functions...
+' -----------------------------------------------------------------------------
+
+' Draw simple text with shadow...
+
+Function DrawShadowText (t$, x, y)
+      SetColor 0, 0, 0
+      DrawText t$, x + 1, y + 1
+      SetColor 255, 255, 255
+      DrawText t$, x, y
+End Function
+
+' Returns "Off" if 'status' is 0, otherwise "On"...
+
+Function OnOff$ (status)
+         If status Then Return "On" Else Return "Off"
+End Function
+
+' Phew! Thanks, Birdie! Rectangular overlap function. Should have been so easy...
+
+Function OverLap (x0, y0, x1, y1, x2, y2, x3, y3)
+       If x0 > x3 Or x1 < x2 Then Return False
+       If y0 > y3 Or y1 < y2 Then Return False
+       Return True
+End Function
+
+' Distance between two points...
+
+Function Dist# (x0#, y0#, x1#, y1#)
+         Return Sqr (((x1 - x0) * (x1 - x0)) + ((y1 - y0) * (y1 - y0)))
+End Function
+
+' -----------------------------------------------------------------------------
+' Main game. This is where it all goes pear-shaped!
+' -----------------------------------------------------------------------------
+
+' Open display...
+
+'Graphics 640, 480, 32
+
+x = GadgetWidth (Desktop ()) / 2 - 320
+y = GadgetHeight (Desktop ()) / 2 - 240
+
+window = CreateWindow ("RockOut GUI", x, y, 640, 480, Null, WINDOW_TITLEBAR)
+If Not window Notify "Couldn't open window!"; End
+
+canvas:TGadget = CreateCanvas (0, 0, ClientWidth (window), ClientHeight (window) - 48, window)
+If Not canvas Notify "Couldn't create canvas!"; End
+
+SetGraphics CanvasGraphics (canvas)
+
+' Buttons...
+
+y = ClientHeight (window) - 24
+width = ClientWidth (window) / 4
+
+tbackground:TGadget    = CreateButton ("Toggle background", 0, y, width, 24, window)
+tdebris:TGadget                = CreateButton ("Toggle debris", width, y, width, 24, window)
+tshadows:TGadget = CreateButton ("Toggle shadows", width * 2, y, width, 24, window)
+tsounds:TGadget = CreateButton ("Toggle sounds", width * 3, y, width + 2, 24, window)
+
+tslabel:TGadget = CreateLabel ("Shields:", 20, y - 22, 60, 20, window, LABEL_CENTER)' | LABEL_FRAME)
+tshields:TGadget = CreateProgBar (100, y - 24, ClientWidth (window) - 100, 20, window)
+
+' Pre-calc half of graphics width...
+
+Global GW2 = GraphicsWidth () / 2
+Global GH2 = GraphicsHeight () / 2
+
+' Set Cls colour (used when background turned off)...
+
+SetClsColor 64, 96, 128
+
+' All images' and rectangles' handles should be set to the centre...
+
+AutoMidHandle True
+SetHandle 0.5, 0.5
+
+' All images unfiltered...
+
+'AutoImageFlags MASKEDIMAGE
+
+' Mask colour for loaded images (will be transparent)...
+
+SetMaskColor 255, 0, 255
+
+' Mouse position -- used in some type methods and functions, hence global...
+
+Global mx, my
+
+' Player object...
+
+Global PlayerOne:Player
+
+' Draw shadows?
+
+Global Shadows_On = True
+
+' Turn off sound?
+
+Global Sounds_On = True
+
+' Load media -- sounds, from included binaries (see start of code)...
+
+Global shoot = LoadSound ("incbin::sounds/shot.ogg")
+Global hit   = LoadSound ("incbin::sounds/hit.ogg")
+Global beep  = LoadSound ("incbin::sounds/beep.ogg")
+Global over  = LoadSound ("incbin::sounds/gameover.ogg")
+
+' Load media -- images, from included binaries...
+
+' Shots...
+
+Global ShotImage = LoadImage ("incbin::gfx/shot.png")
+
+' Blocks...
+
+' Note there is only one image for all blocks -- they are altered by SetColorRGB before
+' drawing (WHITE gives normal image)...
+
+Global BlockImage = LoadImage ("incbin::gfx/block.png")
+
+' Player...
+
+pimage = LoadImage ("incbin::gfx/boing.png",MASKEDIMAGE|MIPMAPPEDIMAGE)
+
+' Background...
+
+' Note that bgscale stores the length of the screen diagonal, and this value is used
+' for the image height, so it doesn't get chopped when it rotates...
+
+bg = LoadImage ("incbin::gfx/land.png")
+bgscale# = Dist (0, 0, GraphicsWidth () - 1, GraphicsHeight () - 1) / ImageHeight (bg)
+
+' Background angle/speed of rotation...
+
+bgang# = 0
+bgangspeed# = 0
+
+' Create an array of 100 debris particles...
+
+Local debris:DebrisItem [100]
+For loop = 0 Until 100
+    debris [loop] = New DebrisItem
+Next
+
+' This should probably read 'rows' -- the number of rows of blocks at startup...
+
+layers = 5
+
+' Toggle variables for drawing background, debris and wireframe mode...
+
+bgtoggle = 1
+debristoggle = 1
+wftoggle = 0
+
+' Delay before adding another row of blocks (this is decreased as the game progresses)...
+
+rowdelay = 10000 ' 10 seconds (10000 milliseconds)...
+
+' Background colour and first target colour...
+
+backr# = 64
+backg# = 96
+backb# = 180
+
+backtr# = 128
+backtg# = 32
+backtb# = 48
+
+' Delay between colour increments...
+
+backstep# = 5000
+
+' Colour increments...
+
+backstepr# = (backtr - backr) / backstep
+backstepg# = (backtg - backg) / backstep
+backstepb# = (backtb - backb) / backstep
+
+' Direction of increment to target colour...
+
+backsgn = Sgn (backtr - backr)
+
+mx = GraphicsWidth () / 2
+my = GraphicsHeight () / 2
+MoveMouse mx, my
+
+timer = CreateTimer (60)
+
+' This is the point where the game is re-started from, whenever a level is completed or game ended...
+
+#ResetLevel ' $name signifies a label now...
+
+' Increase level number (level is 0 on startup, so becomes 1 for first level)...
+
+level = level + 1
+
+' Reset the 'new row' delay timer to the current time...
+
+rowtimer = MilliSecs ()
+
+' Set fire rate limiter to current time...
+
+firetimer = MilliSecs ()
+
+' Create rows of blocks...
+
+For y = 0 To layers - 1
+    For x = 0 Until GraphicsWidth () Step BLOCKWIDTH
+        b:Block = Block.Create (x + BLOCKWIDTH / 2, (y * BLOCKHEIGHT) + BLOCKHEIGHT / 2)
+        b.r = Rnd (127, 255)
+        b.g = Rnd (127, 255)
+        b.b = Rnd (127, 255)
+    Next
+Next
+
+' Minimum number of blocks left before we *stop* dropping them down (equivalent of 2 rows)...
+
+lowblocks = 2 * (GraphicsWidth () / BLOCKWIDTH)
+
+' When a level is completed, we delete the player object for simplicity of resetting
+' all its values. This creates it (same for game startup)...
+
+If PlayerOne = Null Then PlayerOne = Player.Create (mx, my, pimage)
+
+' Game text and precalculated x offsets...
+
+go$ = "G A M E   O V E R   --   H I T   S P A C E   O R   R M B"
+wd$ = "W E L L   D O N E   --   H I T   S P A C E   O R   R M B"
+
+gox = (GraphicsWidth () / 2) - (TextWidth (go$) / 2)
+wdx = (GraphicsWidth () / 2) - (TextWidth (wd$) / 2)
+
+ActivateGadget canvas
+
+firing = 0
+HideMouse
+
+firstgo = 1
+
+Repeat
+
+       ' Mac compatibility fix...
+       
+'      SetGraphics CanvasGraphics (canvas)
+
+               WaitEvent
+               
+      ' Clear the screen...
+
+      Cls
+
+      ' Store mouse position in these global variables...
+
+               Select EventID ()
+               
+                       Case EVENT_MOUSEENTER
+                               If EventSource () = canvas Then HideMouse
+
+                       Case EVENT_MOUSELEAVE
+                               If EventSource () = canvas Then ShowMouse
+                       
+                       Case EVENT_TIMERTICK
+                               'Print "Tick!"
+                               RedrawGadget canvas
+                               
+                       Case EVENT_GADGETPAINT
+                               draw = 1
+                               
+                       Case EVENT_MOUSEDOWN
+                               If EventData () = 1
+                                       firing = 1
+                               EndIf
+                               
+                       Case EVENT_MOUSEUP
+                               firing = 0
+                               If EventData () = 2
+                                       spacehit = 1
+                               EndIf
+                                       
+                       Case EVENT_MOUSEMOVE
+                             mx = EventX ()
+                         my = EventY ()
+
+                       Case EVENT_KEYUP
+       
+                     ' -----------------------------------------------------------------------
+                     ' Toggles...
+                     ' -----------------------------------------------------------------------
+               
+                               Select EventData ()
+                                       Case KEY_ESCAPE
+                                               End
+                                       Case KEY_SPACE
+                                               spacehit = 1
+                               End Select
+                       
+               Case EVENT_GADGETACTION
+
+                       Select EventSource ()
+                               Case tbackground:TGadget        
+                                       bgtoggle = 1 - bgtoggle
+                               Case tdebris:TGadget
+                                       debristoggle = 1 - debristoggle
+                               Case tshadows:TGadget
+                                       Shadows_On = 1 - Shadows_On
+                               Case tsounds:TGadget
+                                       Sounds_On = 1 - Sounds_On
+                       End Select
+                       
+                       ActivateGadget canvas ' Get event focus back!
+                       
+               End Select
+
+      ' -----------------------------------------------------------------------
+      ' Background...
+      ' -----------------------------------------------------------------------
+
+       If draw ' EVENT_GADGETPAINT received...
+       
+      ' Update background rotation...
+
+      bgang = bgang + bgangspeed; If bgang > 359 - bgangspeed Then bgang = 0
+      bgangspeed = bgangspeed + 0.0001
+
+      ' The bgtoggle variable controls whether the background should be drawn or not...
+
+      If bgtoggle
+
+              ' Change colour by pre-calculated increment...
+
+              backr = backr + backstepr
+              backg = backg + backstepg
+              backb = backb + backstepb
+
+              ' Reached target colour? Set a new target/increments/increment-direction...
+
+              If backr => backtr * backsgn
+                  backtr = Rnd (255)
+                  backtg = Rnd (255)
+                  backtb = Rnd (255)
+                  backstepr# = (backtr - backr) / backstep
+                  backstepg# = (backtg - backg) / backstep
+                  backstepb# = (backtb - backb) / backstep
+                  backsgn = Sgn (backtr - backr)
+              EndIf
+
+      EndIf
+
+      ' When the player is hit, the 'damaged' field is set to the current time.
+      ' This code checks if a second has passed since 'damaged'. If so, it draws
+       ' the player normally; if not, the player is drawn in red, with varying
+       ' transparency...
+
+      If MilliSecs () > PlayerOne.damaged + 1000 ' Damage timeout has passed...
+
+         ' Draw normally...
+
+         PlayerOne.damaged = 0 ' Resetting damage time...
+         alpha# = 1
+         rcol = 255; gcol = 255; bcol = 255
+
+      Else
+
+          ' Flash player for 1 second if hit...
+
+          alpha# = Sin (MilliSecs ())
+          rcol = 255; gcol = 0; bcol = 0
+
+      EndIf
+
+      ' -----------------------------------------------------------------------
+      ' If player is alive, do stuff...
+      ' -----------------------------------------------------------------------
+
+      If Int (PlayerOne.shields) > 0 ' Shields is a float, so gotta round it...
+
+         ' Player is alive...
+
+         ' If more than 'lowblocks' left on screen, add a row and lower all
+         ' blocks. Reset drop-down timer and reduce delay for next drop-down...
+
+         If Block.BCount > lowblocks And MilliSecs () > rowtimer + rowdelay
+
+            ' Add a row of blocks, above top of screen...
+
+            For x = 0 Until GraphicsWidth () Step BLOCKWIDTH
+                b:Block = Block.Create (x + BLOCKWIDTH / 2, -BLOCKHEIGHT / 2)
+                b.r = Rnd (127, 255)
+                b.g = Rnd (127, 255)
+                b.b = Rnd (127, 255)
+            Next
+
+            ' Set all blocks' target y position down by block height. When blocks
+            ' are updated, they get moved towards this new position...
+
+            For b:Block = EachIn GravityItem.GravityItemList
+                b.desty = b.desty + BLOCKHEIGHT
+            Next
+
+            ' Reset timeout until a new row is added...
+
+            rowtimer = MilliSecs ()
+
+            ' Reduce row-down timeout a bit...
+
+            If rowdelay => 1100 Then rowdelay = rowdelay - 100 ' Minimum 1 sec interval!
+
+         EndIf
+
+         ' --------------------------------------------------------------------
+         ' Fire shot (maximum fire rate 75 milliseconds)...
+         ' --------------------------------------------------------------------
+
+         If firing 'MouseDown (1)
+            If MilliSecs () > firetimer + 75
+               pan# = PlayerOne.x / GW2 - 1.0
+               s:Shot = Shot.Create (PlayerOne.x, PlayerOne.y - (PlayerOne.height / 2 + 5), -5, PlayerOne.xs / 5.0, pan)
+               firetimer = MilliSecs ()
+            EndIf
+         EndIf
+
+         ' --------------------------------------------------------------------
+         ' No blocks left?
+         ' --------------------------------------------------------------------
+
+         ' Set 'welldone' flag (text shows "Well done" below if True);
+
+         ' If there are no blocks and Space is hit, delete all GravityItems,
+         ' reduce block count, increase number of block rows and reset level...
+
+         If Block.BCount = 0
+
+            ' Will display 'well done' message further down...
+
+            welldone = True
+
+            ' Remove all items (and reduce block count)...
+
+            For g:GravityItem = EachIn GravityItem.GravityItemList
+                If Block (g) Then Block.BCount = Block.BCount - 1
+                g.Destroy
+            Next
+
+            ' If space is hit, add some layers and reset everything (new level)...
+
+            If spacehit'KeyHit (KEY_SPACE) Or MouseHit (2)
+               If Sounds_On Then PlaySound beep
+               layers = layers + 3
+               Goto ResetLevel
+            EndIf
+
+         EndIf
+
+      Else
+
+          If gameoverplayed = 0
+             If Sounds_On Then PlaySound over
+             gameoverplayed = 1
+          EndIf
+
+          ' Player is dead...
+
+          PlayerOne.shields = 0 ' Force to zero as can be reduced after game is over...
+
+          gameover = True
+
+          ' Remove all blocks...
+
+          For b:Block = EachIn GravityItem.GravityItemList
+              b.Destroy
+              Block.BCount = Block.BCount - 1
+          Next
+
+          ' -------------------------------------------------------------------
+          ' If player is dead and Space hit...
+          ' -------------------------------------------------------------------
+
+          ' Space hit... remove everything else and reset to initial settings...
+
+          If spacehit'KeyHit (KEY_SPACE) Or MouseHit (2)
+
+             If Sounds_On Then PlaySound beep
+
+             For g:GravityItem = EachIn GravityItem.GravityItemList
+                 g.Destroy
+             Next
+
+             ' Delete player (recreated when level is reset)...
+
+             PlayerOne = Null
+             layers = 5
+             bgang = 0
+             bgangspeed = 0
+             level = 0
+             rowdelay = 10000
+
+             gameoverplayed = 0
+
+             Goto ResetLevel
+
+          EndIf
+
+      EndIf
+
+      If debristoggle
+         For loop = 0 Until 100
+             debris [loop].Update
+         Next
+      EndIf
+
+
+       
+               If bgtoggle
+                             ' Set colour of background image (applied to the greyscale default)...
+               
+                             SetColor backr, backg, backb
+               
+                             ' Set the background's pre-calculated scale...
+               
+                             SetScale bgscale, bgscale
+                             SetRotation bgang
+                             SetAlpha 1
+               
+                             DrawImage bg, GW2, GH2
+               
+                             ' Reset this stuff so next drawn items don't have to...
+               
+                             SetRotation 0
+                             SetScale 1, 1
+               
+                             ' Put back to wireframe/non-wireframe mode, depending on value of 'wftoggle'...
+               
+               '              WireFrame wftoggle
+               EndIf
+       
+             ' -----------------------------------------------------------------------
+             ' Debris...
+             ' -----------------------------------------------------------------------
+       
+             ' Draw debris particles if 'debristoggle' is True...
+       
+             If debristoggle
+                For loop = 0 Until 100
+       '             debris [loop].Update
+                               debris [loop].Draw
+                Next
+             EndIf
+       
+             ' -----------------------------------------------------------------------
+             ' Cursor...
+             ' -----------------------------------------------------------------------
+       
+             SetColor 255, 255, 255
+             DrawLine mx - 8, my, mx + 8, my
+             DrawLine mx, my - 8, mx, my + 8
+       
+             ' -----------------------------------------------------------------------
+             ' Move and draw player...
+             ' -----------------------------------------------------------------------
+       
+             ' Move the player object based on mouse position (the '20' controls the
+             ' speed at which the player moves toward the mouse -- play with it;
+             ' lower is faster)...
+       
+             PlayerOne.Move (mx, my, 12)
+       
+             ' Draw the player using the above values...
+       
+             PlayerOne.Draw (alpha, rcol, gcol, bcol)
+       
+             ' -----------------------------------------------------------------------
+             ' Update everything...
+             ' -----------------------------------------------------------------------
+       
+             GravityItem.UpdateAll
+       
+             ' -----------------------------------------------------------------------
+             ' Draw text on top of everything...
+             ' -----------------------------------------------------------------------
+       
+             SetAlpha 1
+       
+             DrawShadowText "Level: " + level, 20, GraphicsHeight () - 40
+       ' + " | Shields: " + Int (PlayerOne.shields) + "%"
+                       UpdateProgBar tshields, Int (PlayerOne.Shields) / 100.0
+             ' Draw extra text if appropriate...
+       
+             If gameover
+                DrawShadowText go$, gox, GraphicsHeight () / 2
+                gameover = False
+             Else
+                If welldone
+                   DrawShadowText wd$, wdx, GraphicsHeight () / 2
+                   welldone = False
+                EndIf
+             EndIf
+       
+             ' Display everything that's been drawn to the hidden back buffer...
+       
+             Flip
+       
+               spacehit = 0
+               draw = 0
+               
+       EndIf
+       
+Until EventID () = EVENT_WINDOWCLOSE
+
+End
diff --git a/samples/hitoro/shadowimage.bmx b/samples/hitoro/shadowimage.bmx
new file mode 100644 (file)
index 0000000..ff180e8
--- /dev/null
@@ -0,0 +1,113 @@
+
+' Rockets rotating and casting alpha-blended, pseudo light-sourced shadows on each other...
+
+MAXNUM = 500
+
+Graphics 640, 480, 32
+
+AutoImageFlags MASKEDIMAGE
+
+SetMaskColor 255, 0, 255
+
+rocket = LoadImage ("gfx/boing.png",MASKEDIMAGE|MIPMAPPEDIMAGE)
+grass = LoadImage ("gfx/grass.png")
+
+MidHandleImage rocket
+
+scale# = 0.5
+trans# = 0.5
+
+NUM = MAXNUM
+
+Local x [NUM], y [NUM]
+Local xs [NUM], ys [NUM]
+Local ang# [NUM], angstep# [NUM]
+
+For loop = 0 To NUM - 1
+       x [loop] = Rand (0, GraphicsWidth () - 1)
+       y [loop] = Rand (0, GraphicsHeight () - 1)
+       xs [loop] = Rand (1, 5)
+       ys [loop] = Rand (1, 5)
+       ang [loop] = Rand (0, 359)
+       angstep [loop] = Rnd (1, 5)
+Next
+
+NUM = 1
+
+Repeat
+
+       Cls
+
+        If KeyHit (KEY_RIGHT) Or MouseHit (2)
+           If NUM < MAXNUM Then NUM = NUM + 1
+        Else
+            If KeyHit (KEY_LEFT) Or MouseHit (1)
+               If NUM > 1 Then NUM = NUM - 1
+            EndIf
+        EndIf
+
+       mx = MouseX ()
+       my = MouseY ()
+
+        SetScale scale, scale
+       SetRotation 0
+       TileImage grass
+
+       For loop = 0 To NUM - 1
+
+               x [loop] = x [loop] + xs [loop]
+               y [loop] = y [loop] + ys [loop]
+
+               If x [loop] < 0 Or x [loop] > GraphicsWidth () - 1
+                  xs [loop] = -xs [loop]; x [loop] = x [loop] + xs [loop]
+                  angstep [loop] = -angstep [loop]
+               EndIf
+
+               If y [loop] < 0 Or y [loop] > GraphicsHeight () - 1
+                  ys [loop] = -ys [loop]; y [loop] = y [loop] + ys [loop]
+                  angstep [loop] = -angstep [loop]
+               EndIf
+
+               ang [loop] = ang [loop] + angstep [loop]
+                If ang [loop] > 360 - angstep [loop] Then ang [loop] = 0
+               SetRotation ang [loop]
+
+               offx = -(mx - x [loop]) / 8
+               offy = -(my - y [loop]) / 8
+               DrawShadowedImage rocket, x [loop], y [loop], offx, offy, trans
+
+       Next
+
+        SetScale 1, 1
+        DrawShadowText "Use left/right cursors or mouse buttons to add/remove rockets", 20, 20
+        DrawShadowText "Move mouse to change light direction", 20, 40
+        DrawShadowText "Number of rockets: " + NUM, 20, 80
+
+       Flip
+
+Until KeyHit (KEY_ESCAPE)
+
+End
+
+Function DrawShadowText (t$, x, y)
+      SetRotation 0
+      SetColor 0, 0, 0
+      DrawText t$, x + 1, y + 1
+      SetColor 255, 255, 255
+      DrawText t$, x, y
+End Function
+
+Function DrawShadowedImage (image, x#, y#, xoff#, yoff#, level#)
+
+       SetBlend ALPHABLEND
+       SetColor 0, 0, 0
+       SetAlpha level
+       DrawImage image, x + xoff, y + yoff
+
+       SetBlend MASKBLEND
+       SetColor 255, 255, 255
+       SetAlpha 1
+       DrawImage image, x, y
+
+End Function
+
diff --git a/samples/hitoro/singlelist.bmx b/samples/hitoro/singlelist.bmx
new file mode 100644 (file)
index 0000000..ac8897f
--- /dev/null
@@ -0,0 +1,78 @@
+
+' Adding objects to an object-specific list...
+
+Type Particle
+
+     Global ParticleList:TList ' The list for all objects of this type...
+     Global Gravity# = 0.1
+
+     Field x#
+     Field y#
+     Field xs#
+     Field ys#
+
+     ' The New method is called whenever one of these objects is created. If
+     ' the list hasn't yet been created, it's created here. The object is then
+     ' added to the list...
+
+     Method New ()
+            If ParticleList = Null
+               ParticleList = New TList
+            EndIf
+            ParticleList.AddLast Self
+     End Method
+
+     Function Create:Particle (x, y)
+              p:Particle = New Particle
+              p.x = x
+              p.y = y
+              p.xs = Rnd (-4, 4)
+              p.ys = 0
+              Return p
+     End Function
+
+     Function UpdateAll ()
+
+            ' Better check the list exists before trying to use it...
+
+            If ParticleList = Null Return
+
+            ' Iterate through list...
+
+            For p:Particle = EachIn ParticleList
+                    p.ys = p.ys + Gravity
+                    p.x = p.x + p.xs
+                    p.y = p.y + p.ys
+                    DrawRect p.x, p.y, 8, 8
+                    If p.y > GraphicsHeight () p = Null
+            Next
+
+     End Function
+
+End Type
+
+' D E M O . . .
+
+Graphics 640, 480
+
+Repeat
+
+      Cls
+
+      ' Create a Particle every now and then...
+
+      If Rand (100) > 50
+            p:Particle = Particle.Create (MouseX (), MouseY ())
+      EndIf
+
+      ' Update all Particle objects...
+
+      Particle.UpdateAll ()
+
+      Flip
+
+Until KeyHit (KEY_ESCAPE)
+
+End
+
+
diff --git a/samples/hitoro/sounds/beep.ogg b/samples/hitoro/sounds/beep.ogg
new file mode 100644 (file)
index 0000000..d96ac86
Binary files /dev/null and b/samples/hitoro/sounds/beep.ogg differ
diff --git a/samples/hitoro/sounds/fall.ogg b/samples/hitoro/sounds/fall.ogg
new file mode 100644 (file)
index 0000000..12cf317
Binary files /dev/null and b/samples/hitoro/sounds/fall.ogg differ
diff --git a/samples/hitoro/sounds/gameover.ogg b/samples/hitoro/sounds/gameover.ogg
new file mode 100644 (file)
index 0000000..b6a563e
Binary files /dev/null and b/samples/hitoro/sounds/gameover.ogg differ
diff --git a/samples/hitoro/sounds/hit.ogg b/samples/hitoro/sounds/hit.ogg
new file mode 100644 (file)
index 0000000..6ef2153
Binary files /dev/null and b/samples/hitoro/sounds/hit.ogg differ
diff --git a/samples/hitoro/sounds/shot.ogg b/samples/hitoro/sounds/shot.ogg
new file mode 100644 (file)
index 0000000..1a279d4
Binary files /dev/null and b/samples/hitoro/sounds/shot.ogg differ
diff --git a/samples/hitoro/throwrockets.bmx b/samples/hitoro/throwrockets.bmx
new file mode 100644 (file)
index 0000000..fb2def5
--- /dev/null
@@ -0,0 +1,133 @@
+Const PARTICLE_GRAVITY# = 0.05
+
+Global ParticleCounter
+Global ParticleList:TList = New TList
+
+' Core abstract type...
+
+Type Atom
+
+       Field image
+       Field x#
+       Field y#
+       Field xs#
+       Field ys#
+       Field ALPHA# = 1
+       Field size#
+       
+       Method Update () Abstract
+
+End Type
+
+' Generic particle type that holds creation/update functions, based
+' on abstract type Atom...
+
+Type Particle Extends Atom
+
+       Function Create:Particle (image, x#, y#, xs#, ys#)
+               p:Rocket = New Rocket
+               p.image = image
+               p.x = x
+               p.y = y
+               p.xs = xs
+               p.ys = ys
+               ParticleList.AddLast p
+               ParticleCounter = ParticleCounter + 1
+               Return p
+       End Function
+
+       Function UpdateAll ()
+               Local p:Atom
+               For p=EachIn ParticleList
+               p.Update ()
+               Next
+       End Function
+
+End Type
+
+' Types based on Particle, all to be created using EXTENDED_TYPE.Create ()...
+
+Type Rocket Extends Particle
+
+       Method Update ()
+               If ALPHA > 0.01
+                       ALPHA = ALPHA - 0.005
+                       SetAlpha ALPHA
+                       ys = ys + PARTICLE_GRAVITY
+                       x = x + xs
+                       y = y + ys
+                       ang# = ATan2 (xs, -ys)
+                       SetRotation ang
+                       DrawImage image, x, y
+                       If x < 0 Or x > GraphicsWidth () Or y > GraphicsHeight ()
+                               ParticleList.Remove Self
+                               ParticleCounter = ParticleCounter - 1
+                       EndIf
+               Else
+                       ParticleList.Remove Self
+                       ParticleCounter = ParticleCounter - 1
+               EndIf
+       End Method
+
+End Type
+
+' --------------------------------------------------------------------------------
+
+Incbin "gfx/boing.png"
+
+Const GAME_WIDTH = 640
+Const GAME_HEIGHT = 480
+
+Const GRAPHICS_WIDTH = 1024
+Const GRAPHICS_HEIGHT = 768
+
+Graphics GRAPHICS_WIDTH,GRAPHICS_HEIGHT,32
+
+SetVirtualResolution GAME_WIDTH,GAME_HEIGHT
+
+SetClsColor 64, 96, 180
+
+SetMaskColor 255, 0, 255
+AutoImageFlags MASKEDIMAGE ' Disable for filtered rockets...
+
+image = LoadImage ("incbin::gfx/boing.png")
+MidHandleImage image
+
+lastmousex = VirtualMouseX ()
+lastmousey = VirtualMouseY ()
+
+Repeat
+
+       x = VirtualMouseX ()
+       y = VirtualMouseY ()
+
+       mxs# = VirtualMouseXSpeed ()'# = x - lastmousex
+       mys# = VirtualMouseYSpeed ()'# = y - lastmousey
+
+       Cls
+
+       xs# = mxs / 10 + Rnd (-0.1, 0.1)
+       ys# = mys / 10 + Rnd (-0.1, 0.1)
+
+       If MouseDown (1) And (mxs Or mys)
+               Rocket.Create (image, x, y, xs, ys)
+       EndIf
+
+        SetScale 0.2, 0.2
+       SetBlend ALPHABLEND
+       Particle.UpdateAll ()
+
+        SetScale 1, 1
+        SetRotation 0
+
+       DrawText "Click and drag mouse to throw rockets!", 10, 10
+       DrawText "Rockets: " + ParticleCounter, 10, 25
+
+       Flip
+
+       lastmousex = x
+       lastmousey = y
+
+Until KeyHit (KEY_ESCAPE)
+
+End
diff --git a/samples/hitoro/tilerocket.bmx b/samples/hitoro/tilerocket.bmx
new file mode 100644 (file)
index 0000000..2436b5f
--- /dev/null
@@ -0,0 +1,205 @@
+
+' Ugly -- just playing around!
+
+Global FlameList:TList = New TList
+Global ShotList:TList = New TList
+
+Type Flame
+       Field x#, y#
+       Field image
+       Field ALPHA#
+       Field scale#
+       Field ys#
+End Type
+
+Type Shot
+       Field x#, y#
+       Field xs#, ys#
+       Field ALPHA#
+End Type
+
+Graphics 640, 480
+
+AutoImageFlags MASKEDIMAGE
+
+SetClsColor 16, 32, 64
+
+SetMaskColor 255, 0, 255
+
+player = LoadImage ("gfx/boing.png")
+MidHandleImage player
+
+flm = LoadImage ("gfx/flame.png")
+MidHandleImage flm
+
+sky = LoadImage ("gfx/sky.png")
+grass = LoadImage ("gfx/grass.png")
+rock = LoadImage ("gfx/rock.png")
+water = LoadImage ("gfx/water.png")
+
+MidHandleImage grass
+MidHandleImage rock
+MidHandleImage water
+
+x# = GraphicsWidth () / 2
+y# = GraphicsHeight () / 2
+
+speed# = 0
+
+playerscale# = 0.25
+
+' Map tiles...
+
+MAPXS = 50
+MAPYS = 30
+
+Local map [MAPXS, MAPYS]
+
+For mapx = 0 To MAPXS - 1
+
+       For mapy = 0 To MAPYS - 1
+
+               Select Rand (0, 3)
+                       Case 0
+                               image = 0
+                       Case 1
+                               image = grass
+                       Case 2
+                               image = rock
+                       Case 3
+                               image = water
+               End Select
+
+               map [mapx, mapy] = image
+
+       Next
+
+Next
+
+GW2 = GraphicsWidth () / 2
+GH2 = GraphicsHeight () / 2
+
+ShotSpeed# = 4
+
+Repeat
+
+       mx = MouseX ()
+       my = MouseY ()
+       
+       Cls
+       
+       SetBlend SOLIDBLEND
+       TileImage sky
+
+       ang# = ATan2 (my - GH2, mx - GW2)
+
+       x = x + Cos (ang) * speed
+       y = y + Sin (ang) * speed
+       
+       If KeyHit (KEY_SPACE)
+               s:Shot = New Shot
+               s.x = (x + Cos (ang) * (ImageWidth (player) * playerscale) / 2)
+               s.y = (y + Sin (ang) * (ImageHeight (player) * playerscale)/ 2)
+               s.xs = Cos (ang) * (speed + ShotSpeed)
+               s.ys = Sin (ang) * (speed + ShotSpeed)
+               s.ALPHA = 1
+               ShotList.AddLast s
+       EndIf
+       
+       If MouseDown (1)
+               If speed < 10 Then speed = speed + 0.1
+               If Rand (1, 100) > (100 - speed * 2.5)
+                       f:Flame = New Flame
+                       f.x = Rand (1, 8) + (x - Cos (ang) * (ImageWidth (player) * playerscale) / 2)
+                       f.y = Rand (1, 8) + (y - Sin (ang) * (ImageHeight (player) * playerscale)/ 2)
+                       f.ys = 0
+                       f.image = flm
+                       f.ALPHA = 1
+                       f.scale = 0.5
+                       FlameList.AddLast f
+               EndIf
+       EndIf
+       
+       SetBlend MASKBLEND
+       
+       SetRotation 0
+       SetScale 1, 1
+       
+       For mapx = 0 To MAPXS - 1
+               For mapy = 0 To MAPYS - 1
+                       If map [mapx, mapy]
+                               DrawImage map [mapx, mapy], mapx * 128 - x, mapy * 128 - y
+                       EndIf
+               Next
+       Next
+       
+       SetColor 255, 255, 255
+       SetBlend ALPHABLEND
+       
+       Local p:Flame
+       For p=EachIn FlameList
+               p.ys = p.ys - 0.05
+               p.y = p.y + p.ys
+               SetAlpha p.ALPHA
+               SetScale p.scale, p.scale
+               SetRotation 0
+               DrawImage p.image, GW2 + p.x - x, GH2 + p.y - y
+               p.ALPHA = p.ALPHA - 0.01
+               p.scale = p.scale + Rnd (0.0025, 0.05)
+               If p.ALPHA < 0
+                       FlameList.remove p
+               EndIf
+       Next
+       
+       SetColor 255, 255, 0
+       
+       For s=EachIn ShotList
+               s.x = s.x + s.xs
+               s.y = s.y + s.ys
+               SetAlpha s.ALPHA
+               SetRotation 0
+               SetScale 1, 1
+               DrawRect GW2 + s.x - x, GH2 + s.y - y, 8, 8
+               s.ALPHA = s.ALPHA - 0.01
+               If s.ALPHA < 0
+                       ShotList.remove s
+               EndIf
+       Next
+       
+       SetBlend ALPHABLEND
+       SetAlpha 0.25
+       SetScale 0.25, 0.25
+       SetColor 0, 0, 0
+       sp2 = speed * 2
+       DrawPointedImage player, GW2 + sp2, GH2 + sp2, mx + sp2, my + sp2
+
+       SetColor 255, 255, 255
+       SetBlend MASKBLEND
+       SetScale 0.25, 0.25
+       SetAlpha 1
+       DrawPointedImage player, GW2, GH2, mx, my
+
+       speed = speed - 0.075; If speed < 0 Then speed = 0
+
+       SetRotation 0
+       SetScale 1, 1
+       SetColor 0, 0, 0
+       DrawText "Hold left mouse button to move and hit space to fire...", 21, 21
+       SetColor 255, 255, 255
+       DrawText "Hold left mouse button to move and hit space to fire...", 20, 20
+       
+       Flip
+
+Until KeyHit (KEY_ESCAPE)
+
+End
+
+' Assumes image is oriented 'upwards' by default -- fiddle with
+' the "+ 90" part on the first line if not!
+
+Function DrawPointedImage (image, x#, y#, targetx#, targety# )
+       ang# = ATan2 (targety - y, targetx - x) + 90
+       SetRotation ang
+       DrawImage image, x, y
+End Function
+
diff --git a/samples/hitoro/viewport.bmx b/samples/hitoro/viewport.bmx
new file mode 100644 (file)
index 0000000..c821a09
--- /dev/null
@@ -0,0 +1,65 @@
+
+Incbin "gfx/bg.png"
+Incbin "gfx/boing.png"
+
+Graphics 640, 480 , 32
+
+AutoImageFlags MASKEDIMAGE|FILTEREDIMAGE
+
+SetMaskColor 255, 0, 255
+
+bg = LoadImage ("incbin::gfx/bg.png")
+bgw# = GraphicsWidth () / Float (ImageWidth (bg))
+bgh# = GraphicsHeight () / Float (ImageHeight (bg))
+
+image = LoadImage ("incbin::gfx/boing.png") ' My example is 256 x 256
+MidHandleImage image
+
+rotstep# = 1
+
+Repeat
+
+       mx = MouseX (); my = MouseY ()
+       
+       SetViewport 0, 0, GraphicsWidth (), GraphicsHeight ()
+       Cls
+       
+       SetViewport mx - 200, my - 150, 400, 300
+       Cls
+       
+       ' ---------------------------------------------------------------
+       ' Draw background...
+       ' ---------------------------------------------------------------
+       
+       SetAlpha 1
+       SetBlend MASKBLEND
+       
+       SetRotation 0; SetScale bgw, bgh
+       DrawImage bg, 0, 0
+       
+       ' ---------------------------------------------------------------
+       ' Draw image...
+       ' ---------------------------------------------------------------
+       
+       rot# = rot + rotstep; If rot > 360 - rotstep Then rot = 0
+       SetRotation rot
+       
+       scale# = 0.1 + Sin (rot / 2); If scale < 0 Then scale = -scale
+       SetScale scale, scale
+       
+       SetBlend ALPHABLEND
+       SetAlpha scale
+       
+       DrawImage image, mx, my
+       
+       Flip
+       
+Until KeyHit (KEY_ESCAPE)
+
+End
+
+
+
+
+
+
diff --git a/samples/mak/bullet1.png b/samples/mak/bullet1.png
new file mode 100644 (file)
index 0000000..46e2e2a
Binary files /dev/null and b/samples/mak/bullet1.png differ
diff --git a/samples/mak/gnetchat.bmx b/samples/mak/gnetchat.bmx
new file mode 100644 (file)
index 0000000..93c309a
--- /dev/null
@@ -0,0 +1,126 @@
+
+Strict
+
+Import BRL.GNet
+
+AppTitle="GNet Test2"
+
+Local host:TGNetHost=CreateGNetHost()
+
+Local me:TGNetObject
+Local chat$,info$
+
+Graphics 800,600,0,15
+
+Repeat
+
+       Local c=GetChar()
+       
+       Select c
+       Case 8
+               If chat chat=chat[..chat.length-1]
+       Case 27
+               If Confirm( "Quit?" )
+                       CloseGNetHost host
+                       End
+               EndIf
+       Case 13
+               If chat.find("/")=0
+                       chat=chat[1..]
+                       Local cmd$=chat
+                       Local arg$
+                       Local i=chat.find(" ")
+                       If i<>-1
+                               cmd=chat[..i]
+                               arg=chat[i+1..]
+                       EndIf
+                       Select cmd
+                       Case "create"
+                               If me
+                                       info="Already created"
+                               Else
+                                       me=CreateGNetObject( host )
+                                       SetGNetString me,0,arg
+                                       SetGNetString me,1,"Ready"
+                               EndIf
+                       Case "close"
+                               If me
+                                       CloseGNetObject me
+                                       me=Null
+                               Else
+                                       info="Not created"
+                               EndIf
+                       Case "quit","exit"
+                               CloseGNetHost host
+                               End
+                       Case "nick"
+                               If arg
+                                       If me SetGNetString me,0,arg
+                                       info="Nick changed to "+arg
+                               Else
+                                       info="Expecting arg"
+                               EndIf
+                       Case "listen"
+                               Local port=12345
+                               If arg port=Int(arg)
+                               If GNetListen( host,port )
+                                       info="Listening on port "+port
+                               Else
+                                       info="Listen failed"
+                               EndIf
+                       Case "connect"
+                               If arg
+                                       Local addr$=arg
+                                       Local port=12345
+                                       Local i=arg.find(":")
+                                       If i<>-1
+                                               addr=arg[..i]
+                                               port=Int(arg[i+1..])
+                                       EndIf
+                                       If GNetConnect( host,addr,port )
+                                               info="Connected to "+addr+":"+port
+                                       Else
+                                               info="Failed to connect to "+addr+":"+port
+                                       EndIf
+                               Else
+                                       info="Expecting arg"
+                               EndIf
+                       Default
+                               info="Unrecognized command '"+cmd+"'"
+                       End Select
+               Else
+                       If me SetGNetString me,1,chat
+               EndIf
+               chat=""
+       Default
+               If c>31 And c<127 chat:+Chr(c)
+       End Select
+       
+       GNetSync host
+       
+       Cls
+
+       Local y,h=GraphicsHeight()
+       
+       For Local obj:TGNetObject=EachIn GNetObjects( host,GNET_ALL )
+               If obj.state()=GNET_CLOSED Continue
+               If obj=me
+                       SetColor 255,255,255
+               Else
+                       SetColor 0,128,255
+               EndIf
+               DrawText GetGNetString( obj,0 )+":"+GetGNetString( obj,1 ),0,y
+               y:+16
+       Next
+       
+       SetColor 255,255,0
+       DrawText info,0,h-32
+       
+       SetColor 0,255,0
+       DrawText ">"+chat,0,h-16
+       DrawRect TextWidth(">"+chat),h-16,8,16
+       DrawText "/create nick    /listen    /connect host    /quit    /nick newnick",0,h-48
+       
+       Flip
+       
+Forever
diff --git a/samples/mak/gnetdemo.bmx b/samples/mak/gnetdemo.bmx
new file mode 100644 (file)
index 0000000..138221e
--- /dev/null
@@ -0,0 +1,287 @@
+
+Strict
+
+?Win32
+Framework BRL.D3D7Max2D
+?MacOS
+Framework BRL.GLMax2D
+?
+Import BRL.GNet
+Import BRL.BASIC
+Import BRL.PNGLoader
+
+Const GAMEPORT=12345
+
+Const SLOT_TYPE=0
+Const SLOT_NAME=1
+Const SLOT_CHAT=2              
+Const SlOT_SCORE=3
+Const SLOT_X=4
+Const SLOT_Y=5
+Const SLOT_VX=6
+Const SLOT_VY=7
+Const SLOT_ROT=8
+Const SLOT_TIMEOUT=9
+Const SLOT_HIT=10
+
+Local GWIDTH=640
+Local GHEIGHT=480
+Local GDEPTH=0
+Local GHERTZ=30
+
+Graphics GWIDTH,GHEIGHT,GDEPTH,GHERTZ
+
+AutoMidHandle True
+Local playerImage:TImage=LoadImage( "ship.png" )
+Local bulletImage:TImage=LoadImage( "bullet1.png" )
+Local warpImage:TImage=LoadImage( "sparkle.png" )
+
+Local host:TGNetHost=CreateGNetHost()
+
+SeedRnd MilliSecs()
+
+Local playerName$="Player"
+Local playerChat$=""
+Local playerX#=Rnd(GWIDTH-64)+32
+Local playerY#=Rnd(GHEIGHT-64)+32
+Local playerVx#=0
+Local playerVy#=0
+Local playerRot#=0
+Local playerScore=0
+Local playerHit#=0
+Local playerShot=0
+
+'create local player
+Local localPlayer:TGNetObject=CreateGNetObject( host )
+
+SetGNetString localPlayer,SLOT_TYPE,"player"
+SetGNetString localPlayer,SLOT_NAME,playerName
+SetGNetString localPlayer,SLOT_CHAT,"Ready"
+SetGNetFloat localPlayer,SLOT_X,playerX
+SetGNetFloat localPlayer,SLOT_Y,playerY
+SetGNetFloat localPlayer,SLOT_ROT,playerRot
+SetGNetFloat localPlayer,SLOT_HIT,playerHit
+SetGNetInt localPlayer,SLOT_SCORE,playerScore
+
+While Not KeyHit( KEY_ESCAPE )
+
+       Local c=GetChar()
+       Select c
+       Case 8
+               If playerChat playerChat=playerChat[..playerChat.length-1]
+       Case 13
+               If playerChat
+                       If playerChat[..1]="/"
+                               Local cmd$=playerChat[1..]
+                               Local i=cmd.Find(" "),arg$
+                               If i<>-1
+                                       arg=cmd[i+1..]
+                                       cmd=cmd[..i]
+                               EndIf
+                               Select cmd.ToLower()
+                               Case "nick"
+                                       If arg
+                                               playerName=arg
+                                               SetGNetString localPlayer,SLOT_NAME,playerName
+                                       EndIf
+                               Case "listen"
+                                       If Not GNetListen( host,GAMEPORT ) Notify "Listen failed"
+                               Case "connect"
+                                       If Not arg arg="localhost"
+                                       If Not GNetConnect( host,arg,GAMEPORT ) Notify "Connect failed"
+                               End Select
+                       Else
+                               SetGNetString localPlayer,SLOT_CHAT,playerChat
+                       EndIf
+                       playerChat=""
+               EndIf
+       Default
+               If c>31 And c<127 playerChat:+Chr(c)
+       End Select
+       
+       If KeyDown( KEY_LEFT )
+               playerRot:-5
+               If playerRot<-180 playerRot:+360
+               SetGNetFloat localPlayer,SLOT_ROT,playerRot
+       Else If KeyDown( KEY_RIGHT )
+               playerRot:+5
+               If playerRot>=180 playerRot:-360
+               SetGNetFloat localPlayer,SLOT_ROT,playerRot
+       EndIf
+       
+       If KeyDown( KEY_UP )
+               playerVx:+Cos(playerRot)*.15
+               playerVy:+Sin(playerRot)*.15
+       Else
+               playerVx:*.99
+               If Abs(playerVx)<.1 playerVx=0
+               playerVy:*.99
+               If Abs(playerVy)<.1 playerVy=0
+       EndIf
+       
+       If playerVx
+               playerX:+playerVx
+               If playerX<-8 playerX:+GWIDTH+16 Else If playerX>=GWIDTH+8 playerX:-GWIDTH+16
+               SetGNetFloat localPlayer,SLOT_X,playerX
+       EndIf
+       
+       If playerVy
+               playerY:+playerVy
+               If playerY<-8 playerY:+GHEIGHT+16 Else If playerY>=GHEIGHT+8 playerY:-GHEIGHT+16
+               SetGNetFloat localPlayer,SLOT_Y,playerY
+       EndIf
+       
+       If playerShot playerShot:-1
+       
+       If KeyHit( KEY_LALT ) And Not playerShot
+               Local obj:TGnetObject=CreateGNetObject( host )
+               SetGNetString obj,SLOT_TYPE,"bullet"
+               SetGNetFloat obj,SLOT_X,playerX
+               SetGNetFloat obj,SLOT_Y,playerY
+               SetGNetFloat obj,SLOT_VX,playerVx+Cos(playerRot)*10
+               SetGNetFloat obj,SLOT_VY,playerVy+Sin(playerRot)*10
+               SetGNetInt obj,SLOT_TIMEOUT,60
+               playerShot=5
+       EndIf
+       
+       'update bullets
+       For Local obj:TGNetObject=EachIn GNetObjects( host )
+
+               If obj.State()=GNET_CLOSED Continue
+       
+               Local typ$=GetGNetString( obj,SLOT_TYPE )
+               If typ<>"bullet" Continue
+
+               Local x#=GetGNetFloat( obj,SLOT_X )
+               Local y#=GetGNetFloat( obj,SLOT_Y )
+               
+               If GNetObjectRemote( obj )
+                       'remote bullet? Check for collision...
+                       Local dx#=x-playerX,dy#=y-playerY
+                       If dx*dx+dy*dy<256'144
+                               Local msg:TGNetObject=CreateGNetMessage( host )
+                               If playerHit
+                                       SetGNetString msg,SLOT_TYPE,"gotme"
+                               Else
+                                       SetGNetString msg,SLOT_TYPE,"hurtme"
+                                       playerHit=1
+                               EndIf
+                               SendGNetMessage msg,obj
+                       EndIf
+               Else
+                       'local bullet? Update...
+                       Local t=GetGNetInt( obj,SLOT_TIMEOUT )
+                       
+                       If Not t
+                               CloseGNetObject obj
+                               Continue
+                       EndIf
+
+                       Local vx#=GetGNetFloat( obj,SLOT_VX )
+                       Local vy#=GetGNetFloat( obj,SLOT_VY )
+                       
+                       Local dx#=x-GWIDTH/2
+                       Local dy#=y-GHEIGHT/2
+                       Local rot#=ATan2(dy,dx)
+                       Local accel#=1/(dx*dx+dy*dy)*2000
+                       vx:-Cos(rot)*accel
+                       vy:-Sin(rot)*accel
+                       x:+vx
+                       y:+vy
+
+                       SetGNetFloat obj,SLOT_X,x
+                       SetGNetFloat obj,SLOT_Y,y
+                       SetGNetFloat obj,SLOT_VX,vx
+                       SetGNetFloat obj,SLOT_VY,vy
+                       SetGNetInt obj,SLOT_TIMEOUT,t-1
+               EndIf
+       Next
+       
+       If playerHit
+               playerHit:-.05
+               If playerHit<0 playerHit=0
+               SetGNetFloat localPlayer,SLOT_HIT,playerHit
+       EndIf
+       
+       GNetSync host
+       
+       For Local msg:TGNetObject=EachIn GNetMessages( host )
+               Local typ$=GetGNetString( msg,SLOT_TYPE )
+               Select typ
+               Case "gotme","hurtme"
+                       Local obj:TGNetObject=GNetMessageObject(msg)
+                       If obj.State()<>GNET_CLOSED
+                               If typ="hurtme" 
+                                       playerScore:+1
+                                       SetGNetInt localPlayer,SLOT_SCORE,playerScore
+                               EndIf
+                               CloseGNetObject obj
+                       EndIf
+               End Select
+       Next
+       
+       Cls
+       
+       Local ty
+       For Local obj:TGNetObject=EachIn GNetObjects( host )
+
+               If obj.State()=GNET_CLOSED Continue
+
+               Local typ$=GetGNetString( obj,SLOT_TYPE )
+               Local x#=GetGNetFloat( obj,SLOT_X )
+               Local y#=GetGNetFloat( obj,SLOT_Y )
+               Select typ
+               Case "bullet"
+                       SetBlend LIGHTBLEND
+                       SetColor 255,255,255
+                       DrawImage bulletImage,x,y
+                       SetBlend MASKBLEND
+               Case "player"
+                       Local rot#=GetGNetFloat( obj,SLOT_ROT )
+                       Local name$=GetGNetString( obj,SLOT_NAME )
+                       Local chat$=GetGNetString( obj,SLOT_CHAT )
+                       Local score=GetGNetInt( obj,SLOT_SCORE )
+                       Local hit#=GetGNetFloat( obj,SLOT_HIT )
+                       SetRotation rot
+                       SetColor 255,255,255
+                       DrawImage playerImage,x,y
+                       If hit 
+                               SetAlpha hit
+                               SetBlend LIGHTBLEND
+                               DrawImage playerImage,x,y
+                               SetBlend MASKBLEND
+                               SetAlpha 1
+                               SetColor 255,255,255
+                       EndIf
+                       SetRotation 0
+                       DrawText name+":"+score,x,y+16
+                       If obj=localPlayer SetColor 255,255,255 Else SetColor 0,128,255
+                       DrawText name+":"+chat,0,ty
+                       ty:+16
+               End Select
+       Next
+       
+       If playerChat
+               SetColor 255,255,0
+               DrawText ">"+playerChat,0,GHEIGHT-16
+               SetColor 0,255,0
+               DrawRect TextWidth(">"+playerChat),GHEIGHT-16,8,16
+       EndIf
+       
+       SetColor 255,255,255
+       Local txt$="MemAllocd:"+GCMemAlloced()
+       DrawText txt,GWIDTH-TextWidth(txt),0
+       
+       SetBlend LIGHTBLEND
+       SetRotation Rnd(360)
+       SetScale Rnd(2,2.125),Rnd(2,2.125)
+       DrawImage warpImage,GWIDTH/2,GHEIGHT/2
+       SetScale 1,1
+       SetRotation 0
+       SetBlend MASKBLEND
+       
+       Flip
+
+Wend
+
+CloseGNetHost host
diff --git a/samples/mak/requestgraphicsmode.bmx b/samples/mak/requestgraphicsmode.bmx
new file mode 100644 (file)
index 0000000..080b9b9
--- /dev/null
@@ -0,0 +1,102 @@
+
+Strict
+
+Import MaxGui.Drivers
+
+Repeat
+
+       Local w,h,d,r
+
+       If Not RequestGraphicsMode( w,h,d,r ) End
+
+       Graphics w,h,d,r
+
+       DrawText "Graphics Mode:"+w+","+h+","+d+" "+r+"Hz",0,0
+       DrawText "Hit any key",0,16
+
+       Flip
+
+       WaitKey
+       
+       EndGraphics
+
+Forever
+
+Function ListModes( list:TGadget )
+       ClearGadgetItems list
+       For Local t:TGraphicsMode=EachIn GraphicsModes()
+               AddGadgetItem list,t.ToString()
+       Next
+       SelectGadgetItem list,0
+End Function
+
+Function RequestGraphicsMode( width Var,height Var,depth Var,hertz Var )
+
+       Local w=ClientWidth( Desktop() ),h=ClientHeight( Desktop() )
+
+       Local window:TGadget=CreateWindow( "Select graphics Mode",w/2-160,h/2-160,320,320,Null,WINDOW_TITLEBAR )
+       
+       Local panel:TGadget=CreatePanel( 0,0,ClientWidth(window),ClientHeight(window),window )
+
+       w=ClientWidth(panel) ; h=ClientHeight(panel)
+       
+       Local okay:TGadget=CreateButton( "Okay",w-104,h-32,96,24,panel,BUTTON_OK )
+       
+       CreateLabel "Graphics Mode:",8,16,w-16,16,panel
+       Local list1:TGadget=CreateListBox( 8,32,w-16,h-128,panel )
+
+       CreateLabel "Graphics Driver:",8,h-80,w-16,16,panel
+       Local combo1:TGadget=CreateComboBox( 8,h-64,w-16,24,panel )
+       DisableGadget combo1
+       AddGadgetItem combo1,"OpenGL"
+       SelectGadgetItem combo1,0
+       SetGraphicsDriver GLMax2DDriver()
+?Win32
+       EnableGadget combo1
+       AddGadgetItem combo1,"Direct3D7"
+       SelectGadgetItem combo1,1
+       SetGraphicsDriver D3D7Max2DDriver()
+?
+       Local cancel:TGadget=CreateButton( "Cancel",8,h-32,96,24,panel,BUTTON_CANCEL )
+
+       ListModes list1
+       ActivateGadget list1
+
+       Local ret=False 
+               
+       While WaitEvent()<>EVENT_WINDOWCLOSE
+               Select EventID()
+               Case EVENT_GADGETACTION
+                       Select EventSource()
+                       Case okay
+                               Local t:TGraphicsMode=GraphicsModes()[ SelectedGadgetItem( list1 ) ]
+                               width=t.width
+                               height=t.height
+                               depth=t.depth
+                               hertz=t.hertz
+                               ret=True
+                               Exit
+                       Case cancel
+                               Exit
+                       Case combo1
+                               Select SelectedGadgetItem( combo1 )
+                               Case 0
+                                       SetGraphicsDriver GLMax2DDriver()
+?Win32
+                               Case 1
+                                       SetGraphicsDriver D3D7Max2DDriver()
+?
+                               End Select
+                               ListModes list1
+                       End Select
+               Case EVENT_WINDOWCLOSE
+                       Exit
+               End Select
+       Wend
+       
+       FreeGadget window
+       
+       Return ret
+       
+End Function
+
diff --git a/samples/mak/ship.png b/samples/mak/ship.png
new file mode 100644 (file)
index 0000000..5712f1a
Binary files /dev/null and b/samples/mak/ship.png differ
diff --git a/samples/mak/sparkle.png b/samples/mak/sparkle.png
new file mode 100644 (file)
index 0000000..7dd3851
Binary files /dev/null and b/samples/mak/sparkle.png differ
diff --git a/samples/maxgui/bigsearch.bmx b/samples/maxgui/bigsearch.bmx
new file mode 100644 (file)
index 0000000..5b6849d
--- /dev/null
@@ -0,0 +1,142 @@
+Import MaxGui.Drivers
+
+AppTitle = "BigSearch"
+
+Const Views = 1'3 ' Update this if you add more searches in DefData lines below!
+
+Global HTML:TGadget [Views]
+
+Global HTMLTitle$ [Views]
+Global HTMLURL$ [Views]
+
+gadheight = 24
+
+For site = 0 To Views - 1
+       ReadData HTMLTitle (site)
+       ReadData HTMLURL (site)
+Next
+
+' Some random examples...
+
+'DefData "Google", "http://www.google.com/search?q="
+'DefData "Yahoo", "http://search.yahoo.com/search?p="
+DefData "Merriam-Webster Dictionary", "http://www.m-w.com/cgi-bin/dictionary?"
+
+Load = ReadFile ("window.dat")
+If Load
+       x = Int (ReadLine (Load))
+       y = Int (ReadLine (Load))
+       width = Int (ReadLine (Load))
+       height = Int (ReadLine (Load))
+EndIf
+
+If x < 0 Then x = 0
+If x > GadgetWidth (Desktop ()) x = 0
+
+If y < 0 Then x = 0
+If y > GadgetHeight (Desktop ()) x = 0
+
+If width <= 0 width = 640
+If height <= 0 height = 480
+
+window:TGadget = CreateWindow ("BigSearch", x, y, width, height)
+
+htmlheight = (ClientHeight (window) - gadheight) / Views
+
+If window
+
+       file:TGadget = CreateMenu ("&File", 0, WindowMenu (window))
+       xit:TGadget = CreateMenu ("E&xit", 1, file)
+
+       help:TGadget = CreateMenu ("&Help", 2, WindowMenu (window))
+       about:TGadget = CreateMenu ("&About...", 3, help)
+
+       UpdateWindowMenu window
+       
+       search:TGadget = CreateTextField (4, 4, ClientWidth (window) - 152, gadheight, window)
+
+       go:TGadget = CreateButton ("Search!", ClientWidth (window) - 144, 4, 140, gadheight, window, BUTTON_OK)
+
+       SetGadgetLayout search, 1, 1, 1, 0
+       SetGadgetLayout go, 0, 1, 1, 0
+
+       tab:TGadget = CreateTabber (0, gadheight+4, ClientWidth (window), ClientHeight (window) - gadheight - 4, window)        
+       panel:TGadget = CreatePanel (0, 0, ClientWidth (tab), ClientHeight (tab), tab)
+
+       SetGadgetLayout tab, 1, 1, 1, 1
+       SetGadgetLayout panel, 1, 1, 1, 1
+       
+       For loop = 0 To Views - 1
+               HTML (loop) = CreateHTMLView (0, 0, ClientWidth (panel), ClientHeight (panel), panel)
+               SetGadgetLayout HTML (loop), 1, 1, 1, 1
+               HideGadget HTML (loop)
+               AddGadgetItem (tab, HTMLTitle (loop))
+       Next
+       
+       ShowGadget HTML (0)
+       SetStatusText window, "Done"
+       
+       urltimer:TTimer = CreateTimer (1)
+       
+       ActivateGadget search
+       
+       Repeat
+
+               Select WaitEvent ()
+'              Print currentevent.toString()
+'              Select EventID()
+
+                       Case EVENT_GADGETACTION
+                               If (EventSource () = go)' Or ((EventSource () = search) And (EventData () = KEY_ENTER))
+                                       For site = 0 To Views - 1
+                                               HtmlViewGo HTML (site), HTMLURL (site) + TextFieldText (search)
+                                       Next
+                               EndIf
+
+                               If EventSource () = tab
+                                       For loop = 0 To Views - 1
+                                               HideGadget HTML (loop)
+                                       Next
+                                       ShowGadget HTML (SelectedGadgetItem (tab))
+                                       ActivateGadget HTML (SelectedGadgetItem (tab))
+                               EndIf
+                               
+                       Case EVENT_WINDOWCLOSE
+                               SaveWindow (window); End
+
+' ****** Not working!
+
+                       Case EVENT_TIMERTICK
+'                      DebugLog HtmlViewStatus (HTML (SelectedGadgetItem (tab)))
+                                       If HtmlViewStatus (HTML (SelectedGadgetItem (tab))) 
+                                               SetStatusText window, "Loading..."
+                                       Else
+                                               SetStatusText window, "Done"
+                                       EndIf
+
+'                      Case EVENT_GADGETDONE
+'                      DebugLog HtmlViewStatus (HTML (SelectedGadgetItem (tab)))
+                                               
+                       Case EVENT_MENUACTION
+                               If EventData () = 1 Then SaveWindow (window); End
+                               If EventData () = 3 Then Notify ("BigSearch: it searches [tm]")
+                       
+               End Select
+               
+       Forever
+       
+EndIf
+
+Function SaveWindow (window:TGadget)
+       If window
+               save = WriteFile ("window.dat")
+               If save
+                       WriteLine save, GadgetX (window)
+                       WriteLine save, GadgetY (window)
+                       WriteLine save, GadgetWidth (window)
+                       WriteLine save, GadgetHeight (window)
+                       CloseFile save
+               EndIf
+       EndIf
+End Function
+
diff --git a/samples/maxgui/glcube.bmx b/samples/maxgui/glcube.bmx
new file mode 100644 (file)
index 0000000..f0d357d
--- /dev/null
@@ -0,0 +1,134 @@
+
+'Simple GL cube demo
+'Written by Birdie
+
+Import MaxGui.Drivers
+
+Strict
+SetGraphicsDriver GLGraphicsDriver(),GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER
+
+Global ax#, ay#,tim#
+
+Local w:TGadget = CreateWindow("Easy GL Cube in a GUI window", 10, 10, 512, 512 )
+
+Local c:TGadget = CreateCanvas(0,0,w.ClientWidth(),w.ClientHeight(),w,0)
+c.setlayout 1,1,1,1
+CreateTimer( 60 )
+
+While True
+        WaitEvent()
+        Select EventID()
+                Case EVENT_WINDOWCLOSE
+                        End
+                Case EVENT_TIMERTICK
+                        RedrawGadget c
+                        
+                Case EVENT_GADGETPAINT
+                        SetGraphics CanvasGraphics( c )
+                                Local wid = c.ClientWidth()
+                                Local hgt = c.ClientHeight()
+                                Local asp# = Float(wid)/Float(hgt)
+                                
+                                glViewport 0,0,wid,hgt
+                                glMatrixMode GL_PROJECTION
+                                glLoadIdentity
+                                gluPerspective 45, asp, 1, 100
+                                gltranslatef 0,0,-50+tim
+                                tim=20*Cos(MilliSecs()/10.0)
+                                
+                                glMatrixMode GL_MODELVIEW
+                                glLoadIdentity
+                                
+                                Local global_ambient#[]=[0.6#, 0.5#,  0.3#, 1.0#]
+                                Local light0pos#[]=     [0.0#, 5.0#, 10.0#, 1.0#]
+                                Local light0ambient#[]= [0.5#, 0.5#,  0.5#, 1.0#]
+                                Local light0diffuse#[]= [0.3#, 0.3#,  0.3#, 1.0#]
+                                Local light0specular#[]=[0.8#, 0.8#,  0.8#, 1.0#]
+                        
+                                Local lmodel_ambient#[]=[ 0.2#,0.2#,0.2#,1.0#]
+                                glLightModelfv(GL_LIGHT_MODEL_AMBIENT,lmodel_ambient)
+                        
+                                glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient)
+                                glLightfv(GL_LIGHT0, GL_POSITION, light0pos)
+                                glLightfv(GL_LIGHT0, GL_AMBIENT, light0ambient)
+                                glLightfv(GL_LIGHT0, GL_DIFFUSE, light0diffuse)
+                                glLightfv(GL_LIGHT0, GL_SPECULAR, light0specular)
+                                glEnable(GL_LIGHTING)
+                                glEnable(GL_LIGHT0)
+                                glShadeModel(GL_SMOOTH)
+                                glMateriali(GL_FRONT, GL_SHININESS, 128)
+        
+                                                                
+                                glClearColor 0,0,0.5,1
+                                glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+
+                                glEnable(GL_DEPTH_TEST)
+                                
+                                glRotatef ax,1,0,0
+                                glRotatef ay,0,1,0
+                                ax:+1
+                                ay:+5
+                                DrawSizeCube(7)
+                                
+                                Flip
+                                
+        EndSelect
+Wend
+
+
+
+Function DrawSizeCube(size#)
+        size=-size
+        'Front Face
+        glBegin(GL_TRIANGLE_STRIP)
+                glNormal3f( 0.0, 0.0, 1.0)
+                glVertex3f( size, size,-size)
+                glNormal3f( 0.0, 0.0, 1.0)
+                glVertex3f(-size, size,-size)
+                glNormal3f( 0.0, 0.0, 1.0)
+                glVertex3f( size,-size,-size)
+                glNormal3f( 0.0, 0.0, 1.0)
+                glVertex3f(-size,-size,-size)
+        glEnd
+        'Back Face
+        glNormal3f( 0.0, 0.0, -1.0)
+        glBegin(GL_TRIANGLE_STRIP)
+                glVertex3f(-size, size, size)
+                glVertex3f( size, size, size)
+                glVertex3f(-size,-size, size)
+                glVertex3f( size,-size, size)
+        glEnd
+        'Right Face
+        glNormal3f( 1.0, 0.0, 0.0)
+        glBegin(GL_TRIANGLE_STRIP)
+                glVertex3f(-size, size,-size)
+                glVertex3f(-size, size, size)
+                glVertex3f(-size,-size,-size)
+                glVertex3f(-size,-size, size)
+        glEnd
+        'Left Face
+        glNormal3f( -1.0, 0.0, 0.0)
+        glBegin(GL_TRIANGLE_STRIP)
+                glVertex3f( size, size, size)
+                glVertex3f( size, size,-size)
+                glVertex3f( size,-size, size)
+                glVertex3f( size,-size,-size)
+        glEnd
+        'Bottom Face
+        glNormal3f( 0.0, -1.0, 0.0)
+        glBegin(GL_TRIANGLE_STRIP)
+                glVertex3f( size, size,-size)
+                glVertex3f( size, size, size)
+                glVertex3f(-size, size,-size)
+                glVertex3f(-size, size, size)
+        glEnd
+        'Top Face
+        glNormal3f( 0.0, 1.0, 0.0)
+        glBegin(GL_TRIANGLE_STRIP)
+                glVertex3f( size,-size,-size)
+                glVertex3f(-size,-size,-size)
+                glVertex3f( size,-size, size)
+                glVertex3f(-size,-size, size)
+    glEnd
+End Function
+
diff --git a/samples/maxgui/guilauncher/PNGHeader.bmx b/samples/maxgui/guilauncher/PNGHeader.bmx
new file mode 100644 (file)
index 0000000..79d35e1
--- /dev/null
@@ -0,0 +1,60 @@
+Strict
+
+Import BRL.Stream
+Import BRL.EndianStream
+
+Type PNGHeader
+
+       Field signiture:String
+       Field chunksize:Int
+       Field chunkID:String
+       Field width:Int
+       Field height:Int
+       Global PNG_ID:String = Chr($89) + Chr($50) + Chr($4E) + Chr($47) + Chr($0D) + Chr($0A) + Chr($1A) + Chr($0A)
+
+       Function fromFile:PNGHeader( url:Object )
+               Local myStream:TStream = ReadStream( url )
+               Local temp:PNGHeader
+               If StreamSize (myStream) > 24
+                       temp = New PNGHeader
+                       Local eStream:TStream = BigEndianStream(myStream)
+                       temp.signiture = ReadString (eStream , 8)
+                       temp.chunksize = Readint (eStream)
+                       temp.chunkID = ReadString (eStream , 4)
+                       temp.width = Readint (eStream)
+                       temp.height = Readint (eStream)
+                       CloseStream eStream
+               EndIf
+               CloseStream myStream
+               Return temp
+       EndFunction     
+
+       Function fromPtr:PNGHeader( Pointer:Byte Ptr )
+               Local temp:PNGHeader = New PNGHeader
+               temp.signiture = Chr(Pointer[0]) + Chr(Pointer[1]) + Chr(Pointer[2]) + Chr(Pointer[3]) + Chr(Pointer[4]) + Chr(Pointer[5]) + Chr(Pointer[6]) + Chr(Pointer[7])
+               temp.chunksize = Pointer[8] Shl 24 | Pointer[9] Shl 16 | Pointer[10] Shl 8 | Pointer[11]
+               temp.chunkID = Chr(Pointer[12]) + Chr(Pointer[13]) + Chr(Pointer[14]) + Chr(Pointer[15])
+               temp.width = Pointer[16] Shl 24 | Pointer[17] Shl 16 | Pointer[18] Shl 8 | Pointer[19]
+               temp.height = Pointer[20] Shl 24 | Pointer[21] Shl 16 | Pointer[22] Shl 8 | Pointer[23]
+               Return temp
+       EndFunction
+
+       Method isPNG:Int()
+               If signiture = PNG_ID
+                       Return True
+               EndIf
+               Return False
+       EndMethod
+       
+       Method toString:String()
+               Local temp:String = "isPng: "
+               If isPNG()
+                       temp:+"True "
+               Else
+                       temp:+"False "
+               EndIf
+               temp:+"Width: " + width + " Height: " + height
+               
+               Return temp
+       EndMethod
+EndType 
\ No newline at end of file
diff --git a/samples/maxgui/guilauncher/TLauncher.bmx b/samples/maxgui/guilauncher/TLauncher.bmx
new file mode 100644 (file)
index 0000000..3b1d862
--- /dev/null
@@ -0,0 +1,145 @@
+Strict
+
+Import MaxGui.Drivers
+
+Import "PNGHeader.bmx"
+Incbin "bmxlogo.png"
+
+Type TAR
+       Field width:Int
+       Field height:Int
+       
+       Function Create:TAR( width:Int , height:Int )
+               Local temp:TAR = New TAR
+               temp.width = width
+               temp.height = height
+               Return temp
+       EndFunction
+       Method ToString:String()
+       Return width + ":" + height
+       EndMethod
+EndType
+
+Type TLauncher
+       Field angle = 0
+       Field sync:TTimer
+       Field myWindow:TGadget
+       Field myCanvas:TGadget
+       Field myLogo:TImage
+       Field myLB:TGadget
+       Field resMap:TMap
+       Field btnLaunch:TGadget
+       Field btnAbort:TGadget
+       Field terminate = False
+       Field selected:TGraphicsMode
+       Field isDisposed = True
+       Field aspectRatios:TList
+       Field pngInfo:PNGHeader
+
+       Method initGUI()
+               myWindow = CreateWindow("Arise GUI Launcher - BETA", Desktop().width/2 - 100, Desktop().height/2 - 100, 200, 200, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS | WINDOW_HIDDEN)
+               myCanvas:TGadget = CreateCanvas ( 0 , 0 , 200 , 87 , myWindow)
+               pngInfo:PNGHeader = PNGHeader.fromPtr(IncbinPtr( "bmxlogo.png" ))
+               If pngInfo.isPNG()
+                       myLogo:TImage = LoadAnimImage( "incbin::bmxlogo.png",pngInfo.width,1,0,pngInfo.height )
+               EndIf
+               myLB:TGadget = CreateListBox(0,88,200,93,myWindow)
+               For Local i:String = EachIn resMap.Keys()
+                       AddGadgetItem myLB , i
+               Next
+               
+               'SelectGadgetItem myLB , CountGadgetItems(myLB) -1
+               sync = CreateTimer(100)
+               btnLaunch = CreateButton ("LAUNCH!" , 0,181,100,20,myWindow)
+               btnAbort = CreateButton ("ABORT!" , 100,181,100,20,myWindow)
+               isDisposed = False
+       EndMethod
+
+       Function Create:TLauncher()
+               Local temp:TLauncher = New TLauncher
+               temp.addAspectRatio( 4 , 3 )
+               temp.populateModes
+               Return temp
+       End Function
+
+       Method populateModes()
+               If aspectRatios = Null
+                       addAspectRatio( 4 , 3 )
+               EndIf
+               resMap = New TMap
+
+               For Local i:TGraphicsMode = EachIn GraphicsModes()
+                       For Local j:TAR = EachIn aspectRatios
+                               If i.width / j.width = i.height / j.height And i.depth > 8
+                                       Local res:String = i.width + " x " + i.height + " - " + i.depth + " bits @ " + i.hertz + "Hz"
+                                       resMap.insert res , i
+                                       Exit
+                               EndIf
+                       Next
+               Next
+       EndMethod
+
+       Method addAspectRatio( width:Int , height:Int )
+               If aspectRatios = Null
+                       aspectRatios = New TList
+               EndIf
+               aspectRatios.addLast( TAR.Create( width , height ))
+       EndMethod
+
+       Method show()
+               If Not isDisposed
+                       ShowGadget myWindow     
+               EndIf
+       EndMethod
+
+       Method hide()
+               If Not isDisposed
+                       HideGadget myWindow
+               EndIf
+       EndMethod
+       
+       Method dispose()
+               FreeGadget myWindow
+               FreeGadget myCanvas
+               FreeGadget btnLaunch
+               FreeGadget btnAbort
+               FreeGadget myLB
+
+               myLogo = Null
+               resMap = Null
+               myWindow = Null
+               myCanvas = Null
+               btnLaunch = Null
+               btnAbort = Null
+               myLB = Null
+               isDisposed = True
+       EndMethod
+
+       Method getSelectedMode:TGraphicsMode()
+               Return selected
+       EndMethod
+       
+       Method main()
+               If Not isDisposed
+                       WaitEvent
+                       If CurrentEvent.id = EVENT_TIMERTICK 
+                               angle = TimerTicks(sync) Mod 360 
+                               SetGraphics CanvasGraphics( myCanvas )
+                               SetClsColor 255 , 255 , 255
+                               Cls
+                               For Local i:Int = 0 Until pngInfo.height
+                                       DrawImage myLogo,24 + Sin(angle+i*2) * 48,i,i
+                               Next
+                               Flip
+                       ElseIf CurrentEvent.id = EVENT_APPTERMINATE Or CurrentEvent.id = EVENT_WINDOWCLOSE Or..
+                               ( CurrentEvent.id = EVENT_GADGETACTION And EventSource() = btnAbort )
+                               terminate = True
+                       ElseIf ( CurrentEvent.id = EVENT_GADGETACTION And EventSource() = btnLaunch )
+                               terminate = True
+                               If SelectedGadgetItem(myLB)<>-1
+                                       selected = TGraphicsMode(resMap.ValueForKey(GadgetItemText(myLB,SelectedGadgetItem(myLB))))
+                               EndIf
+                       EndIf
+               EndIf
+       EndMethod
+EndType
diff --git a/samples/maxgui/guilauncher/bmxlogo.png b/samples/maxgui/guilauncher/bmxlogo.png
new file mode 100644 (file)
index 0000000..fa1e3bf
Binary files /dev/null and b/samples/maxgui/guilauncher/bmxlogo.png differ
diff --git a/samples/maxgui/guilauncher/test.bmx b/samples/maxgui/guilauncher/test.bmx
new file mode 100644 (file)
index 0000000..ebbe453
--- /dev/null
@@ -0,0 +1,24 @@
+Strict
+
+Import "TLauncher.bmx"
+
+Local myL:TLauncher
+Local myMode:TGraphicsMode
+
+'myL = TLauncher.Create() <- The quick way, will create a standard requester with only a 4:3 aspect ratio.
+
+myL = New TLauncher
+
+myL.addAspectRatio( 4 , 3 )
+myL.addAspectRatio( 16 , 9 )
+myL.populateModes
+
+myL.initGUI()
+myL.show()
+While Not myL.terminate
+       myL.main
+EndWhile
+If myL.selected <> Null
+       Print myL.selected.toString()
+EndIf
+
diff --git a/samples/maxgui/imagedrop.bmx b/samples/maxgui/imagedrop.bmx
new file mode 100644 (file)
index 0000000..1ac2e97
--- /dev/null
@@ -0,0 +1,135 @@
+' file drag & drop example
+
+Import MaxGui.Drivers
+
+Strict
+
+Const MENU_EXIT=105
+Const MENU_ABOUT=109
+
+'
+' A window
+Local win:TGadget = CreateWindow("Drag & Drop!",100,100,400,400,Null,WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_MENU|WINDOW_STATUS|WINDOW_CLIENTCOORDS|WINDOW_ACCEPTFILES)
+
+'
+' A simple menu
+Local filemenu:TGadget = CreateMenu("&File",0,WindowMenu(win))
+CreateMenu"E&xit",MENU_EXIT,filemenu
+
+Local helpmenu:TGadget = CreateMenu("&Help",0,WindowMenu(win))
+CreateMenu "&About",MENU_ABOUT,helpmenu
+
+UpdateWindowMenu win
+
+'
+' A canvas gadget to display the image
+Local can:TGadget = CreateCanvas(0,0,400,400,win,1)
+SetGadgetLayout can,1,1,1,1
+
+'
+' A few bits and pieces
+Local image:Timage
+Local file:String = "Drag an image file onto window"
+SetStatusText win,file
+
+
+'
+' Main loop
+While WaitEvent()
+       Select EventID()
+
+               Case EVENT_GADGETPAINT
+                       Select EventSource()
+                               Case can
+                                       '
+                                       ' Draw to the canvas
+                                       SetGraphics CanvasGraphics(can)
+                                       
+                                       '
+                                       ' Make sure it has the correct dimensions
+                                       SetViewport 0,0,GadgetWidth(can),GadgetHeight(can)
+                                       
+                                       '
+                                       ' Draw the checker background
+                                       SetBlend SOLIDBLEND
+                                       Local a:Int = 1
+                                       Local b:Int = 1
+                                       For Local x = 0 To GadgetWidth(can) Step 16
+                                               b = Not b
+                                               a = b
+                                               For Local y = 0 To GadgetHeight(can) Step 16
+                                                       a = Not a
+                                                       SetColor 160-a*20,160-a*20,160-a*20
+                                                       DrawRect x,y,16,16
+                                               Next
+                                       Next
+                                               
+                                       '
+                                       ' Draw the image
+                                       If image
+                                               SetBlend ALPHABLEND
+                                               SetColor 255,255,255
+                                               
+                                               Local scale:Float = Min(1.0,Min(Float(ClientWidth(can))/ImageWidth(image),Float(ClientHeight(can))/ImageHeight(image)))
+               
+                                               Local w = ImageWidth(image)*scale
+                                               Local h = ImageHeight(image)*scale      
+                                               Local x = (ClientWidth(can)-w)/2
+                                               Local y = (ClientHeight(can)-h)/2
+               
+                                               SetScale scale,scale
+                                               DrawImage image,x,y
+               
+                                               SetScale 1,1
+                                               SetBlend SHADEBLEND
+                                               SetColor 170,170,170                    
+                                               DrawRect x-1,0,1,ClientHeight(can)
+                                               DrawRect x+w,0,1,ClientHeight(can)
+                                               DrawRect 0,y-1,ClientWidth(can),1
+                                               DrawRect 0,y+h,ClientWidth(can),1
+                                               
+                                               SetStatusText win,file+" @ "+Int(scale*100)+"%"
+                                       EndIf
+                                       
+                                       Flip
+                       EndSelect
+                                       
+               Case EVENT_WINDOWCLOSE
+                       '
+                       ' Quit
+                       End
+                       
+               Case EVENT_WINDOWACCEPT
+                       '
+                       ' A file has been dragged and dropped on the window
+                       file = EventExtra().tostring()
+                       
+                       '
+                       ' Try loading the file as an image
+                       image = LoadImage(file)
+                       If image = Null
+                               file = "Invalid file format!"
+                       Else
+                               file = file+"  ("+(FileSize(file)/1024)+"Kb)  "+ImageWidth(image)+"x"+ImageHeight(image)
+                       EndIf
+                       SetStatusText win,file
+                       RedrawGadget can
+               
+               Case EVENT_MENUACTION
+                       '
+                       ' Menu stuff
+                       Select EventData()
+                               Case MENU_EXIT
+                                       End
+                               Case MENU_ABOUT
+                                       Notify "File drag & drop example!~nBy Mikkel Fredborg"
+                       End Select
+               
+               Default
+                       '
+                       ' Uncomment this to show what other events occur
+                       ' Print CurrentEvent.toString()
+                                       
+       EndSelect
+       
+Wend
diff --git a/samples/maxgui/sliderthing/sliderthing.bmx b/samples/maxgui/sliderthing/sliderthing.bmx
new file mode 100644 (file)
index 0000000..87a16a6
--- /dev/null
@@ -0,0 +1,211 @@
+'
+' www.sublimegames.com
+' Silly picture tool by Stephen Greener (aka Shagwana)
+'
+'
+
+Strict
+Import MaxGUI.Drivers
+
+
+'_/ Consts \_______________________________________________________________________________________________________________
+
+Const iLEVEL_X_PIXEL_SIZE:Int = 32
+Const iLEVEL_Y_PIXEL_SIZE:Int = 32
+
+Const iLEVEL_X_SIZE:Int = 512 / iLEVEL_X_PIXEL_SIZE
+Const iLEVEL_Y_SIZE:Int = 512 / iLEVEL_Y_PIXEL_SIZE
+
+
+'_/ Includes \_______________________________________________________________________________________________________________
+
+
+
+'Image files
+Incbin "sourcepic.jpg"   '512x512 
+
+
+'_/ Types \_______________________________________________________________________________________________________________
+
+
+
+Type tLevelInfo
+
+  Field pImage:TImage[iLEVEL_X_SIZE,iLEVEL_Y_SIZE]
+  Field pMapping:TImage[iLEVEL_X_SIZE,iLEVEL_Y_SIZE]
+
+
+  Method Reset()
+    For Local iX:Int=0 To iLEVEL_X_SIZE-1
+      For Local iY:Int=0 To iLEVEL_Y_SIZE-1
+        pMapping[iX,iY]=pImage[iX,iY]
+        Next
+      Next
+    End Method
+
+  Method Load(sFilename:String)
+    'Load the image
+    Local pPixmap:TPixmap=LoadPixmap(sFilename)
+    pPixmap:TPixmap=ConvertPixmap(pPixmap:TPixmap,PF_BGR888)
+    For Local iX:Int=0 To iLEVEL_X_SIZE-1
+      For Local iY:Int=0 To iLEVEL_Y_SIZE-1
+        Local tWinPixMap:TPixmap=PixmapWindow(pPixmap:TPixmap,iX*iLEVEL_X_PIXEL_SIZE,iY*iLEVEL_Y_PIXEL_SIZE,iLEVEL_X_PIXEL_SIZE,iLEVEL_Y_PIXEL_SIZE)
+        pImage:TImage[iX,iY]=LoadImage(tWinPixMap:TPixmap,MASKEDIMAGE)    'Chop up the image into tiles
+        pMapping[iX,iY]=pImage:TImage[iX,iY]
+        Next
+      Next
+    End Method
+
+  Method Draw()
+    SetBlend SOLIDBLEND
+    For Local iX:Int=0 To iLEVEL_X_SIZE-1
+      For Local iY:Int=0 To iLEVEL_Y_SIZE-1
+        DrawImage pMapping[iX,iY],(iX*32),(iY*32)
+        Next
+      Next
+    Flip
+    End Method
+
+  End Type 
+
+
+
+
+'_/ Setup \_______________________________________________________________________________________________________________
+
+Local pMainWindow:TGadget = CreateWindow("Picture sliding thing v1.0",(GadgetWidth(Desktop())-600)/2,(GadgetHeight(Desktop())-600)/2,600,600,Null,WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
+Local pCanvas:TGadget = CreateCanvas(44,44,512,512,pMainWindow:TGadget)
+
+Local pLeftButton:TGadget[16]
+Local pRightButton:TGadget[16]
+Local pTopButton:TGadget[16]
+Local pBottomButton:TGadget[16]
+
+For Local iLoop:Int=0 To 15
+  pRightButton[iLoop]=CreateButton("+",512+44,44+(iLoop*32),32,32,pMainWindow,BUTTON_PUSH)
+  pLeftButton[iLoop]=CreateButton("+",44-32,44+(iLoop*32),32,32,pMainWindow,BUTTON_PUSH)
+  pTopButton[iLoop]=CreateButton("+",44+(iLoop*32),44-32,32,32,pMainWindow,BUTTON_PUSH)
+  pBottomButton[iLoop]=CreateButton("+",44+(iLoop*32),512+44,32,32,pMainWindow,BUTTON_PUSH)
+  Next
+
+
+Global tGameLevel:tLevelInfo = New tLevelInfo
+tGameLevel.Load("incbin::sourcepic.jpg")    'Load it from the included file
+
+Local bQuitProgram=False
+
+'_/ Main program \_______________________________________________________________________________________________________________
+
+
+
+Repeat
+
+       gccollect
+   
+       WaitEvent() 
+
+    Local pGadgetResposible:TGadget=Null
+    Local iDir:Int=-1
+    Local iXLine:Int=-1
+    Local iYLine:Int=-1
+
+    For Local iLoop:Int=0 To 15
+      If EventSource()=pLeftButton[iLoop] 
+        pGadgetResposible=pLeftButton[iLoop]
+        iXLine=-1
+        iYLine=iLoop
+        iDir=1
+        EndIf
+      If EventSource()=pRightButton[iLoop] 
+        pGadgetResposible=pRightButton[iLoop] 
+        iXLine=-1
+        iYLine=iLoop
+        iDir=-1
+        EndIf
+      If EventSource()=pTopButton[iLoop] 
+        pGadgetResposible=pTopButton[iLoop]
+        iYLine=-1
+        iXLine=iLoop
+        iDir=1
+        EndIf
+      If EventSource()=pBottomButton[iLoop] 
+        pGadgetResposible=pBottomButton[iLoop]
+        iYLine=-1
+        iXLine=iLoop
+        iDir=-1
+        EndIf
+      Next
+
+
+
+    If pGadgetResposible<>Null
+      'Was a slider gadget ? ...
+
+      If iYLine<>-1
+        'X line to scroll
+        If iDir=1
+          'Scroll map one way
+          Local pTemp:TImage=tGameLevel.pMapping[0,iYLine]
+          For Local iP:Int=0 To iLEVEL_Y_SIZE-2
+            tGameLevel.pMapping[iP,iYLine]=tGameLevel.pMapping[iP+1,iYLine]
+            Next
+          tGameLevel.pMapping[iLEVEL_X_SIZE-1,iYLine]=pTemp:TImage
+          Else
+          'Scroll map the other way
+          Local pTemp:TImage=tGameLevel.pMapping[iLEVEL_X_SIZE-1,iYLine]
+          For Local iP:Int=iLEVEL_Y_SIZE-2 To 0 Step -1
+            tGameLevel.pMapping[iP+1,iYLine]=tGameLevel.pMapping[iP,iYLine]
+            Next
+          tGameLevel.pMapping[0,iYLine]=pTemp:TImage
+          EndIf
+
+        Else 
+        'Presume that iXLine<>-1
+        If iDir=1
+          'Scroll map one way
+          Local pTemp:TImage=tGameLevel.pMapping[iXLine,0]
+          For Local iP:Int=0 To iLEVEL_X_SIZE-2
+            tGameLevel.pMapping[iXLine,iP]=tGameLevel.pMapping[iXLine,iP+1]
+            Next
+          tGameLevel.pMapping[iXLine,iLEVEL_X_SIZE-1]=pTemp:TImage
+          Else
+          'Scroll map the other way
+          Local pTemp:TImage=tGameLevel.pMapping[iXLine,iLEVEL_Y_SIZE-1]
+          For Local iP:Int=iLEVEL_X_SIZE-2 To 0 Step -1
+            tGameLevel.pMapping[iXLine,iP+1]=tGameLevel.pMapping[iXLine,iP]
+            Next
+          tGameLevel.pMapping[iXLine,0]=pTemp:TImage
+          EndIf
+
+        EndIf
+
+      'Redraw the display cause we have moved it
+      SetGraphics CanvasGraphics(pCanvas)
+      Cls
+      tGameLevel.Draw()
+
+
+
+      Else
+
+      'Not one of the main game control gadgets
+      Select EventID()
+       
+        Case EVENT_GADGETPAINT
+        'Redraw the main display
+           SetGraphics CanvasGraphics(pCanvas)
+        Cls
+        tGameLevel.Draw()
+       
+        Case EVENT_WINDOWCLOSE
+        'Quit the program
+        bQuitProgram=True
+
+        End Select
+      EndIf
+
+  
+  Until bQuitProgram=True
+
+End
\ No newline at end of file
diff --git a/samples/maxgui/sliderthing/sourcepic.jpg b/samples/maxgui/sliderthing/sourcepic.jpg
new file mode 100644 (file)
index 0000000..eba4ee6
Binary files /dev/null and b/samples/maxgui/sliderthing/sourcepic.jpg differ
diff --git a/samples/shooter/_shooter_main.bmx b/samples/shooter/_shooter_main.bmx
new file mode 100644 (file)
index 0000000..4f1659d
--- /dev/null
@@ -0,0 +1,148 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' main
+'===============================================================================
+' A little shooty thing! Needs a lot of work as I only hacked it together in
+' about three hours one night and it's a right mix of both procedural and OO
+' but it may inspire someone to do something..
+'===============================================================================
+
+Include "globals.bmx"
+Include "player.bmx"
+Include "playershots.bmx"
+Include "enemies.bmx"
+Include "background.bmx"
+Include "particles.bmx"
+Include "sound.bmx"
+Include "init.bmx"
+Include "titles.bmx"
+Include "gfont.bmx"
+
+' -----------------------------------------------------------------------------
+
+Global tm, ms, old
+
+AppTitle$="Choose Screen Mode"
+Graphics 320,240,0,60
+DrawText "(W)indowed or (F)ullscreen?",0,120 ; Flip
+
+Repeat
+Until (KeyDown(KEY_F) Or KeyDown(KEY_W)) Or JoyDown(2)
+
+AppTitle$="Little Shooty Test by RiK (ESC To quit)"
+
+If KeyDown(KEY_W) Or JoyDown(2) Then
+       Graphics WIDTH, HEIGHT,0,60
+Else
+       Graphics WIDTH, HEIGHT,32,60
+EndIf
+
+AutoMidHandle True
+SeedRnd(MilliSecs())
+
+' -----------------------------------------------------------------------------
+' init
+' -----------------------------------------------------------------------------
+
+init()
+Gfont.Init()
+HideMouse()
+ShowTitlePage()
+
+' -----------------------------------------------------------------------------
+' Main game loop
+' -----------------------------------------------------------------------------
+
+' Just stick an OGG called "music.ogg" in the sounds dir
+' PlaySound(music,musicchannel)  
+
+'SetChannelVolume SoundChannel,1
+SetChannelVolume MusicChannel,0.75
+
+While Not KeyHit(KEY_ESCAPE)
+       While JoyDown(5)
+       Wend
+
+       Cls
+       ResetCollisions
+       
+       ' -------------------------------------------------------------------------
+       ' Spawn a random spikey thing, joypad/keyboard check are for testing.
+       ' -------------------------------------------------------------------------
+               
+       If Spawntimer<=0 Or JoyDown(3) Or KeyDown(key_e) Then 
+               Local nx=Rand(0,800)
+               If Abs(player.x-nx)<200 Then nx=nx+400 ' dont spawn on top of player!
+               Local ny=Rand(0,600)
+               TEnemy.CreateEnemy (nx,ny)
+               Spawntimer=60
+       EndIf
+       
+       spawntimer:-1
+
+       ' -------------------------------------------------------------------------
+       ' Update Everything
+       ' -------------------------------------------------------------------------
+
+       UpdateEntities()
+
+       ' -------------------------------------------------------------------------
+       ' HUD/Score/whatever
+       ' -------------------------------------------------------------------------
+               
+       SetColor 255,255,255;   SetRotation 0;  SetAlpha 1
+
+       DrawText player.invincible,0,0 ' just for debug purposes
+       DrawText "Little Shooty Test by RiK (ESC to quit)",20,0
+               
+       GFont.DrawString 800,16,score,-1,0
+
+       If player.state=2 Then GFont.Drawstring 400,300,"YOU SUCK!",1,1
+
+       Flip
+Wend
+
+ShowMouse()
+
+' -----------------------------------------------------------------------------
+' Update/draw everything 
+'
+' I've only stuck in out here as I like to keep the main loop small for clarity
+' 
+' -----------------------------------------------------------------------------
+
+Function UpdateEntities(  )
+
+       MoveBG()
+       RenderBackGround(0,player.y)
+
+       SetScale 1,1
+       For Local b:TBullet =EachIn bullets
+               b.Update
+       Next
+       
+       SetScale 1,1
+       For Local e:TEnemy =EachIn enemies
+               e.Update
+       Next
+
+       For Local p:TParticle =EachIn particles
+               p.Update
+       Next
+       
+       player.update()
+
+       ' Reset everything
+       SetBlend ALPHABLEND
+       SetScale 1,1
+       SetAlpha 1
+       SetRotation 0
+
+End Function
+
+' -----------------------------------------------------------------------------
+' End
+' -----------------------------------------------------------------------------
+
diff --git a/samples/shooter/background.bmx b/samples/shooter/background.bmx
new file mode 100644 (file)
index 0000000..e97754d
--- /dev/null
@@ -0,0 +1,192 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' Background.bmx
+'
+' Module for tilemapped background layer
+'
+'===============================================================================
+
+Global bgtileset, bgwidth=256
+Global skyfade, cloud
+Global direction=1
+Global map:Int[6,1000,2]
+Global worldpos
+
+'==============================================================================
+' Init BG
+'==============================================================================
+
+Function CreateBG()
+       bgtileset=LoadAnimImage:TImage("gfx/hill_1.png",256,256,0,9, MASKEDIMAGE )      
+       skyfade=LoadAnimImage:TImage("gfx/sky32.png",32,32,0,48 )       
+       cloud = LoadImage:TImage("gfx/bigcloud.png")
+       RandomMap()
+EndFunction
+
+'==============================================================================
+' Note: 
+'==============================================================================
+
+Function RenderBackground( worldx, worldy)
+
+       Local sframe,soffset,lx
+       Local layerpos, mappos, offset
+
+       '-------------------------------
+       ' Sky
+       '-------------------------------        
+
+       SetBlend ALPHABLEND
+       SetAlpha 1
+       SetRotation 0
+       SetScale 1,1
+
+       If y_offset<0 Then y_offset=0
+       If y_offset>600 Then y_offset=600
+       
+       sframe = Int(y_offset/32) ; If sframe>24 Then sframe=24
+       soffset = y_offset Mod 32
+
+       For x = 0 To WIDTH Step 32
+               For y=0 To 18   
+                       DrawImage skyfade,x,(y*32)-soffset,sframe+y
+               Next
+       Next
+
+       '-------------------------------
+       ' Clouds
+       '-------------------------------        
+
+       SetBlend ALPHABLEND
+       SetAlpha 0.25
+       DrawImage cloud,sky_pos, 100
+       
+       '-------------------------------
+       ' Hills
+       '-------------------------------        
+       SetAlpha 1
+       ' layerpos = scaled from worldpos for parallax
+       ' map_pos = offset into Map
+       ' offset = shift for 
+                                               
+       layerpos = worldpos/8
+       mappos  = Int(layerpos/bgwidth)
+       offset  = layerpos Mod bgwidth
+               
+       For x = 0 To 5
+               DrawImage bgtileset,(x*bgwidth)-offset,380-(y_offset/12), map[5,mappos+x,0]
+       Next    
+
+       layerpos = worldpos/6
+       mappos  = Int(layerpos/bgwidth)
+       offset  = layerpos Mod bgwidth
+       
+       For x = 0 To 5
+               DrawImage bgtileset,(x*bgwidth)-offset,430-(y_offset/11), map[4,mappos+x,0]
+       Next    
+
+       layerpos = worldpos/4
+       mappos  = Int(layerpos/bgwidth)
+       offset  = layerpos Mod bgwidth
+
+       For x = 0 To 5
+               DrawImage bgtileset,(x*bgwidth)-offset,480-(y_offset/10), map[3,mappos+x,0]
+       Next    
+
+       layerpos = worldpos/2
+       mappos  = Int(layerpos/bgwidth)
+       offset  = layerpos Mod bgwidth
+
+       For x = 0 To 5
+               DrawImage bgtileset,(x*bgwidth)-offset,530-(y_offset/9), map[2,mappos+x,0]
+       Next    
+               
+       '----------------------------------
+       ' Layer 1 Hills with collisions
+       '----------------------------------
+       
+       SetAlpha 1
+               
+       mappos  = Int(worldpos/bgwidth)
+       offset  = worldpos Mod bgwidth
+       
+       For x = 0 To 5
+               DrawImage    bgtileset,(x*bgwidth)-offset,480, map[1,mappos+x,0]
+'              CollideImage bgtileset,(x*bgwidth)-offset,480, map[1,mappos+x,0],0,2
+       Next    
+       
+End Function
+
+
+'===============================================================================
+' Description:
+'
+' Quick hack to test the concept. Need to sort this out fully. 
+'
+'===============================================================================
+
+Function MoveBg()
+
+       sky_pos = sky_pos - (scroll_speed/32)
+       If sky_pos<-256 Then sky_pos=1000
+
+  worldpos=worldpos + scroll_speed
+End Function
+
+'==============================================================================
+' Random Map
+'
+' Test function only to randomise map data
+'==============================================================================
+
+Function RandomMap()
+       Local h=0, l=0,pos=0
+
+       For h=0 To 5
+       
+               pos=0
+       
+               While pos<980
+                       
+                       '--------------------------
+                       ' Hill 
+                       map(h,pos,0)=1 ' Hill ramp up   
+                       pos:+1  
+                       l=Rand(5)
+                       If h=1 Then l=Rand(10)
+                       If h=5 Then l=Rand(20)  
+                                                                       
+                       While l>0
+                               map(h,pos,0)=Rand(2,7)
+                               pos:+1
+                               l:-1
+                       Wend
+                       
+                       map(h,pos,0)=8 ' Hill ramp down
+                       pos:+1          
+                       
+                       '--------------------------
+                       ' Gap 
+                       
+                       l=Rand(3)
+                       While l>0
+                               If pos<1000 map(h,pos,0)=0
+                               pos:+1
+                               l:-1
+                       Wend
+                       
+                       
+               Wend
+
+       Next
+
+End Function
+
+
+'===============================================================================
+' END OF FILE
+'===============================================================================
diff --git a/samples/shooter/enemies.bmx b/samples/shooter/enemies.bmx
new file mode 100644 (file)
index 0000000..41e69fa
--- /dev/null
@@ -0,0 +1,78 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' enemies.bmx
+'===============================================================================
+
+Global enemies:TList=New TList
+Global num_enemies=0
+Global alien_img
+
+Type TEnemy 
+       Field link:TLink
+       Field x#,y#
+       Field xs#,ys#
+       Field ang#, rs#;
+       Field alpha#,img
+       Field expl
+       Field frame
+
+       '-------------------------------------------------------------------
+       ' Move / Draw
+       '-------------------------------------------------------------------
+
+       Method Update()
+               x:+xs ; If x>WIDTH Or x<0 Then xs:*-1
+               y:+ys ; If y>HEIGHT Or y<0 Then ys:*-1
+               frame=(frame+1)&63
+
+               'SetRotation ang ; ang:+rs;
+               SetAlpha 1
+               SetBlend ALPHABLEND
+               DrawImage img,x,y, frame/4
+               CollideImage img,x,y,frame/4,0,1
+       End Method
+       
+       Method hit()
+'              PlaySound explode, SoundChannel
+               PlaySound explode
+               TParticle.CreateExplosion(x,y)
+               TParticle.ShowBonus(x,y,1)
+'              TParticle.ShowMult(x,y,Rand(9))
+               enemies.remove(Self)
+               num_enemies:-1
+       End Method
+
+       '-------------------------------------------------------------------
+
+       Function CreateEnemy:TEnemy( x#,y# )
+               Local enemy:TEnemy=New TEnemy
+               enemy.x=x
+               enemy.y=y
+               enemy.alpha=0.1
+               enemy.ang=0.0
+               enemy.rs#=Rnd(0,4)
+               enemy.Expl=0
+               enemy.img=alien_img
+               Repeat 
+                       enemy.xs=Rnd(-6,6)
+               Until enemy.xs<>0
+
+               Repeat 
+                       enemy.ys=Rnd(-6,6)
+               Until enemy.ys<>0
+               enemies.AddLast enemy
+               num_enemies:+1
+       End Function
+       
+       Function Init()
+               SetMaskColor(255,0,255)
+               alien_img=LoadAnimImage("gfx/spikeyball.png",64,64,0,16,MASKEDIMAGE)
+       EndFunction
+
+End Type
+
+'----------------------------------------------------------------------
+' End of file
+'---------------------------------------------------------------------
\ No newline at end of file
diff --git a/samples/shooter/gfont.bmx b/samples/shooter/gfont.bmx
new file mode 100644 (file)
index 0000000..82db21d
--- /dev/null
@@ -0,0 +1,83 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'==============================================================================
+' Graphic Font
+'==============================================================================
+Type GFont
+
+       Global FontImg, f
+       Global TypeStr$
+
+       ' ---------------------------------------------------------------------------
+       ' Init() - Load Font Image
+       ' ---------------------------------------------------------------------------
+
+       Function Init()
+               FontImg = LoadAnimImage("gfx/abduction.png",32,32,0,49, MASKEDIMAGE)    
+       End Function
+
+       ' ---------------------------------------------------------------------------
+       ' DrawString(MsgX,MsgY,Message$)
+       ' ---------------------------------------------------------------------------
+
+        Function DrawString(MsgX,MsgY,Message$,centrex, centrey)
+               Local MsgCount = Len(Message$)
+               
+               SetBlend MASKBLEND
+               SetScale 1,1
+               SetAlpha 1
+               SetRotation 0
+
+               length =Len(message$)*30        
+               x=msgx
+
+               If centrex=1 Then x=msgx-(length/2)
+               If centrex=-1 Then x=msgx-length        
+                                       
+               If centrey=1
+                       y=msgy-16
+               Else
+               y=msgy
+               EndIf
+               
+               For f=0 To MsgCount-1
+                       FontChar = Asc(Lower$(Mid$(Message$,f+1,1)))
+                       imgchar= sortchar(fontchar)
+                       
+                       DrawImage FontImg,x+(f*30),MsgY,ImgChar
+               Next
+               
+       End Function
+
+       ' ---------------------------------------------------------------------------
+       ' Sortchar
+       ' ---------------------------------------------------------------------------
+
+       Function sortchar(char)
+               ' Letters
+               If char>=97 And char<=122 Then c=char-97
+       
+       ' Numbers
+               If char>=48 And char<=57 Then c=char-22
+
+               ' Special characters
+               Select Char
+                       Case 63 c = 36 
+                       Case 46 c= 37
+                       Case 44 c= 38 
+                       Case 39 c= 39
+                       Case 34 c= 40 
+                       Case 33 c= 41
+                       Case 40 c= 42 
+                       Case 41 c= 43
+                       Case 45 c= 44 
+                       Case 58 c= 45
+                       Case 59 c= 46 
+                       Case 32 c= 48
+               End Select
+
+               Return c
+       End Function
+       
+End Type
\ No newline at end of file
diff --git a/samples/shooter/gfx/Hill_1.png b/samples/shooter/gfx/Hill_1.png
new file mode 100644 (file)
index 0000000..6f723ed
Binary files /dev/null and b/samples/shooter/gfx/Hill_1.png differ
diff --git a/samples/shooter/gfx/SMOKE.png b/samples/shooter/gfx/SMOKE.png
new file mode 100644 (file)
index 0000000..7e9ab78
Binary files /dev/null and b/samples/shooter/gfx/SMOKE.png differ
diff --git a/samples/shooter/gfx/TitlePage.png b/samples/shooter/gfx/TitlePage.png
new file mode 100644 (file)
index 0000000..7e25ebc
Binary files /dev/null and b/samples/shooter/gfx/TitlePage.png differ
diff --git a/samples/shooter/gfx/abduction.png b/samples/shooter/gfx/abduction.png
new file mode 100644 (file)
index 0000000..57d11bb
Binary files /dev/null and b/samples/shooter/gfx/abduction.png differ
diff --git a/samples/shooter/gfx/alien_shot.png b/samples/shooter/gfx/alien_shot.png
new file mode 100644 (file)
index 0000000..b1f55d6
Binary files /dev/null and b/samples/shooter/gfx/alien_shot.png differ
diff --git a/samples/shooter/gfx/bigcloud.png b/samples/shooter/gfx/bigcloud.png
new file mode 100644 (file)
index 0000000..01a4339
Binary files /dev/null and b/samples/shooter/gfx/bigcloud.png differ
diff --git a/samples/shooter/gfx/bonusdecals.png b/samples/shooter/gfx/bonusdecals.png
new file mode 100644 (file)
index 0000000..003a791
Binary files /dev/null and b/samples/shooter/gfx/bonusdecals.png differ
diff --git a/samples/shooter/gfx/expl.png b/samples/shooter/gfx/expl.png
new file mode 100644 (file)
index 0000000..df5ebb5
Binary files /dev/null and b/samples/shooter/gfx/expl.png differ
diff --git a/samples/shooter/gfx/multdecals.png b/samples/shooter/gfx/multdecals.png
new file mode 100644 (file)
index 0000000..374c638
Binary files /dev/null and b/samples/shooter/gfx/multdecals.png differ
diff --git a/samples/shooter/gfx/player.png b/samples/shooter/gfx/player.png
new file mode 100644 (file)
index 0000000..076c6d2
Binary files /dev/null and b/samples/shooter/gfx/player.png differ
diff --git a/samples/shooter/gfx/player_shot.png b/samples/shooter/gfx/player_shot.png
new file mode 100644 (file)
index 0000000..fd51613
Binary files /dev/null and b/samples/shooter/gfx/player_shot.png differ
diff --git a/samples/shooter/gfx/playera.png b/samples/shooter/gfx/playera.png
new file mode 100644 (file)
index 0000000..252eac5
Binary files /dev/null and b/samples/shooter/gfx/playera.png differ
diff --git a/samples/shooter/gfx/sky32.png b/samples/shooter/gfx/sky32.png
new file mode 100644 (file)
index 0000000..8b6fa13
Binary files /dev/null and b/samples/shooter/gfx/sky32.png differ
diff --git a/samples/shooter/gfx/spark1.png b/samples/shooter/gfx/spark1.png
new file mode 100644 (file)
index 0000000..bf1b81e
Binary files /dev/null and b/samples/shooter/gfx/spark1.png differ
diff --git a/samples/shooter/gfx/spark2.png b/samples/shooter/gfx/spark2.png
new file mode 100644 (file)
index 0000000..8f57744
Binary files /dev/null and b/samples/shooter/gfx/spark2.png differ
diff --git a/samples/shooter/gfx/spark3.png b/samples/shooter/gfx/spark3.png
new file mode 100644 (file)
index 0000000..6cc5a82
Binary files /dev/null and b/samples/shooter/gfx/spark3.png differ
diff --git a/samples/shooter/gfx/spikeyball.png b/samples/shooter/gfx/spikeyball.png
new file mode 100644 (file)
index 0000000..2a3289a
Binary files /dev/null and b/samples/shooter/gfx/spikeyball.png differ
diff --git a/samples/shooter/gfx/tex_1.png b/samples/shooter/gfx/tex_1.png
new file mode 100644 (file)
index 0000000..6cc5a82
Binary files /dev/null and b/samples/shooter/gfx/tex_1.png differ
diff --git a/samples/shooter/gfx/tex_2.png b/samples/shooter/gfx/tex_2.png
new file mode 100644 (file)
index 0000000..b791e27
Binary files /dev/null and b/samples/shooter/gfx/tex_2.png differ
diff --git a/samples/shooter/globals.bmx b/samples/shooter/globals.bmx
new file mode 100644 (file)
index 0000000..8a89b11
--- /dev/null
@@ -0,0 +1,46 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' Constants
+'===============================================================================
+
+Const WIDTH=800,HEIGHT=600
+Const DEPTH=16,HERTZ=60
+
+'===============================================================================
+' Global Vars
+'===============================================================================
+
+Global spawntimer=0
+Global sky, ay
+Global bg_layer_1
+Global bp1
+Global bx1
+Global sky_pos#=800
+Global scroll_speed#=2.0
+Const  horizon = 200
+Global upd=0
+
+'===============================================================================
+' Controls
+'===============================================================================
+
+' Default key mappings for PS2 dualshock through USB adaptor
+'
+' For a full game obviously this stuff would be configurable from an options
+' screen, or at the very least read from a text file.
+'
+
+Const Joy_L = 15
+Const Joy_R = 13
+Const Joy_U = 12 
+Const Joy_D = 14
+
+Const Joy_Fire1 = 2
+Const Joy_Fire2 = 3
+Const Joy_Fire3 = 1
+Const Joy_Fire4 = 0
+
+Const Joy_Start = 9
+Const Joy_Select = 8
diff --git a/samples/shooter/init.bmx b/samples/shooter/init.bmx
new file mode 100644 (file)
index 0000000..b1dc9c8
--- /dev/null
@@ -0,0 +1,21 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' Initialisation
+'===============================================================================
+
+Function Init()
+
+       HideMouse()
+       JoyCount()
+
+       TPlayer.CreatePlayer()
+       Tbullet.image=LoadImage("gfx/player_shot.png", MASKEDIMAGE)
+
+       CreateBG()
+       TParticle.Init()
+       TEnemy.Init()
+       InitSound()
+
+EndFunction
diff --git a/samples/shooter/particles.bmx b/samples/shooter/particles.bmx
new file mode 100644 (file)
index 0000000..42a4045
--- /dev/null
@@ -0,0 +1,168 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' particles.bmx
+'===============================================================================
+
+Global particles:TList=New TList
+Global particle_density=8
+Global spark1,spark2,spark3,explosion, smoke
+Global mult_img, score_decal
+
+Type TParticle 
+       Field link:TLink
+       Field img       
+       Field life
+       Field frame
+       Field x#,y#,xs#,ys#
+       Field scale#, ss#
+       Field speed#,gravity#=0
+       Field bounce=0
+       Field ang#, rs#=0.0;
+       Field alpha#=1.0, as#=0.0
+
+       '-------------------------------------------------------------------
+       ' Move / Draw
+       '-------------------------------------------------------------------
+
+       Method Update()
+               ' Move ---------------------------------------------------------
+               x:+xs ; If x<0 Or x>WIDTH  Then kill()
+               y:+ys ; If y<0 Or y>HEIGHT Then kill()
+               ys:+gravity
+               ang:+rs;
+               alpha:+as
+               scale:+ss
+
+               ' Draw ---------------------------------------------------------
+               SetScale scale, scale
+               SetRotation ang
+               SetAlpha alpha
+               SetBlend ALPHABLEND
+               DrawImage img,x,y,frame
+       
+               life:-1
+               If life<=0 Then particles.remove(Self)
+       End Method
+       
+       Method hit()
+               expl=1
+               particles.remove(Self)
+       End Method
+       
+       Method kill()
+               particles.remove(Self)
+       End Method
+
+       '-------------------------------------------------------------------
+
+       Function Init() 
+               spark1=LoadImage("gfx/spark1.png", MASKEDIMAGE|FILTEREDIMAGE)
+               spark2=LoadImage("gfx/spark2.png", MASKEDIMAGE|FILTEREDIMAGE)
+               spark3=LoadImage("gfx/spark3.png", MASKEDIMAGE|FILTEREDIMAGE)           
+               explosion=LoadImage("gfx/expl.png", MASKEDIMAGE|FILTEREDIMAGE)
+               smoke=LoadImage("gfx/smoke.png", MASKEDIMAGE|FILTEREDIMAGE)
+               score_decal     = LoadAnimImage("gfx/bonusdecals.png",128,64,0,5, MASKEDIMAGE|FILTEREDIMAGE)                    
+               mult_img =    LoadAnimImage("gfx/multdecals.png",128,64,0,10, MASKEDIMAGE|FILTEREDIMAGE)
+       End Function
+
+       '-------------------------------------------------------------------
+
+       Function CreateExplosion(x,y)
+               For Local s = 0 To particle_density
+                       TParticle.CreateSpark(explosion,x,y, 0.5 ,0 ,6 ,0.1 , Rand(50,100) ) 
+                       TParticle.CreateSpark(spark1,   x,y, 0.5 ,0 ,7 ,0.2 , Rand(30,80) ) 
+                       TParticle.CreateSpark(spark2,   x,y, 0.25,0 ,10 ,0.3, Rand(50,100)) 
+               Next
+               TParticle.Createspark(explosion, x,y,0.5,0.1,0,0, Rand(50,100))
+       EndFunction
+
+       Function PlayerExplosion(x,y)
+               For Local s = 0 To particle_density*2
+                       TParticle.CreateSpark(explosion,x,y, 0.5 ,0 ,10 ,0.1 , Rand(150,200) ) 
+                       TParticle.CreateSpark(spark1,   x,y, 0.5 ,0 ,12 ,0.2 , Rand(130,180) ) 
+                       TParticle.CreateSpark(spark2,   x,y, 0.25,0 ,14 ,0.3, Rand(150,200)) 
+               Next
+               
+               For Local i=1 To 6
+                       TParticle.Createspark(explosion, x+Rand(-64,64),y+Rand(-64,64),Rnd(0.25,1),0.2,Rand(4),0, Rand(150,300))
+               Next 
+       EndFunction
+
+
+
+       Function CreateSpark:Tparticle(img,x#,y#,sc#,si#,sp#,gr#, lf)
+               Local particle:Tparticle=New Tparticle
+               particle.img=img
+               
+               particle.x=x
+               particle.y=y
+
+               particle.alpha=1
+               particle.as=-0.03
+               
+               particle.scale=sc
+               particle.ss=si
+               
+               particle.speed=sp
+
+               particle.ang = Rnd(360)
+               particle.xs = Sin(particle.ang)*sp
+               particle.ys = Cos(particle.ang)*sp
+                                                                               
+               particle.rs#=Rnd(0,2)
+               particle.life=lf                
+               particle.gravity = gr
+               
+               particles.AddLast particle                      
+       End Function
+
+       Function ShowBonus:Tparticle( x#,y#,frame )
+               Local particle:Tparticle=New Tparticle
+               particle.img=score_decal
+               particle.frame=frame
+               particle.x=x
+               particle.y=y
+               particle.alpha=1
+               particle.as=-0.02
+               particle.scale=0.5
+               particle.ss=0.01
+               particle.ang = 0
+               particle.xs = 0
+               particle.ys = -1
+                               
+               particle.rs#=0
+               particle.life=60
+               particle.gravity=0
+               
+               particles.AddLast particle                      
+       End Function
+
+       Function ShowMult:Tparticle( x#,y#,frame )
+               Local particle:Tparticle=New Tparticle
+               particle.img=mult_img
+               particle.frame=frame
+               particle.x=x
+               particle.y=y
+               particle.alpha=1
+               particle.as=-0.02
+               particle.scale=0.1
+               particle.ss=0.2
+               particle.ang = 0
+               particle.xs = Rnd(-4,4)
+               particle.ys = Rnd(-4,4)
+                               
+               particle.rs#=Rnd(6)
+               particle.life=100
+               particle.gravity=0
+               
+               particles.AddLast particle                      
+       End Function
+
+
+End Type
+
+'----------------------------------------------------------------------
+' End of file
+'---------------------------------------------------------------------
\ No newline at end of file
diff --git a/samples/shooter/player.bmx b/samples/shooter/player.bmx
new file mode 100644 (file)
index 0000000..b981743
--- /dev/null
@@ -0,0 +1,168 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' Player.bmx
+'===============================================================================
+
+Global score=0, oldswitch=0
+Global mx, mn, damping#
+Global player:TPlayer
+
+
+Type TPlayer 
+       Field x#,y#,xs#,ys#
+       Field rot#,alpha#,img,frame=2
+       Field primary_weapon, secondary_weapon
+       Field pshot_timer=0
+       Field shield = 0
+       Field invincible =0
+       Field state=0, lives
+       
+       '---------------------------------------
+       
+       Function CreatePlayer()
+               player=New TPlayer
+               player.x=320; xs#=0
+               player.y=240; ys#=0
+               player.img=LoadAnimImage:TImage("gfx/playera.png",80,64,0,5, MASKEDIMAGE|FILTEREDIMAGE )
+               mx=6
+               mn=-6
+               damping#=0.8
+               player.rot=0
+               player.state=1
+               player.lives=3
+               player.shield=180
+               player.invincible=0
+               player.primary_weapon=WPN_DEFLASER
+       EndFunction
+
+       '---------------------------------------
+                       
+       Method Update()
+               shield:-1
+               If state=2 Then Goto pskip
+
+               '---------------------------------------------
+               ' move
+               
+               If JoyDown(5) Then
+                       If oldswitch=0 Then
+                               direction=-direction
+                               oldswitch=1
+                       Else
+                               oldswitch=0
+                       EndIf
+               EndIf
+               
+                       
+               If KeyHit(KEY_I) Then invincible=1-invincible
+                       
+               If KeyDown(KEY_RIGHT)Or KeyDown(KEY_D) Then xs:+1
+               If KeyDown(KEY_LEFT)Or KeyDown(KEY_A) Then xs:-1        
+               If Abs(JoyX(0))>0.2 Then xs:+JoyX(0) 
+               If (xs > mx) Then xs=mx
+               If (xs < mn) Then xs=mn
+               xs:*damping# ; If Abs(pvx)<0.5 Then pvx=0
+
+               If KeyDown(KEY_UP)Or KeyDown(KEY_W) Then ys:-1 
+               If KeyDown(KEY_DOWN) Or KeyDown(KEY_S) Then ys:+1                               
+               If Abs(JoyY(0))>0.2 Then ys:+JoyY(0) 
+               
+               If ys > mx Then ys=mx
+               If ys < mn Then ys=mn
+               
+               ys:*damping# ; If Abs(pvy)<0.5 Then pvy=0
+               frame = 4-(Int(ys/1.5)+2)
+                               
+               x:+xs ; If x>=WIDTH Then x=WIDTH ; If x<=0 Then x=0
+               y:+ys ; If y>=HEIGHT Then y=HEIGHT ; If y<=0 Then y=0
+
+               '---------------------------------------------
+               ' shoot?
+
+               pshot_timer:-1
+               If (JoyDown(2) Or KeyDown(KEY_SPACE)) And pshot_timer<0 Then fire()                                                             
+                                                                                                                                                                                               
+#pskip If state=2 Then
+                       If rot<60 Then rot=rot+0.25
+                       ys=ys+0.05
+                       y=y+ys
+                       x=x+1
+                       ' img,x#,y#,sc#,si#,sp#,gr#, lf
+                       If (Int(y)&3)=1 Then TParticle.Createspark(smoke, x,y,0.25,0.02,Rand(-0.5,0.5),0, Rand(125,175) )
+
+                       If y>HEIGHT Then 
+                               StopChannel TempChannel
+                               PlaySound playerdie
+                               TParticle.PlayerExplosion(x,y)
+                               rot=0
+                               state=1
+                               y=HEIGHT/2
+                               ys=0
+                               shield=180
+                               lives=lives-1
+                       EndIf
+               EndIf   
+
+               '---------------------------------------------
+               ' Draw
+               
+               SetBlend ALPHABLEND
+               SetScale 1,1
+               SetAlpha 1
+               SetRotation rot
+               
+               If shield>0 Then SetAlpha Rnd(1)
+
+               DrawImage img,x,y,frame
+
+               '---------------------------------------------  
+               ' Collisions
+               If (shield <0) Then
+                       If CollideImage(img,x,y,frame,1,0) Then hit() ' Player/Alien Collision
+'                      If CollideImage(img,x,y,frame,2,0) Then hit() ' Player/Ground Collision
+               EndIf
+               '---------------------------------------------  
+               
+       End Method
+       
+       Method fire()
+
+               Select primary_weapon
+               
+                       Case WPN_NORMAL
+                                       TBullet.CreateBullet bull_img,x+24,y+2+(ys*2),(16+spd)*direction                
+                                       pshot_timer=5
+                                       PlaySound player_shot, SoundChannel
+                                                               
+                       Case WPN_DEFLASER
+                       
+                               For Local sp=1 To 8
+                                       TBullet.CreateBullet bull_img,x+24,y+2+(ys*2),(16+sp)*direction
+                               Next
+                               pshot_timer=5
+                               PlaySound player_shot, SoundChannel
+
+               End Select
+
+       End Method
+       
+       
+       Method hit()
+               If invincible Then Return
+               If state=1 Then 
+'                      TParticle.PlayerExplosion(x,y)
+                       TParticle.CreateExplosion(x,y)
+                       TempChannel=AllocChannel()
+                       PlaySound bombfall, TempChannel
+                       state=2
+               EndIf
+       End Method
+
+End Type
+
+
+'----------------------------------------------------------------------
+' End of file
+'---------------------------------------------------------------------
\ No newline at end of file
diff --git a/samples/shooter/playershots.bmx b/samples/shooter/playershots.bmx
new file mode 100644 (file)
index 0000000..bcb277b
--- /dev/null
@@ -0,0 +1,56 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' Player shots
+'===============================================================================
+
+Global bullets:TList=New TList
+
+Const  WPN_NORMAL=0
+Const  WPN_DEFLASER=1
+
+Type TBullet
+       Global image
+       
+       Field link:TLink
+       Field x#,y#,xs#,ys#
+       Field rot#,alpha#,img
+
+       Method Update()
+               x:+xs
+               alpha:+0.02
+               If x>WIDTH
+                       ' remove
+                       Return
+               EndIf
+               
+               For Local e:TEnemy =EachIn enemies
+                       If ( x>(e.x-16) And x<(e.x+16) And y>(e.y-16) And y<(e.y+16) ) Then 
+                               e.hit()
+                               score:+100
+                       EndIf
+               Next
+               
+               SetScale 1,1
+               If player.primary_weapon = WPN_DEFLASER Then SetScale 1,0.5
+               SetBlend ALPHABLEND
+               DrawImage img,x,y
+               
+       End Method
+
+       Function CreateBullet:TBullet( img, x#,y#, xs# )
+               Local bullet:TBullet=New TBullet
+               bullet.x=x
+               bullet.y=y
+               bullet.xs=xs
+               bullet.alpha=0.1
+               bullet.img=image
+               bullets.AddLast bullet
+       End Function
+
+End Type
+
+'===============================================================================
+'
+'===============================================================================
\ No newline at end of file
diff --git a/samples/shooter/sound.bmx b/samples/shooter/sound.bmx
new file mode 100644 (file)
index 0000000..0587115
--- /dev/null
@@ -0,0 +1,26 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'===============================================================================
+' Sound & Music
+'===============================================================================
+
+Global player_shot, playerdie
+Global bombfall
+Global explode, SoundChannel, TempChannel
+Global music, MusicChannel
+
+Function InitSound()
+       player_shot = LoadSound("sound/shot-1.wav", 0)
+       playerdie = LoadSound("sound/explosion1.wav", 0)
+       explode = LoadSound("sound/explode.wav", 0)
+       bombfall = LoadSound("sound/bombfall.wav", 0)
+       SoundChannel=0'AllocChannel()
+       
+       MusicChannel=AllocChannel()
+'      music=LoadSound("sound/music.ogg",1)
+EndFunction
+
+'===============================================================================
+'
+'===============================================================================
\ No newline at end of file
diff --git a/samples/shooter/sound/EXPLOSION1.WAV b/samples/shooter/sound/EXPLOSION1.WAV
new file mode 100644 (file)
index 0000000..dd0a1b6
Binary files /dev/null and b/samples/shooter/sound/EXPLOSION1.WAV differ
diff --git a/samples/shooter/sound/bombfall.wav b/samples/shooter/sound/bombfall.wav
new file mode 100644 (file)
index 0000000..bf302da
Binary files /dev/null and b/samples/shooter/sound/bombfall.wav differ
diff --git a/samples/shooter/sound/explode.wav b/samples/shooter/sound/explode.wav
new file mode 100644 (file)
index 0000000..0e16c9f
Binary files /dev/null and b/samples/shooter/sound/explode.wav differ
diff --git a/samples/shooter/sound/shot-1.wav b/samples/shooter/sound/shot-1.wav
new file mode 100644 (file)
index 0000000..0bea437
Binary files /dev/null and b/samples/shooter/sound/shot-1.wav differ
diff --git a/samples/shooter/titles.bmx b/samples/shooter/titles.bmx
new file mode 100644 (file)
index 0000000..00041a1
--- /dev/null
@@ -0,0 +1,52 @@
+'===============================================================================
+' Little Shooty Test Thing
+' Code & Stuff by Richard Olpin (rik@olpin.net)
+'==============================================================================
+' Titles
+'==============================================================================
+
+Function ShowTitlePage()
+       Local title, i#, a#, s#
+       Local state, quit, time
+       
+       title=LoadImage ("gfx/titlepage.png",MASKEDIMAGE|FILTEREDIMAGE)
+       a#=0.01
+       s=1.0
+       state=0
+       time=100
+
+       SetBlend ALPHABLEND
+
+       Repeat
+               Cls
+       
+               Select state
+               
+                       Case 0 ' Fade in
+                               a#:+0.01
+                               time:-1
+                               If time<0 Then state=1  
+               
+                       Case 1 ' Static, wait for quit                          
+                               
+                       Case 2 ' Fade Out
+                               a#:-0.02
+                               s:+0.2
+                               time:-1
+                               If time<0 Then state=-1
+               
+               End Select
+               
+               If JoyDown(Joy_Fire1) Or KeyHit(KEY_SPACE) Then 
+                       State=2
+                       time=100
+               EndIf
+
+               SetAlpha a#
+               SetScale s,s
+
+               DrawImage title,400,300
+               Flip            
+       Until state=-1
+
+End Function
\ No newline at end of file
diff --git a/samples/simonh/fireworks/fireworks.bmx b/samples/simonh/fireworks/fireworks.bmx
new file mode 100644 (file)
index 0000000..01532f8
--- /dev/null
@@ -0,0 +1,115 @@
+' Fireworks by simonh (si@si-design.co.uk)
+
+Strict
+
+Global width=800
+Global height=600
+
+Graphics width,height,16
+
+' Create a spark type
+Type spark
+       Field x#,y#,z#,vy#,xd#,yd#,zd#,r#,g#,b#,alpha#
+End Type
+
+' Load spark image
+Global sparki:TImage=LoadImage("spark.png")
+
+' Set no. of sparks to be created per firework
+Global no_sparks=500
+
+' Create spark list
+Global spark_list:TList=New TList
+
+' Load and set font
+Global font:TImageFont=LoadImageFont("Arial.ttf",1)
+SetImageFont font
+
+' Start main loop
+While Not KeyHit(KEY_ESCAPE)
+
+       ' If space key pressed then create new set of sparks (new firework)
+
+       If KeyHit(KEY_SPACE)
+
+               Local x#=Rand(-100,100)
+               Local y#=Rand(-100,100)
+               Local z#=200
+
+               Local r#=Rand(255)
+               Local g#=Rand(255)
+               Local b#=Rand(255)
+
+               For Local i=1 To no_sparks
+
+                       Local speed# = 0.1
+
+                       Local ang1# = Rnd!(360)
+                       Local ang2# = Rnd!(360)
+
+                       Local sp:spark=New Spark
+                       spark_list.AddLast sp
+
+                       sp.x=x#
+                       sp.y=y#
+                       sp.z=z#
+
+                       sp.xd=Cos(ang1#)*Cos(ang2#)*speed#
+                       sp.yd=Cos(ang1#)*Sin(ang2#)*speed#
+                       sp.zd=Sin(ang1#)*speed#
+       
+                       sp.r=r
+                       sp.g=g
+                       sp.b=b
+       
+                       sp.alpha=1
+       
+               Next
+
+       EndIf
+
+       ' Draw all sparks
+
+       For Local sp:spark=EachIn spark_list
+
+               ' If spark alpha is above 0 then draw it...
+
+               If sp.alpha>0
+
+                       sp.x=sp.x+sp.xd*10.0
+                       sp.y=sp.y+sp.yd*10.0
+                       sp.z=sp.z+sp.zd*10.0
+                       sp.y=sp.y+sp.vy#
+                       sp.vy=sp.vy+0.02
+
+                       ' Calculate x and y draw values based on x,y,z co-ordinates
+                       Local x#=(width/2.0)+((sp.x/sp.z)*500)
+                       Local y#=(height/2.0)+((sp.y/sp.z)*500)
+
+                       sp.alpha=sp.alpha-0.01
+
+                       SetColor sp.r#,sp.g#,sp.b#
+                       SetBlend LIGHTBLEND
+                       SetAlpha sp.alpha
+                       SetScale 20/sp.z,20/sp.z
+                       DrawImage sparki,x#,y#
+
+               '...else remove spark from spark list
+
+               Else
+
+                       spark_list.Remove sp
+
+               EndIf
+
+       Next
+
+       SetBlend SOLIDBLEND
+       SetScale 1,1
+       SetColor 255,255,255
+       DrawText "Press space to ignite firework",0,0
+
+       Flip
+       Cls
+
+Wend
diff --git a/samples/simonh/fireworks/spark.png b/samples/simonh/fireworks/spark.png
new file mode 100644 (file)
index 0000000..2493de3
Binary files /dev/null and b/samples/simonh/fireworks/spark.png differ
diff --git a/samples/simonh/snow/flake.png b/samples/simonh/snow/flake.png
new file mode 100644 (file)
index 0000000..2493de3
Binary files /dev/null and b/samples/simonh/snow/flake.png differ
diff --git a/samples/simonh/snow/snowfall.bmx b/samples/simonh/snow/snowfall.bmx
new file mode 100644 (file)
index 0000000..905e945
--- /dev/null
@@ -0,0 +1,83 @@
+' Snowfall by simonh (si@si-design.co.uk)
+
+Strict
+
+Global width=800
+Global height=600
+
+Graphics width,height,16
+
+' Load snowflake image
+Global flakei:TImage=LoadImage("flake.png",MIPMAPPEDIMAGE)
+
+' Set no. of snowflakes to be created
+Global no_flakes=1000
+
+' Create a snowflake type
+Type flake
+       Field x#,y#,size#,speed#,sway#,phase
+End Type
+
+' Create snowflake list
+Global flake_list:TList=New TList
+
+' Initialise snowflakes
+
+For Local i=1 To no_flakes
+
+       Local fl:flake=New flake
+       flake_list.AddLast fl
+
+       fl.size=Rnd!(0.01,0.1)
+       fl.speed=Rnd!(1,2)
+       fl.sway=Rnd!(1,2)
+       fl.phase=Rand(45)
+       fl.x=Rand(-10,width+10)
+       fl.y=Rand(height)-height-10
+
+Next
+
+' Main loop
+
+While Not KeyHit(KEY_ESCAPE)
+
+       ' Begin loop in which we will update values of all snowflakes and draw them
+
+       For Local wind=1 To 360 Step 5
+
+               ' Iterate through our snowflake list
+
+               For Local fl:flake=EachIn flake_list
+
+                       ' Just update the snowflake position values to try and make them move convincingly!
+                       fl.y=fl.y+fl.speed
+                       fl.x#=fl.x#+(Sin(wind+(fl.phase)))*fl.sway
+
+                       ' If snowflake has not yet reached the bottom of screen...
+                       If fl.y<height+10
+
+                               ' ...then draw snowflake.
+                               SetBlend LIGHTBLEND
+                               SetScale fl.size,fl.size
+                               DrawImage flakei,fl.x,fl.y
+
+                       '...else if snowflake has reached bottom of screen...
+                       Else
+
+                               '...reset snowflake values so it appears as new snowflake at top of screen.
+                               fl.speed=Rnd!(1,2)
+                               fl.sway=Rnd!(1,2)
+                               fl.phase=Rand(45)
+                               fl.x=Rand(-10,width+10)
+                               fl.y=-10
+
+                       EndIf
+
+               Next
+
+               Flip
+               Cls
+
+       Next
+
+Wend
diff --git a/samples/spintext/spintext.bmx b/samples/spintext/spintext.bmx
new file mode 100644 (file)
index 0000000..01feb52
--- /dev/null
@@ -0,0 +1,31 @@
+
+Graphics 640,480
+
+t$="***** Some spinny text *****"
+w=TextWidth(t)
+h=TextHeight(t)
+
+r#=0
+
+While Not KeyHit( KEY_ESCAPE )
+
+       Cls
+       
+       r:+3
+       SetOrigin 320,240
+       SetHandle w/2,h/2
+       SetTransform r,3,5
+
+       SetColor 0,0,255
+       DrawRect 0,0,w,h
+       SetColor 255,255,255
+       DrawText t,0,0
+
+       SetOrigin 0,0
+       SetHandle 0,0   
+       SetTransform 0,1,1
+       
+       Flip
+
+Wend
+       
\ No newline at end of file
diff --git a/samples/starfieldpong/starfieldpong.bmx b/samples/starfieldpong/starfieldpong.bmx
new file mode 100644 (file)
index 0000000..64d570e
--- /dev/null
@@ -0,0 +1,190 @@
+Strict
+Const WIDTH=640,HEIGHT=480,DEPTH=32
+Const Star_Count       = 1000         ' Stars Count
+Const MAX_SIZE         = 12             ' Maximum starts
+Const MAX_ROTSPD#      = 1.5            ' How much rotation goin on
+
+Global Delta_X#,Delta_Y#, Delta_Ang#=0 ,tick#=0
+
+Type TEntity
+       Field x#,y#
+       Method Update() Abstract
+EndType
+
+Type Star Extends TEntity
+       Field s#
+       Field size#
+       Field col#,alp#
+       Field rot#
+       Field tcol[3]
+       Field vtype
+
+       Method Update()
+               Local cs# , sn#
+               Local tx# , ty#
+
+               x:+ ( x-319.99999 ) / s
+               y:+ ( y-239.99999 ) / s
+
+               x=x-320
+               y=y-240
+               
+               cs = Cos(Delta_Ang)
+               sn = Sin(Delta_Ang)
+
+               tx = x
+               ty = y
+
+               x = tx * cs - ty * sn
+               y = tx * sn + ty * Cs
+
+               x=x +320
+               y=y +240
+
+               'Pitch Horiz and Verti
+               x = x + Delta_X / s
+               y = y + Delta_Y / s
+
+               If x<0 Or x>WIDTH
+                       x=Rnd(WIDTH)
+                       alp=0
+               EndIf
+               If y<0 Or y>HEIGHT
+                       y=Rnd(HEIGHT)
+                       alp=0
+               EndIf
+               If alp<1
+                       alp = alp + .05
+                       EndIf
+               SetBlend LIGHTBLEND
+               SetRotation rot
+               SetAlpha alp
+               rot=rot+5
+               SetColor tcol[0],tcol[1],tcol[2]
+               Select vtype
+                       Case 0
+                               SetHandle size*.5,.5
+                               DrawRect x,y,size,1
+                               SetHandle .5,size*.5
+                               DrawRect x,y,1,size
+                               SetHandle 0,0
+                       Case 1
+                               SetHandle size*.5,size*.5
+                               DrawRect x,y,size,size
+                               SetHandle 0,0
+               End Select
+       End Method
+
+       Function CreateStar:Star()
+               Local s:Star = New Star
+               Local r =Rand(128)
+               s.x=Rnd(640)
+               s.y=Rnd(480)
+               s.s=Rnd(150,250)
+               s.tcol=[r,r,r]
+               s.size = Rnd(1,MAX_SIZE)
+               s.vtype = Rnd(1)
+               Return s
+       EndFunction
+End Type
+
+Function UpdateEntities( list:TList )
+       Delta_X = 400*Cos(tick)
+       Delta_Y = 400*Sin(tick)
+
+       Delta_Ang = MAX_ROTSPD*Cos( tick )
+       tick=tick+.5
+       Local c:TEntity
+  For c=EachIn list
+               c.Update
+       Next
+End Function
+
+Graphics WIDTH,HEIGHT,DEPTH
+HideMouse
+
+Local StarList:TList = New TList
+Local a
+
+Local px1#=30,py1#
+Local px2#=WIDTH-30,py2#
+Local bx#=WIDTH/2, by#=HEIGHT/2
+Local bdx#=Rnd(-8,4)
+Local bdy#=3
+Local sc1,sc2
+
+
+For a= 0 To Star_Count-1
+       StarList.AddLast( star.CreateStar() )
+Next
+
+While Not KeyHit( KEY_ESCAPE )
+       Cls
+       UpdateEntities StarList
+
+  py1=MouseY()
+       If py1<40 py1=40
+       If py1>HEIGHT-40 py1=HEIGHT-40
+
+       SetBlend SOLIDBLEND
+       SetColor 255,0,0
+       SetRotation 0
+       SetHandle 5,40
+       DrawRect px1,py1,10,80
+
+       DrawRect px2,py2,10,80
+       SetHandle 0,0
+  SetColor 0,0,255
+       SetHandle 2.5,2.5
+       DrawRect bx,by,5,5
+       SetHandle 0,0
+
+
+  bx=bx+bdx
+  by=by+bdy
+  If by<3 bdy=-bdy
+  If by>HEIGHT-3 bdy=-bdy
+
+  'check players paddle
+  If bx<px1+10
+    If by>py1-40 And by<py1+40
+      bdx=-bdx*Rnd(1.1,1.2)
+      bdy=-bdy+Rnd(-1,1)
+    EndIf
+
+  EndIf
+
+  If bx>px2-10  And bx<px2+10
+    If by>py2-40 And by<py2+40
+      bdx=-bdx*Rnd(1.1,1.2)
+      bdy=-bdy+Rnd(-1,1)
+    EndIf
+  EndIf
+
+  If bx>WIDTH-3 Or bx<3
+    bdx= Rnd(-8,8)
+    bdy= Rnd(-8,8)
+    If bx>Width-3
+      sc1:+1
+    Else
+      sc2:+1
+    EndIf
+    bx=width/2
+    by=height/2
+  EndIf
+
+  If py2<by
+    If py2<HEIGHT-40
+      py2=py2+3
+    EndIf
+  EndIf
+  If py2>by
+    If py2>40
+      py2=py2-3
+    EndIf
+  EndIf
+  DrawText sc1,width/2-40,0
+  DrawText sc2,width/2+40,0
+
+       Flip
+Wend
diff --git a/samples/teapot/teapot.bmx b/samples/teapot/teapot.bmx
new file mode 100644 (file)
index 0000000..48c7b0a
--- /dev/null
@@ -0,0 +1,243 @@
+' The UTAH Teapot. See <a href="http://sjbaker.org/teapot/" target="_blank">sjbaker.org/teapot/</a> For more information
+' This Function returns an OpenGL display list.
+' BlitzMax port by Peter Scheutz 2004.12.18
+Function ogld_TeaPot(grid%)
+
+       Local x#,y#,z#
+       Local i, n
+       Local verts
+       Local teaList
+       Local rimbank
+       Local bodybank1
+       Local bodybank2
+       Local lidbank1
+       Local lidbank2          
+       Local handlebank1
+       Local handlebank2
+       Local spoutbank1
+       Local spoutbank2
+
+
+       verts=CreateBank(3*4*119)
+
+       
+       RestoreData teaPotVerts
+       For i=0 To 118
+               ReadData x#
+               ReadData y#
+               ReadData z#             
+               
+               PokeFloat verts,i*12,x
+               PokeFloat verts,i*12+4,y                
+               PokeFloat verts,i*12+8,z                
+                       
+       Next
+
+       rimbank=CreateBank(16*4*3)
+
+       bodybank1=CreateBank(16*4*3)
+       bodybank2=CreateBank(16*4*3)
+
+       lidbank1=CreateBank(16*4*3)
+       lidbank2=CreateBank(16*4*3)
+
+
+       handlebank1=CreateBank(16*4*3)
+       handlebank2=CreateBank(16*4*3)
+
+       spoutbank1=CreateBank(16*4*3)
+       spoutbank2=CreateBank(16*4*3)
+
+
+       ' rim
+       RestoreData teaPotRim
+       For n=0 To 15
+               ReadData i
+               PokeFloat rimbank,n*12,PeekFloat(verts,i*12)
+               PokeFloat rimbank,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat rimbank,n*12+8,PeekFloat(verts,i*12+8)
+       Next    
+
+       ' body
+       RestoreData teaPotBody
+       For n=0 To 15
+               ReadData i
+               PokeFloat bodybank1,n*12,PeekFloat(verts,i*12)
+               PokeFloat bodybank1,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat bodybank1,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+       For n=0 To 15
+               ReadData i
+               PokeFloat bodybank2,n*12,PeekFloat(verts,i*12)
+               PokeFloat bodybank2,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat bodybank2,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+
+       ' lid
+       RestoreData teaPotLid
+       For n=0 To 15
+               ReadData i
+               PokeFloat lidbank1,n*12,PeekFloat(verts,i*12)
+               PokeFloat lidbank1,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat lidbank1,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+       For n=0 To 15
+               ReadData i
+               PokeFloat lidbank2,n*12,PeekFloat(verts,i*12)
+               PokeFloat lidbank2,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat lidbank2,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+
+       ' handle
+       RestoreData teaPotHandle
+       For n=0 To 15
+               ReadData i
+               PokeFloat handlebank1,n*12,PeekFloat(verts,i*12)
+               PokeFloat handlebank1,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat handlebank1,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+       For n=0 To 15
+               ReadData i
+               PokeFloat handlebank2,n*12,PeekFloat(verts,i*12)
+               PokeFloat handlebank2,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat handlebank2,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+
+       ' Spout
+       RestoreData teaPotSpout
+       For n=0 To 15
+               ReadData i
+               PokeFloat spoutbank1,n*12,PeekFloat(verts,i*12)
+               PokeFloat spoutbank1,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat spoutbank1,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+       For n=0 To 15
+               ReadData i
+               PokeFloat spoutbank2,n*12,PeekFloat(verts,i*12)
+               PokeFloat spoutbank2,n*12+4,PeekFloat(verts,i*12+4)
+               PokeFloat spoutbank2,n*12+8,PeekFloat(verts,i*12+8)
+       Next
+
+
+
+    teaList = glGenLists(1)
+    glNewList teaList, GL_COMPILE
+    glPushMatrix
+
+    glRotatef 270, 1, 0, 0
+
+       glEnable GL_MAP2_VERTEX_3
+       glMapGrid2f grid, 0, 1, grid, 0, 1
+
+
+
+       For i=0 To 3
+
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(rimbank))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(bodybank1))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(bodybank2))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(lidbank1))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(lidbank2))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+
+           glRotatef 90, 0, 0, 1
+
+
+       Next 
+
+
+       For i=0 To 1
+
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(handlebank1))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(handlebank2))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(spoutbank1))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+       
+               glMap2f GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, Float Ptr( BankBuf(spoutbank2))
+               glEvalMesh2 GL_FILL, 0, grid, 0, grid
+
+               glScalef 1,-1,1 
+
+
+       Next 
+
+
+    glDisable GL_MAP2_VERTEX_3
+    glPopMatrix
+    glEndList
+
+       Return teaList
+
+End Function
+
+
+#teaPotRim
+DefData 102, 103, 104, 105,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15
+#teaPotBody
+DefData 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27 
+DefData 24,  25,  26,  27,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40 
+#teaPotLid
+DefData 96,  96,  96,  96,  97,  98,  99, 100, 101, 101, 101, 101,   0,   1,   2,   3 
+DefData 0,   1,   2,   3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 
+#teaPotHandle
+DefData 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56 
+DefData 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  28,  65,  66,  67 
+#teaPotSpout
+DefData 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83 
+DefData 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95 
+
+
+#teaPotVerts
+DefData  0.2000, 0.0000, 2.70000 , 0.2000, -0.1120, 2.70000 , 0.1120, -0.2000, 2.70000 
+DefData 0.0000, -0.2000, 2.70000 , 1.3375, 0.0000, 2.53125 , 1.3375, -0.7490, 2.53125 
+DefData 0.7490, -1.3375, 2.53125 , 0.0000, -1.3375, 2.53125 , 1.4375, 0.0000, 2.53125 
+DefData 1.4375, -0.8050, 2.53125 , 0.8050, -1.4375, 2.53125 , 0.0000, -1.4375, 2.53125 
+DefData 1.5000, 0.0000, 2.40000 , 1.5000, -0.8400, 2.40000 , 0.8400, -1.5000, 2.40000 
+DefData 0.0000, -1.5000, 2.40000 , 1.7500, 0.0000, 1.87500 , 1.7500, -0.9800, 1.87500 
+DefData 0.9800, -1.7500, 1.87500 , 0.0000, -1.7500, 1.87500 , 2.0000, 0.0000, 1.35000 
+DefData 2.0000, -1.1200, 1.35000 , 1.1200, -2.0000, 1.35000 , 0.0000, -2.0000, 1.35000 
+DefData 2.0000, 0.0000, 0.90000 , 2.0000, -1.1200, 0.90000 , 1.1200, -2.0000, 0.90000 
+DefData 0.0000, -2.0000, 0.90000 , -2.0000, 0.0000, 0.90000 , 2.0000, 0.0000, 0.45000 
+DefData 2.0000, -1.1200, 0.45000 , 1.1200, -2.0000, 0.45000 , 0.0000, -2.0000, 0.45000 
+DefData 1.5000, 0.0000, 0.22500 , 1.5000, -0.8400, 0.22500 , 0.8400, -1.5000, 0.22500 
+DefData 0.0000, -1.5000, 0.22500 , 1.5000, 0.0000, 0.15000 , 1.5000, -0.8400, 0.15000 
+DefData 0.8400, -1.5000, 0.15000 , 0.0000, -1.5000, 0.15000 , -1.6000, 0.0000, 2.02500 
+DefData -1.6000, -0.3000, 2.02500 , -1.5000, -0.3000, 2.25000 , -1.5000, 0.0000, 2.25000 
+DefData -2.3000, 0.0000, 2.02500 , -2.3000, -0.3000, 2.02500 , -2.5000, -0.3000, 2.25000 
+DefData -2.5000, 0.0000, 2.25000 , -2.7000, 0.0000, 2.02500 , -2.7000, -0.3000, 2.02500 
+DefData -3.0000, -0.3000, 2.25000 , -3.0000, 0.0000, 2.25000 , -2.7000, 0.0000, 1.80000 
+DefData -2.7000, -0.3000, 1.80000 , -3.0000, -0.3000, 1.80000 , -3.0000, 0.0000, 1.80000 
+DefData -2.7000, 0.0000, 1.57500 , -2.7000, -0.3000, 1.57500 , -3.0000, -0.3000, 1.35000 
+DefData -3.0000, 0.0000, 1.35000 , -2.5000, 0.0000, 1.12500 , -2.5000, -0.3000, 1.12500 
+DefData -2.6500, -0.3000, 0.93750 , -2.6500, 0.0000, 0.93750 , -2.0000, -0.3000, 0.90000 
+DefData -1.9000, -0.3000, 0.60000 , -1.9000, 0.0000, 0.60000 , 1.7000, 0.0000, 1.42500 
+DefData 1.7000, -0.6600, 1.42500 , 1.7000, -0.6600, 0.60000 , 1.7000, 0.0000, 0.60000 
+DefData 2.6000, 0.0000, 1.42500 , 2.6000, -0.6600, 1.42500 , 3.1000, -0.6600, 0.82500 
+DefData 3.1000, 0.0000, 0.82500 , 2.3000, 0.0000, 2.10000 , 2.3000, -0.2500, 2.10000 
+DefData 2.4000, -0.2500, 2.02500 , 2.4000, 0.0000, 2.02500 , 2.7000, 0.0000, 2.40000 
+DefData 2.7000, -0.2500, 2.40000 , 3.3000, -0.2500, 2.40000 , 3.3000, 0.0000, 2.40000 
+DefData 2.8000, 0.0000, 2.47500 , 2.8000, -0.2500, 2.47500 , 3.5250, -0.2500, 2.49375 
+DefData 3.5250, 0.0000, 2.49375 , 2.9000, 0.0000, 2.47500 , 2.9000, -0.1500, 2.47500 
+DefData 3.4500, -0.1500, 2.51250 , 3.4500, 0.0000, 2.51250 , 2.8000, 0.0000, 2.40000 
+DefData 2.8000, -0.1500, 2.40000 , 3.2000, -0.1500, 2.40000 , 3.2000, 0.0000, 2.40000 
+DefData 0.0000, 0.0000, 3.15000 , 0.8000, 0.0000, 3.15000 , 0.8000, -0.4500, 3.15000 
+DefData 0.4500, -0.8000, 3.15000 , 0.0000, -0.8000, 3.15000 , 0.0000, 0.0000, 2.85000 
+DefData 1.4000, 0.0000, 2.40000 , 1.4000, -0.7840, 2.40000 , 0.7840, -1.4000, 2.40000 
+DefData 0.0000, -1.4000, 2.40000 , 0.4000, 0.0000, 2.55000 , 0.4000, -0.2240, 2.55000 
+DefData 0.2240, -0.4000, 2.55000 , 0.0000, -0.4000, 2.55000 , 1.3000, 0.0000, 2.55000 
+DefData 1.3000, -0.7280, 2.55000 , 0.7280, -1.3000, 2.55000 , 0.0000, -1.3000, 2.55000 
+DefData 1.3000, 0.0000, 2.40000 , 1.3000, -0.7280, 2.40000 , 0.7280, -1.3000, 2.40000 
+DefData 0.0000, -1.3000, 2.40000 , 0.0000, 0.0000, 0.00000 
diff --git a/samples/teapot/teapot_test.bmx b/samples/teapot/teapot_test.bmx
new file mode 100644 (file)
index 0000000..a82cb04
--- /dev/null
@@ -0,0 +1,142 @@
+
+' Test program for the UTAH Teapot. 
+' BlitzMax versio by Peter Scheutz 2004.12.18
+
+Strict
+
+Import "teapot.bmx"
+
+Type ogld_color4f
+       Field r#,g#,b#,a#
+End Type
+
+Type ogld_pos4f
+       Field x#,y#,z#,w#
+End Type
+
+
+Local teapot
+Local z#=-4
+Local xrot#=0
+Local yrot#=0
+
+
+GLGraphics 800,600
+
+       glClearColor(0.2, 0.0, 0.4, 0.0)
+       glEnable(GL_DEPTH_TEST)
+       
+       glEnable GL_AUTO_NORMAL
+       glEnable GL_NORMALIZE
+
+       teapot= ogld_TeaPot(16)
+
+       ResizeViewport 800,600
+
+       initlights 
+
+       gldisable(GL_CULL_FACE)
+       
+       
+
+While Not KeyHit(Key_Escape)
+
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+       
+       glMatrixMode GL_MODELVIEW
+       glLoadIdentity
+
+       glTranslatef 0,0,-8
+       glRotatef yrot,1,0,0
+       glRotatef xrot,0,1,0
+
+
+       glTranslatef 0.0,-1.0,0.0       
+       glCallList teapot
+
+       Flip
+       
+       xrot = xrot +1
+       yrot = yrot +.1
+
+Wend
+
+Function ResizeViewport(w,h)
+
+       Local aspect#
+
+
+       If w = 0 Then h = 1
+
+       glViewport 0,0,w,h
+
+       glMatrixMode GL_PROJECTION
+       glLoadIdentity
+       aspect#=Float(w)/Float(h)
+       
+
+       gluPerspective 45.0,aspect,1.0,100.0
+       glMatrixMode GL_MODELVIEW    
+
+
+End Function
+
+Function initlights()
+
+       Local ambient:ogld_color4f = New ogld_color4f
+       Local position:ogld_pos4f = New ogld_pos4f
+
+       Local mat_ambient:ogld_color4f = New ogld_color4f
+       Local mat_diffuse:ogld_color4f = New ogld_color4f
+       Local mat_specular:ogld_color4f = New ogld_color4f
+       Local mat_shininess:ogld_color4f = New ogld_color4f     
+       
+
+       
+       ambient.r=0.2
+       ambient.g=0.2
+       ambient.b=0.2
+       ambient.a=1     
+
+       position.x=-2
+       position.y=5
+       position.z=0
+       position.w=1            
+
+       mat_ambient.r=1
+       mat_ambient.g=0
+       mat_ambient.b=0
+       mat_diffuse.a=1
+
+       mat_diffuse.r=1
+       mat_diffuse.g=0
+       mat_diffuse.b=0
+       mat_diffuse.a=1
+
+
+
+       mat_specular.r=1
+       mat_specular.g=1
+       mat_specular.b=1
+       mat_specular.a=1
+
+
+       mat_shininess.r=50.0
+       mat_shininess.g=50.0
+       mat_shininess.b=50.0
+       mat_shininess.a=0
+
+
+       glEnable(GL_LIGHTING);
+       glEnable(GL_LIGHT0);
+
+       glLightfv GL_LIGHT0, GL_AMBIENT, Varptr(ambient.r)
+       glLightfv GL_LIGHT0, GL_POSITION, Varptr(position.x)
+
+
+       glMaterialfv GL_FRONT, GL_DIFFUSE, Varptr(mat_diffuse.r)
+       glMaterialfv GL_FRONT, GL_AMBIENT, Varptr(mat_ambient.r)
+       glMaterialfv GL_FRONT, GL_SPECULAR, Varptr(mat_specular.r)
+       glMaterialfv GL_FRONT, GL_SHININESS, Varptr(mat_shininess.r)
+
+End Function
\ No newline at end of file
diff --git a/samples/tempest/Readme.txt b/samples/tempest/Readme.txt
new file mode 100644 (file)
index 0000000..3c3035d
--- /dev/null
@@ -0,0 +1,52 @@
+Tempest 1.5
+---------------------------------------------------------------------------
+Get latest version here:  http:\\www.incitti.com\Blitz\
+
+
+History:
+---------------------------------------------------------------------------
+Version 1.5 - July 18
+   added 16 more tubes
+   tweaked the difficulty and enemy release rates
+   changed many of the scaling calcs to TFormSZ()
+
+Version 1.1 - July 7
+   fixed egg that were hatching to act 7 (non-existent case 
+   - they disappeared)
+   changed fuseballs - only kill when off the edge  w>1 or w<7
+   added Tempest Tubes boards
+
+Version 1.0 - June 20, 2005
+   Completed by Mark Incitti (Mark1nc)
+
+Version 0.1 - 
+   Started by David Bird (Birdie) - BlitzMax 1.10 Samples 
+
+
+
+
+Instructions:
+------------------------------------------------------------------------------
+Run Tempest.exe
+Shoot everything.
+
+
+Controls:
+------------------------------------------------------------------------------
+CTRL - Fire!
+SPACE - Superzapper
+L/R - Move
+ESC - Quit
+T - select tube set  (3 sets of 16 tubes)
+
+
+
+Building using BMax:
+------------------------------------------------------------------------------
+Run boardgen.bmx first - it creates the file boarddata.bmx 
+which contains the tube co-ords.
+This file will be included into Tempest.bmx
+Compile Tempest.bmx
+Feel free to modify and tweak - please let me know of any
+cool changes.
+
diff --git a/samples/tempest/boarddata.bmx b/samples/tempest/boarddata.bmx
new file mode 100644 (file)
index 0000000..1732ad1
--- /dev/null
@@ -0,0 +1,97 @@
+' Continuous, CenterY, YOFFSET, x1,y1,...x16,y16  - created by boardgen
+'Level 1 - circle
+DefData 1,400,-80,200,0,184,76,141,141,76,184,0,200,-76,184,-141,141,-184,76,-200,0,-184,-76,-141,-141,-76,-184,0,-200,76,-184,141,-141,184,-76
+'Level 2 - square
+DefData 1,400,-80,-200,200,-200,100,-200,0,-200,-100,-200,-200,-100,-200,0,-200,100,-200,200,-200,200,-100,200,0,200,100,200,200,100,200,0,200,-100,200
+'Level 3 - plus
+DefData 1,400,-80,-100,100,-200,100,-200,0,-200,-100,-100,-100,-100,-200,0,-200,100,-200,100,-100,200,-100,200,0,200,100,100,100,100,200,0,200,-100,200
+'Level 4 - binoculars
+DefData 1,380,-75,-40,105,-120,150,-220,120,-260,60,-260,-30,-220,-90,-120,-120,-40,-75,40,-75,120,-120,220,-90,260,-30,260,60,220,120,120,150,40,105
+'Level 5 - cross
+DefData 1,415,-90,-30,210,-60,120,-120,60,-210,30,-210,-30,-120,-60,-60,-120,-30,-210,30,-210,60,-120,120,-60,210,-30,210,30,120,60,60,120,30,210
+'Level 6 - triangle
+DefData 1,390,-40,-119,168,-175,168,-140,84,-105,0,-70,-84,-35,-168,0,-252,35,-168,70,-84,105,0,140,84,175,168,119,168,56,168,0,168,-56,168
+'Level 7 - clover
+DefData 1,310,-10,-179,179,-200,50,-100,0,-200,-50,-179,-179,-50,-200,0,-100,50,-200,179,-179,200,-50,100,0,200,50,179,179,50,200,0,100,-50,200
+'Level 8 - Vee
+DefData 0,240,90,240,-220,210,-165,180,-110,150,-55,120,0,90,55,60,110,30,165,-30,165,-60,110,-90,55,-120,0,-150,-55,-180,-110,-210,-165,-240,-220
+'Level 9 - steps
+DefData 0,200,100,280,-108,280,-36,200,-36,200,36,120,36,120,108,40,108,40,180,-40,180,-40,108,-120,108,-120,36,-200,36,-200,-36,-280,-36,-280,-108
+'Level 10 - U
+DefData 0,500,-200,210,-175,210,-105,210,-35,210,35,204,105,165,175,105,227,30,245,-30,245,-105,227,-165,175,-204,105,-210,35,-210,-35,-210,-105,-210,-175
+'Level 11 - horiz line
+DefData 0,230,70,300,160,260,160,220,160,180,160,140,160,100,160,60,160,20,160,-20,160,-60,160,-100,160,-140,160,-180,160,-220,160,-260,160,-300,160
+'Level 12 - heart
+DefData 1,540,-210,60,-180,150,-170,180,-60,180,60,150,150,90,210,0,240,-90,210,-150,150,-180,60,-180,-60,-150,-170,-60,-180,-15,-90,0,30,15,-90
+'Level 13 - star
+DefData 1,415,-95,-120,129,-200,100,-160,0,-200,-100,-120,-129,-80,-220,0,-170,80,-220,120,-129,200,-100,160,0,200,100,120,129,80,220,0,170,-80,220
+'Level 14 - W
+DefData 0,140,120,280,-105,245,-35,234,52,213,129,164,181,94,181,52,140,21,70,-21,70,-52,140,-94,181,-164,181,-213,129,-234,52,-245,-35,-280,-105
+'Level 15 - broken V
+DefData 0,240,75,280,-240,262,-162,245,-90,227,-6,140,-20,97,45,73,120,38,165,-35,150,-87,195,-129,120,-157,60,-175,-30,-192,-90,-227,-150,-280,-210
+'Level 16 - infinity
+DefData 1,310,0,0,0,48,-110,144,-165,240,-110,288,0,240,110,144,165,48,110,0,0,-48,-110,-144,-165,-240,-110,-288,0,-240,110,-144,165,-48,110
+'Level 17 - Tubes 1 - octagon
+DefData 1,400,-80,-120,120,-180,80,-180,0,-180,-80,-120,-120,-60,-160,0,-160,60,-160,120,-120,180,-80,180,0,180,80,120,120,60,160,0,160,-60,160
+'Level 18 - Tubes 2 - tear
+DefData 1,390,-40,-122,150,-157,90,-157,0,-122,-60,-70,-120,-35,-180,0,-240,35,-180,70,-120,122,-60,157,0,157,90,122,150,56,180,0,180,-56,180
+'Level 19 - Tubes 3 - false closed V
+DefData 0,400,0,0,-210,75,-210,150,-175,225,-125,225,-50,150,-25,95,45,50,110,-50,110,-95,45,-150,-25,-225,-50,-225,-125,-150,-175,-75,-210,0,-210
+'Level 20 - Tubes 4 - bowtie
+DefData 1,300,0,-150,75,-250,150,-250,75,-250,-75,-250,-150,-150,-75,-50,-50,50,-50,150,-75,250,-150,250,-75,250,75,250,150,150,75,50,50,-50,50
+'Level 21 - Tubes 5 - vert bent line
+DefData 0,280,0,210,-210,210,-180,210,-150,210,-120,210,-90,195,-60,180,-30,150,0,120,30,105,60,90,90,90,120,90,150,90,180,90,210,90,240
+'Level 22 - Tubes 6 - thin rectangle
+DefData 1,300,0,-30,150,-30,90,-30,30,-30,-30,-30,-90,-30,-150,-30,-210,30,-210,30,-150,30,-90,30,-30,30,30,30,90,30,150,30,210,-30,210
+'Level 23 - Tubes 7 - spiral
+DefData 0,300,0,-210,0,-140,-70,-70,-140,0,-210,70,-140,140,-70,210,0,140,70,70,140,0,210,-70,140,-140,70,-70,0,0,-70,70,0,0,70
+'Level 24 - Tubes 8 - ^U^
+DefData 0,100,90,240,-30,180,-60,120,-60,60,-30,30,30,30,90,30,150,30,210,-30,210,-30,150,-30,90,-30,30,-60,-30,-120,-60,-180,-60,-240,-30
+'Level 25 - Tubes 9 - half spade
+DefData 0,350,0,30,-270,30,-225,60,-180,120,-135,180,-90,210,-45,240,0,270,45,240,112,180,180,120,180,60,112,30,45,30,90,30,135,30,180
+'Level 26 - Tubes 10 - diagonal line
+DefData 0,250,90,300,-200,260,-175,220,-150,180,-125,140,-100,100,-75,60,-50,20,-25,-20,0,-60,25,-100,50,-140,75,-180,100,-220,125,-260,150,-300,175
+'Level 27 - Tubes 11 - jagged horz line
+DefData 0,200,200,280,0,240,25,200,0,160,25,120,0,80,25,40,0,0,25,0,-25,-40,0,-80,-25,-120,0,-160,-25,-200,0,-240,-25,-280,0
+'Level 28 - Tubes 12 - star/cross
+DefData 1,400,-80,-100,100,-200,100,-150,0,-200,-100,-100,-100,-100,-200,0,-150,100,-200,100,-100,200,-100,150,0,200,100,100,100,100,200,0,150,-100,200
+'Level 29 - Tubes 13 - claw
+DefData 1,400,-100,200,-35,150,-140,225,-70,300,0,200,70,100,140,0,210,-100,140,-200,70,-300,0,-225,-70,-150,-140,-200,-35,-100,0,0,35,100,0
+'Level 30 - Tubes 14 - ^-^
+DefData 0,200,150,267,-10,227,-37,187,-37,148,-12,120,25,100,75,60,75,20,75,-20,75,-60,75,-100,75,-120,25,-148,-12,-187,-37,-227,-37,-267,-10
+'Level 31 - Tubes 15 - bent steps
+DefData 0,200,80,245,-150,210,-50,280,0,210,50,210,150,140,100,70,200,35,100,-35,100,-70,200,-140,100,-210,150,-210,50,-280,0,-210,-50,-245,-150
+'Level 32 - Tubes 16 - triple infinity
+DefData 1,310,0,35,105,105,0,175,-105,280,-35,280,35,175,105,105,0,35,-105,-35,-105,-105,0,-175,105,-280,35,-280,-35,-175,-105,-105,0,-35,105
+'Level 33 - rainbow
+DefData 0,480,-80,-199,-23,-191,-69,-176,-113,-154,-152,-126,-185,-94,-211,-58,-229,-19,-238,19,-238,58,-229,94,-211,126,-185,154,-152,176,-113,191,-69,199,-23
+'Level 34 - pointy square
+DefData 1,400,-80,-200,200,-170,100,-130,0,-170,-100,-200,-200,-100,-170,0,-130,100,-170,200,-200,170,-100,130,0,170,100,200,200,100,170,0,130,-100,170
+'Level 35 - 3 leaf clover
+DefData 1,375,0,0,0,170,0,260,66,190,144,75,118,0,0,-85,-128,-80,-228,0,-270,80,-228,85,-128,0,0,-75,118,-190,144,-260,66,-170,0
+'Level 36 - lips
+DefData 1,400,-80,290,0,244,76,171,141,86,164,0,160,-86,164,-171,141,-244,76,-290,0,-244,-76,-171,-141,-76,-154,0,-100,76,-154,171,-141,244,-76
+'Level 37 - /\/
+DefData 0,310,0,280,-60,280,21,270,108,240,170,170,198,100,173,60,117,20,41,-20,-41,-60,-117,-100,-173,-170,-198,-240,-170,-270,-108,-280,-21,-280,60
+'Level 38 - cat
+DefData 1,400,-80,0,-100,66,-124,131,-111,204,-186,220,-60,214,46,161,121,86,174,0,180,-86,174,-161,121,-214,46,-220,-60,-204,-186,-131,-111,-66,-124
+'Level 39 - rocket
+DefData 1,390,-40,-119,168,-175,108,-120,64,-65,0,-30,-74,-15,-158,0,-242,15,-158,30,-74,65,0,110,64,175,108,119,168,56,128,0,168,-56,128
+'Level 40 - pontiac
+DefData 1,370,-50,160,-150,250,-190,200,-110,150,-30,100,50,50,130,0,210,-50,130,-100,50,-150,-30,-200,-110,-250,-190,-160,-150,-75,-110,0,-70,75,-110
+'Level 41 - Ev3
+DefData 0,220,40,170,-188,270,-136,230,-56,270,36,190,46,190,148,100,148,40,220,-40,220,-100,148,-190,148,-190,56,-270,36,-230,-56,-270,-136,-170,-188
+'Level 42 - \O/
+DefData 0,270,30,300,130,200,160,100,160,0,140,-100,90,-150,0,-130,-100,-50,-170,50,-170,130,-100,150,0,100,90,0,140,-100,160,-200,160,-300,130
+'Level 43 - yakhorns
+DefData 0,200,80,120,-210,200,-185,240,-100,200,-25,120,0,90,65,60,130,30,195,-30,195,-60,130,-90,65,-120,0,-200,-25,-240,-100,-200,-185,-120,-210
+'Level 44 - asteroid
+DefData 1,300,40,-150,90,-220,30,-220,-90,-140,-90,-60,-90,-100,-200,0,-200,100,-200,160,-140,230,-70,100,-30,160,20,220,70,130,170,70,100,-70,160
+'Level 45 - broken house
+DefData 0,140,90,70,-138,150,-116,200,-46,200,36,200,116,230,228,120,178,40,210,-40,210,-120,178,-230,228,-200,116,-200,36,-200,-46,-150,-116,-70,-138
+'Level 46 - overlap star
+DefData 1,300,0,-80,80,-100,10,-200,0,-100,-10,-80,-80,-10,-100,0,-200,10,-100,80,-80,100,-10,200,0,100,10,80,80,10,100,0,200,-10,100
+'Level 47 - pentagon
+DefData 1,440,-130,160,-80,250,-20,220,60,190,140,160,220,80,220,0,220,-80,220,-160,220,-190,140,-220,60,-250,-20,-160,-80,-75,-140,0,-190,75,-140
+'Level 48 - skull
+DefData 1,400,-80,180,40,124,86,111,151,66,204,0,220,-66,204,-111,151,-124,86,-180,40,-194,-46,-161,-131,-86,-184,0,-200,86,-184,161,-131,194,-46
diff --git a/samples/tempest/boardgen.bmx b/samples/tempest/boardgen.bmx
new file mode 100644 (file)
index 0000000..738a067
--- /dev/null
@@ -0,0 +1,495 @@
+Strict
+
+' this generates the web coordinates for tempest
+
+Local fh = WriteFile("boarddata.bmx")
+Local a#
+
+WriteLine fh,"' Continuous, CenterY, YOFFSET, x1,y1,...x16,y16  - created by boardgen"
+
+For Local b = 1 To 48
+Select b
+Case 1 'circle (level 1)
+
+       WriteLine fh,"'Level 1 - circle"
+       Local s$ = "DefData "+True+",400"+",-80,"
+       
+       For a#=0 Until  16 '360 Step 22.5 '30
+               s$ = s$ + Int(Cos(a*22.5)*200) +","+ Int(Sin(a*22.5)*200)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 2 ' square (level 2)
+       Local stepsx#[] = [2.0,2.0,2.0,2.0,2.0,1.0,0.0,-1.0,-2.0,-2.0,-2.0,-2.0,-2.0,-1.0,0.0,1.0]
+       Local stepsy#[] = [2.0,1.0,0.0,-1.0,-2.0,-2.0,-2.0,-2.0,-2.0,-1.0,0.0,1.0,2.0,2.0,2.0,2.0]
+
+       WriteLine fh,"'Level 2 - square"
+       Local s$ = "DefData "+True+",400"+",-80,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*100) +","+ Int(stepsy[a]*100)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 3 ' plus (level 3)
+       Local stepsx#[] = [1.0,2.0,2.0,2.0,1.0,1.0,0.0,-1.0,-1.0,-2.0,-2.0,-2.0,-1.0,-1.0,0.0,1.0]
+       Local stepsy#[] = [1.0,1.0,0.0,-1.0,-1.0,-2.0,-2.0,-2.0,-1.0,-1.0,0.0,1.0,1.0,2.0,2.0,2.0]
+
+       WriteLine fh,"'Level 3 - plus"
+       Local s$ = "DefData "+True+",400"+",-80,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*100) +","+ Int(stepsy[a]*100)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 4 'binoculars - level 4
+       Local stepsx#[] = [ 1.0, 3.0, 5.5, 6.5, 6.5, 5.5, 3.0, 1.0,-1.0,-3.0,-5.5,-6.5,-6.5,-5.5,-3.0,-1.0]
+       Local stepsy#[] = [-3.5,-5.0,-4.0,-2.0, 1.0, 3.0, 4.0, 2.5, 2.5, 4.0, 3.0, 1.0,-2.0,-4.0,-5.0,-3.5]
+
+       WriteLine fh,"'Level 4 - binoculars"
+       Local s$ = "DefData "+True+",380"+",-75,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*40) +","+ Int(-stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 5 ' cross level 5
+       Local stepsx#[] = [ 1.0, 2.0, 4.0, 7.0, 7.0, 4.0, 2.0, 1.0,-1.0,-2.0,-4.0,-7.0,-7.0,-4.0,-2.0,-1.0]
+       Local stepsy#[] = [-7.0,-4.0,-2.0,-1.0, 1.0, 2.0, 4.0, 7.0, 7.0, 4.0, 2.0, 1.0,-1.0,-2.0,-4.0,-7.0]
+
+       WriteLine fh,"'Level 5 - cross"
+       Local s$ = "DefData "+True+",415"+",-90,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*30) +","+ Int(-stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 6 ' triangle level 6
+       Local stepsx#[] = [ 3.4, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-4.0,-5.0,-3.4,-1.6, 0.0, 1.6]
+       Local stepsy#[] = [ 6.0, 6.0, 3.0, 0.0,-3.0,-6.0,-9.0,-6.0,-3.0, 0.0, 3.0, 6.0, 6.0, 6.0, 6.0, 6.0]
+
+       WriteLine fh,"'Level 6 - triangle"
+       Local s$ = "DefData "+True+",390"+",-40,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*35) +","+ Int(stepsy[a]*28)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 7 'clover (level 7)
+       Local stepsx#[] = [1.8, 2.0, 1.0, 2.0, 1.8, 0.5, 0.0,-0.5,-1.8,-2.0,-1.0,-2.0,-1.8,-0.5, 0.0, 0.5]
+       Local stepsy#[] = [1.8, 0.5, 0.0,-0.5,-1.8,-2.0,-1.0,-2.0,-1.8,-0.5, 0.0, 0.5, 1.8, 2.0, 1.0, 2.0]
+
+       WriteLine fh,"'Level 7 - clover"
+       Local s$ = "DefData "+True+",310"+",-10,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*100) +","+ Int(stepsy[a]*100)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 8 'V (level 8)
+       Local stepsx#[] = [ 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0,-1.0,-2.0,-3.0,-4.0,-5.0,-6.0,-7.0,-8.0]
+       Local stepsy#[] = [ 4.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-3.0,-2.0,-1.0, 0.0, 1.0, 2.0, 3.0, 4.0]
+
+       WriteLine fh,"'Level 8 - Vee"
+       Local s$ = "DefData "+False+",240"+",90,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*30) +","+ Int(-stepsy[a]*55)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+\vCase 9 'steps (level 9)
+       Local stepsx#[] = [ 7.0, 7.0, 5.0, 5.0, 3.0, 3.0, 1.0, 1.0,-1.0,-1.0,-3.0,-3.0,-5.0,-5.0,-7.0,-7.0]
+       Local stepsy#[] = [-3.0,-1.0,-1.0, 1.0, 1.0, 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 1.0, 1.0,-1.0,-1.0,-3.0]
+
+       WriteLine fh,"'Level 9 - steps"
+       Local s$ = "DefData "+False+",200"+",100,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*40) +","+ Int(stepsy[a]*36)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 10 'U (level 10)
+       Local stepsx#[] = [ 7.0, 7.0, 7.0, 7.0, 6.8, 5.5, 3.5, 1.0,-1.0,-3.5,-5.5,-6.8,-7.0,-7.0,-7.0,-7.0]
+       Local stepsy#[] = [-5.0,-3.0,-1.0, 1.0, 3.0, 5.0, 6.5, 7.0, 7.0, 6.5, 5.0, 3.0, 1.0,-1.0,-3.0,-5.0]
+
+       WriteLine fh,"'Level 10 - U"
+       Local s$ = "DefData "+False+",500"+",-200,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*30) +","+ Int(stepsy[a]*35)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 11 'line (level 11)
+       Local x# = -7.5
+
+       WriteLine fh,"'Level 11 - horiz line"
+       Local s$ = "DefData "+False+",230"+",70,"
+       For a#=0 Until 16
+               s$ = s$ + Int(-x*40) +","+"160"
+               x:+1.0
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 12 'heart (level 12)
+       Local stepsx#[] = [2.0, 5.0, 6.0, 6.0, 5.0, 3.0, 0.0,-3.0,-5.0,-6.0,-6.0,-5.0,-2.0,-0.5, 0.0, 0.5]
+       Local stepsy#[] = [6.0, 5.7, 2.0,-2.0,-5.0,-7.0,-8.0,-7.0,-5.0,-2.0, 2.0, 5.7, 6.0, 3.0,-1.0, 3.0]
+
+       WriteLine fh,"'Level 12 - heart"
+       Local s$ = "DefData "+True+",540"+",-210,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*30) +","+ Int(-stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 13 ' star (level 13)
+       Local stepsx#[] = [1.5,2.5,2.0, 2.5, 1.5, 1.0, 0.0,-1.0,-1.5,-2.5,-2.0,-2.5,-1.5,-1.0,0.0,1.0]
+       Local stepsy#[] = [1.3,1.0,0.0,-1.0,-1.3,-2.2,-1.7,-2.2,-1.3,-1.0, 0.0, 1.0, 1.3, 2.2,1.7,2.2]
+
+       WriteLine fh,"'Level 13 - star"
+       Local s$ = "DefData "+True+",415"+",-95,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*80) +","+ Int(stepsy[a]*100)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 14 'W (level 14)
+       Local stepsx#[] = [ 8.0, 7.0, 6.7, 6.1, 4.7, 2.7, 1.5, 0.6,-0.6,-1.5,-2.7,-4.7,-6.1,-6.7,-7.0,-8.0]
+       Local stepsy#[] = [-3.0,-1.0, 1.5, 3.7, 5.2, 5.2, 4.0, 2.0, 2.0, 4.0, 5.2, 5.2, 3.7, 1.5,-1.0,-3.0]
+
+       WriteLine fh,"'Level 14 - W"
+       Local s$ = "DefData "+False+",140"+",120,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*35) +","+ Int(stepsy[a]*35)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 15 ' broken v (level 15)
+
+       Local stepsx#[] = [ -8.0, -7.5, -7.0, -6.5, -4.0, -2.8, -2.1, -1.1, 1.0, 2.5, 3.7, 4.5, 5.0, 5.5, 6.5,8.0]
+       Local stepsy#[] = [ 8.0, 5.4, 3.0, 0.2, 0.7,-1.5,-4.0,-5.5,-5.0,-6.5,-4.0,-2.0, 1.0, 3.0, 5.0, 7.0]
+
+       WriteLine fh,"'Level 15 - broken V"
+       Local s$ = "DefData "+False+",240"+",75,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*35) +","+ Int(-stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 16 'level 16 infinity
+       Local stepsx#[] = [0.0,-1.0,-3.0,-5.0,-6.0,-5.0,-3.0,-1.0, 0.0, 1.0, 3.0, 5.0, 6.0, 5.0, 3.0, 1.0]
+       Local stepsy#[] = [0.0, 2.0, 3.0, 2.0, 0.0,-2.0,-3.0,-2.0, 0.0, 2.0, 3.0, 2.0, 0.0,-2.0,-3.0,-2.0]
+
+       WriteLine fh,"'Level 16 - infinity"
+       Local s$ = "DefData "+True+",310"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*48) +","+ Int(-stepsy[a]*55)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+
+'Tubes
+Case 17 ' octagon (level 1)
+       Local stepsx#[] = [2.0, 3.0, 3.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-3.0,-3.0,-2.0,-1.0,0.0,1.0]
+       Local stepsy#[] = [1.5, 1.0, 0.0,-1.0,-1.5,-2.0,-2.0,-2.0,-1.5,-1.0, 0.0, 1.0, 1.5, 2.0,2.0,2.0]
+
+       WriteLine fh,"'Level 17 - Tubes 1 - octagon"
+       Local s$ = "DefData "+True+",400"+",-80,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*60) +","+ Int(stepsy[a]*80)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 18 ' tear (level 2)
+       Local stepsx#[] = [ 3.5, 4.5, 4.5, 3.5, 2.0, 1.0, 0.0,-1.0,-2.0,-3.5,-4.5,-4.5,-3.5,-1.6, 0.0, 1.6]
+       Local stepsy#[] = [ 5.0, 3.0, 0.0,-2.0,-4.0,-6.0,-8.0,-6.0,-4.0,-2.0, 0.0, 3.0, 5.0, 6.0, 6.0, 6.0]
+
+       WriteLine fh,"'Level 18 - Tubes 2 - tear"
+       Local s$ = "DefData "+True+",390"+",-40,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*35) +","+ Int(stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 19 'closed V (level 3)
+       WriteLine fh,"'Level 19 - Tubes 3 - false closed V"
+       WriteLine fh,"DefData 0,400,0,0,-210,75,-210,150,-175,225,-125,225,-50,150,-25,95,45,50,110,-50,110,-95,45,-150,-25,-225,-50,-225,-125,-150,-175,-75,-210,0,-210"
+       
+Case 20 ' bowtie (level 4)
+       Local stepsx#[] = [3.0, 5.0, 5.0, 5.0, 5.0, 3.0, 1.0,-1.0,-3.0,-5.0,-5.0,-5.0,-5.0,-3.0,-1.0, 1.0]
+       Local stepsy#[] = [1.5, 3.0, 1.5,-1.5,-3.0,-1.5,-1.0,-1.0,-1.5,-3.0,-1.5, 1.5, 3.0, 1.5, 1.0, 1.0]
+
+       WriteLine fh,"'Level 20 - Tubes 4 - bowtie"
+       Local s$ = "DefData "+True+",300"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*50) +","+ Int(stepsy[a]*50)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 21 ' | (level 5)
+       Local stepsx#[] = [ 7.0, 7.0, 7.0, 7.0, 7.0, 6.5, 6.0, 5.0, 4.0, 3.5, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
+       Local stepsy#[] = [ 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-4.0,-5.0,-6.0,-7.0,-8.0]
+
+       WriteLine fh,"'Level 21 - Tubes 5 - vert bent line"
+       Local s$ = "DefData "+False+",280"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*30) +","+ Int(-stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 22 ' [] (level 6)
+       Local stepsx#[] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,-1.0,-1.0,-1.0,-1.0,-1.0,-1.0,-1.0,-1.0, 1.0]
+       Local stepsy#[] = [5.0, 3.0, 1.0,-1.0,-3.0,-5.0,-7.0,-7.0,-5.0,-3.0,-1.0, 1.0, 3.0, 5.0, 7.0, 7.0]
+
+       WriteLine fh,"'Level 22 - Tubes 6 - thin rectangle"
+       Local s$ = "DefData "+True+",300"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*30) +","+ Int(stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+
+Case 23 ' @ (level 7)
+       Local stepsx#[] = [ 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-2.0,-1.0, 0.0, 1.0, 2.0, 1.0, 0.0,-1.0, 0.0]
+       Local stepsy#[] = [ 0.0, 1.0, 2.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-2.0,-1.0, 0.0, 1.0, 0.0,-1.0]
+
+       WriteLine fh,"'Level 23 - Tubes 7 - spiral"
+       Local s$ = "DefData "+False+",300"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*70) +","+ Int(-stepsy[a]*70)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+
+Case 24 ' ^U^ (level 8)
+       Local stepsx#[] = [8.0, 6.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0,-1.0,-1.0,-1.0,-1.0,-2.0,-4.0,-6.0,-8.0]
+       Local stepsy#[] = [1.0, 2.0, 2.0, 1.0,-1.0,-3.0,-5.0,-7.0,-7.0,-5.0,-3.0,-1.0, 1.0, 2.0, 2.0, 1.0]
+
+       WriteLine fh,"'Level 24 - Tubes 8 - ^U^"
+       Local s$ = "DefData "+False+",100"+",90,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*30) +","+ Int(-stepsy[a]*30)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+
+Case 25 ' half spade (level 9)
+       Local stepsx#[] = [ 1.0, 1.0, 2.0, 4.0, 6.0, 7.0, 8.0, 9.0, 8.0, 6.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0]
+       Local stepsy#[] = [ 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.5,-4.0,-4.0,-2.5,-1.0,-2.0,-3.0,-4.0]
+
+       WriteLine fh,"'Level 25 - Tubes 9 - half spade"
+       Local s$ = "DefData "+False+",350"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*30) +","+ Int(-stepsy[a]*45)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 26 ' / (level 10)
+       Local stepsx#[] = [-7.5,-6.5,-5.5,-4.5,-3.5,-2.5,-1.5,-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]
+       Local stepsy#[] = [ 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0,-1.0,-2.0,-3.0,-4.0,-5.0,-6.0,-7.0]
+
+       WriteLine fh,"'Level 26 - Tubes 10 - diagonal line"
+       Local s$ = "DefData "+False+",250"+",90,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*40) +","+ Int(-stepsy[a]*25)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 27 ' --- (level 11)
+       Local stepsx#[] = [-7.0,-6.0,-5.0,-4.0,-3.0,-2.0,-1.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
+       Local stepsy#[] = [ 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,-1.0,-0.0,-1.0,-0.0,-1.0,-0.0,-1.0,-0.0]
+
+       WriteLine fh,"'Level 27 - Tubes 11 - jagged horz line"
+       Local s$ = "DefData "+False+",200"+",200,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*40) +","+ Int(stepsy[a]*25)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 28 ' star (level 12)
+       Local stepsx#[] = [1.0, 2.0, 1.5, 2.0, 1.0, 1.0, 0.0,-1.0,-1.0,-2.0,-1.5,-2.0,-1.0,-1.0, 0.0, 1.0]
+       Local stepsy#[] = [1.0, 1.0, 0.0,-1.0,-1.0,-2.0,-1.5,-2.0,-1.0,-1.0, 0.0, 1.0, 1.0, 2.0, 1.5, 2.0]
+
+       WriteLine fh,"'Level 28 - Tubes 12 - star/cross"
+       Local s$ = "DefData "+True+",400"+",-80,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(-stepsx[a]*100) +","+ Int(stepsy[a]*100)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$ 
+
+Case 29 ' claw (level 13)
+       Local stepsx#[] = [4.0, 3.0, 4.5, 6.0, 4.0, 2.0, 0.0,-2.0,-4.0,-6.0,-4.5,-3.0,-4.0,-2.0, 0.0, 2.0]
+       Local stepsy#[] = [1.0, 4.0, 2.0, 0.0,-2.0,-4.0,-6.0,-4.0,-2.0, 0.0, 2.0, 4.0, 1.0, 0.0,-1.0, 0.0]
+
+       WriteLine fh,"'Level 29 - Tubes 13 - claw"
+       Local s$ = "DefData "+True+",400"+",-100,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*50) +","+ Int(-stepsy[a]*35)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 30 ' ^-^ (level 14)
+       Local stepsx#[] = [6.7, 5.7, 4.7, 3.7, 3.0, 2.5, 1.5, 0.5,-0.5,-1.5,-2.5,-3.0,-3.7,-4.7,-5.7,-6.7]
+       Local stepsy#[] = [0.4, 1.5, 1.5, 0.5,-1.0,-3.0,-3.0,-3.0,-3.0,-3.0,-3.0,-1.0, 0.5, 1.5, 1.5, 0.4]
+
+       WriteLine fh,"'Level 30 - Tubes 14 - ^-^"
+       Local s$ = "DefData "+False+",200"+",150,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*40) +","+ Int(-stepsy[a]*25)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 31 ' bent steps (level 15)
+       Local stepsx#[] = [ 7.0, 6.0, 8.0, 6.0, 6.0, 4.0, 2.0, 1.0,-1.0,-2.0,-4.0,-6.0,-6.0,-8.0,-6.0,-7.0]
+       Local stepsy#[] = [-3.0,-1.0, 0.0, 1.0, 3.0, 2.0, 4.0, 2.0, 2.0, 4.0, 2.0, 3.0, 1.0, 0.0,-1.0,-3.0]
+
+       WriteLine fh,"'Level 31 - Tubes 15 - bent steps"
+       Local s$ = "DefData "+False+",200"+",80,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*35) +","+ Int(stepsy[a]*50)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 32 'triple infinity <><><>  (level 16)
+       Local stepsx#[] = [ 1.0, 3.0, 5.0, 8.0, 8.0, 5.0, 3.0, 1.0,-1.0,-3.0,-5.0,-8.0,-8.0,-5.0,-3.0,-1.0]
+       Local stepsy#[] = [-3.0, 0.0, 3.0, 1.0,-1.0,-3.0, 0.0, 3.0, 3.0, 0.0,-3.0,-1.0, 1.0, 3.0, 0.0,-3.0]
+
+       WriteLine fh,"'Level 32 - Tubes 16 - triple infinity"
+       Local s$ = "DefData "+True+",310"+",0,"
+       
+       For a#=0 Until 16
+               s$ = s$ + Int(stepsx[a]*35) +","+ Int(-stepsy[a]*35)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+       
+Case 33 'arc 
+       WriteLine fh,"'Level 33 - rainbow"
+       Local s$ = "DefData "+False+",480"+",-80,"
+       
+       For a#=0 Until 16 
+               s$ = s$ + Int(-Cos((a+.5)*11.25)*200) +","+ Int(-Sin((a+.5)*11.25)*240)
+               If a < 15 Then s$=s$+","
+       Next
+       WriteLine fh,s$
+
+Case 34 ' pointy square 
+       WriteLine fh,"'Level 34 - pointy square"
+       WriteLine fh,"DefData 1,400,-80,-200,200,-170,100,-130,0,-170,-100,-200,-200,-100,-170,0,-130,100,-170,200,-200,170,-100,130,0,170,100,200,200,100,170,0,130,-100,170"
+       
+Case 35 ' 3 leaf
+       WriteLine fh,"'Level 35 - 3 leaf clover"
+       WriteLine fh,"DefData 1,375,0,0,0,170,0,260,66,190,144,75,118,0,0,-85,-128,-80,-228,0,-270,80,-228,85,-128,0,0,-75,118,-190,144,-260,66,-170,0"
+       
+Case 36 ' lips 
+       WriteLine fh,"'Level 36 - lips"
+       WriteLine fh,"DefData 1,400,-80,290,0,244,76,171,141,86,164,0,160,-86,164,-171,141,-244,76,-290,0,-244,-76,-171,-141,-76,-154,0,-100,76,-154,171,-141,244,-76"
+
+Case 37 ' ~
+       WriteLine fh,"'Level 37 - /\/"
+       WriteLine fh,"DefData 0,310,0,280,-60,280,21,270,108,240,170,170,198,100,173,60,117,20,41,-20,-41,-60,-117,-100,-173,-170,-198,-240,-170,-270,-108,-280,-21,-280,60"
+       
+Case 38 ' cat
+       WriteLine fh,"'Level 38 - cat"
+       WriteLine fh,"DefData 1,400,-80,0,-100,66,-124,131,-111,204,-186,220,-60,214,46,161,121,86,174,0,180,-86,174,-161,121,-214,46,-220,-60,-204,-186,-131,-111,-66,-124"
+
+Case 39 ' rocket
+       WriteLine fh,"'Level 39 - rocket"
+       WriteLine fh,"DefData 1,390,-40,-119,168,-175,108,-120,64,-65,0,-30,-74,-15,-158,0,-242,15,-158,30,-74,65,0,110,64,175,108,119,168,56,128,0,168,-56,128"
+       
+Case 40 ' pontiac 
+       WriteLine fh,"'Level 40 - pontiac"
+       WriteLine fh,"DefData 1,370,-50,160,-150,250,-190,200,-110,150,-30,100,50,50,130,0,210,-50,130,-100,50,-150,-30,-200,-110,-250,-190,-160,-150,-75,-110,0,-70,75,-110"
+
+Case 41 ' Ev3
+       WriteLine fh,"'Level 41 - Ev3"
+       WriteLine fh,"DefData 0,220,40,170,-188,270,-136,230,-56,270,36,190,46,190,148,100,148,40,220,-40,220,-100,148,-190,148,-190,56,-270,36,-230,-56,-270,-136,-170,-188"
+       
+Case 42 ' \O/
+       WriteLine fh,"'Level 42 - \O/"
+       WriteLine fh,"DefData 0,270,30,300,130,200,160,100,160,0,140,-100,90,-150,0,-130,-100,-50,-170,50,-170,130,-100,150,0,100,90,0,140,-100,160,-200,160,-300,130"
+       
+Case 43 ' yakhorns
+       WriteLine fh,"'Level 43 - yakhorns"
+       WriteLine fh, "DefData 0,200,80,120,-210,200,-185,240,-100,200,-25,120,0,90,65,60,130,30,195,-30,195,-60,130,-90,65,-120,0,-200,-25,-240,-100,-200,-185,-120,-210"
+
+Case 44 ' asteroid
+       WriteLine fh,"'Level 44 - asteroid"
+       WriteLine fh,"DefData 1,300,40,-150,90,-220,30,-220,-90,-140,-90,-60,-90,-100,-200,0,-200,100,-200,160,-140,230,-70,100,-30,160,20,220,70,130,170,70,100,-70,160"
+
+Case 45 ' broken house
+       WriteLine fh,"'Level 45 - broken house"
+       WriteLine fh, "DefData 0,140,90,70,-138,150,-116,200,-46,200,36,200,116,230,228,120,178,40,210,-40,210,-120,178,-230,228,-200,116,-200,36,-200,-46,-150,-116,-70,-138"
+
+Case 46 ' overlap star +
+       WriteLine fh,"'Level 46 - overlap star"
+       WriteLine fh,"DefData 1,300,0,-80,80,-100,10,-200,0,-100,-10,-80,-80,-10,-100,0,-200,10,-100,80,-80,100,-10,200,0,100,10,80,80,10,100,0,200,-10,100"
+
+Case 47 ' pentagon
+       WriteLine fh,"'Level 47 - pentagon"
+       WriteLine fh,"DefData 1,440,-130,160,-80,250,-20,220,60,190,140,160,220,80,220,0,220,-80,220,-160,220,-190,140,-220,60,-250,-20,-160,-80,-75,-140,0,-190,75,-140"
+
+Case 48 ' skull
+       WriteLine fh,"'Level 48 - skull"
+       WriteLine fh,"DefData 1,400,-80,180,40,124,86,111,151,66,204,0,220,-66,204,-111,151,-124,86,-180,40,-194,-46,-161,-131,-86,-184,0,-200,86,-184,161,-131,194,-46"
+               
+End Select     
+Next
+
+CloseFile(fh)
+
diff --git a/samples/tempest/sfx.bmx b/samples/tempest/sfx.bmx
new file mode 100644 (file)
index 0000000..39f43df
--- /dev/null
@@ -0,0 +1,71 @@
+Strict
+
+Import BRL.FreeAudioAudio
+Import BRL.Wavloader
+
+
+' sfx
+Global ticksfx:TSound
+Global bulletsfx:TSound
+Global shotsfx:TSound
+Global zapsfx:TSound
+Global zoominsfx:TSound
+Global zoomoutsfx:TSound
+
+Global pulsesfx:TSound
+
+Global killedbybulletsfx:TSound
+Global killedbyflippersfx:TSound
+Global killedbyspikesfx:TSound
+Global killedbypulsarsfx:TSound
+Global killedbyfuseballsfx:TSound
+
+Global flippershotsfx:TSound
+Global spikeshotsfx:TSound
+Global pulsarshotsfx:TSound
+Global fuseballshotsfx:TSound
+Global tankershotsfx:TSound
+Global spinnershotsfx:TSound
+
+Global bonusmansfx:TSound
+
+Incbin "sfx/tick.wav"
+Incbin "sfx/bullet.wav"
+Incbin "sfx/shot.wav"
+Incbin "sfx/zap.wav"
+Incbin "sfx/zoomin.wav"
+Incbin "sfx/zoomout.wav"
+Incbin "sfx/pulse.wav"
+Incbin "sfx/killedbybullet.wav"
+Incbin "sfx/killedbyflipper.wav"
+Incbin "sfx/flippershot.wav"
+Incbin "sfx/spikeshot.wav"
+Incbin "sfx/bonus.wav"
+
+Function LoadSfx()
+
+       ticksfx = LoadSound("incbin::sfx/tick.wav")
+       bulletsfx = LoadSound("incbin::sfx/bullet.wav")
+       shotsfx = LoadSound("incbin::sfx/shot.wav")
+       zapsfx = LoadSound("incbin::sfx/zap.wav")
+       zoominsfx = LoadSound("incbin::sfx/zoomin.wav")
+       zoomoutsfx = LoadSound("incbin::sfx/zoomout.wav")
+
+       pulsesfx = LoadSound("incbin::sfx/pulse.wav")
+
+       killedbybulletsfx = LoadSound("incbin::sfx/killedbybullet.wav")
+       killedbyflippersfx = LoadSound("incbin::sfx/killedbyflipper.wav")
+       killedbyspikesfx = LoadSound("incbin::sfx/killedbyflipper.wav")'*reused
+       killedbypulsarsfx = LoadSound("incbin::sfx/killedbyflipper.wav")'*reused
+       killedbyfuseballsfx = LoadSound("incbin::sfx/killedbyflipper.wav")'*reused
+
+       flippershotsfx = LoadSound("incbin::sfx/flippershot.wav")
+       spikeshotsfx = LoadSound("incbin::sfx/spikeshot.wav")
+       pulsarshotsfx = LoadSound("incbin::sfx/flippershot.wav")'*reused
+       fuseballshotsfx = LoadSound("incbin::sfx/flippershot.wav")'*reused
+       tankershotsfx = LoadSound("incbin::sfx/flippershot.wav")'*reused
+       spinnershotsfx = LoadSound("incbin::sfx/flippershot.wav")'*reused
+       
+       bonusmansfx = LoadSound("incbin::sfx/bonus.wav")
+
+End Function
\ No newline at end of file
diff --git a/samples/tempest/sfx/bonus.wav b/samples/tempest/sfx/bonus.wav
new file mode 100644 (file)
index 0000000..4ec52c2
Binary files /dev/null and b/samples/tempest/sfx/bonus.wav differ
diff --git a/samples/tempest/sfx/bullet.wav b/samples/tempest/sfx/bullet.wav
new file mode 100644 (file)
index 0000000..4054a34
Binary files /dev/null and b/samples/tempest/sfx/bullet.wav differ
diff --git a/samples/tempest/sfx/flippershot.wav b/samples/tempest/sfx/flippershot.wav
new file mode 100644 (file)
index 0000000..73c415c
Binary files /dev/null and b/samples/tempest/sfx/flippershot.wav differ
diff --git a/samples/tempest/sfx/killedbybullet.wav b/samples/tempest/sfx/killedbybullet.wav
new file mode 100644 (file)
index 0000000..8ee5d65
Binary files /dev/null and b/samples/tempest/sfx/killedbybullet.wav differ
diff --git a/samples/tempest/sfx/killedbyflipper.wav b/samples/tempest/sfx/killedbyflipper.wav
new file mode 100644 (file)
index 0000000..bd2c538
Binary files /dev/null and b/samples/tempest/sfx/killedbyflipper.wav differ
diff --git a/samples/tempest/sfx/pulse.wav b/samples/tempest/sfx/pulse.wav
new file mode 100644 (file)
index 0000000..ff5a7ae
Binary files /dev/null and b/samples/tempest/sfx/pulse.wav differ
diff --git a/samples/tempest/sfx/shot.wav b/samples/tempest/sfx/shot.wav
new file mode 100644 (file)
index 0000000..8853c9d
Binary files /dev/null and b/samples/tempest/sfx/shot.wav differ
diff --git a/samples/tempest/sfx/spikeshot.wav b/samples/tempest/sfx/spikeshot.wav
new file mode 100644 (file)
index 0000000..7eb4503
Binary files /dev/null and b/samples/tempest/sfx/spikeshot.wav differ
diff --git a/samples/tempest/sfx/tick.wav b/samples/tempest/sfx/tick.wav
new file mode 100644 (file)
index 0000000..f82f118
Binary files /dev/null and b/samples/tempest/sfx/tick.wav differ
diff --git a/samples/tempest/sfx/zap.wav b/samples/tempest/sfx/zap.wav
new file mode 100644 (file)
index 0000000..12caf08
Binary files /dev/null and b/samples/tempest/sfx/zap.wav differ
diff --git a/samples/tempest/sfx/zoomin.wav b/samples/tempest/sfx/zoomin.wav
new file mode 100644 (file)
index 0000000..4212fc9
Binary files /dev/null and b/samples/tempest/sfx/zoomin.wav differ
diff --git a/samples/tempest/sfx/zoomout.wav b/samples/tempest/sfx/zoomout.wav
new file mode 100644 (file)
index 0000000..542fd21
Binary files /dev/null and b/samples/tempest/sfx/zoomout.wav differ
diff --git a/samples/tempest/tempest.bmx b/samples/tempest/tempest.bmx
new file mode 100644 (file)
index 0000000..a024d37
--- /dev/null
@@ -0,0 +1,3469 @@
+'Tempest
+'Started by David Bird (Birdie) - BlitzMax 1.10 Samples 
+
+'Completed by Mark Incitti (Mark1nc) - June 2005
+
+' Version 1.5 - July 18
+' added 16 more tubes
+' tweaked the difficulty and release rates
+
+' Version 1.1 - July 7
+' fixed egg hatching to act 7 (non-existant case - disappeared)
+' changed fuseballs - only kill when off the edge  w>1 or w<7
+' added Tempest Tubes boards
+
+' CTRL - Fire!
+' SPACE - Superzapper
+' L/R - Move
+' ESC - Quit
+' T - select tube set
+
+Strict
+
+Import "transformfunctions.bmx"
+Import "vectorfont.bmx"
+Import "sfx.bmx"
+
+'Setup Graphics mode
+Graphics CWidth,CHeight,32    ',0 windowed  ',32 'fullscreen
+HideMouse
+SeedRnd(MilliSecs())
+
+
+'defined colours index
+Const COL_BULLETS = 0
+Const COL_CLAW = 1
+Const COL_TANKERS = 2
+Const COL_FLIPPERS = 3
+Const COL_PULSARS = 4
+Const COL_SPIKERS = 5
+Const COL_LEVEL = 6
+Const COL_INFO = 7
+
+'death types
+Const KILLED_BY_BULLET = 0
+Const KILLED_BY_PULSAR = 2
+Const KILLED_BY_SPIKE = 3
+Const KILLED_BY_FLIPPER = 4
+Const KILLED_BY_FUSEBALL = 5
+
+'level states
+Const LEVEL_BEGIN    = 0
+Const LEVEL_COMPLETE = 1
+Const LEVEL_READY    = 2
+Const LEVEL_PLAYER_DYING = 3
+Const LEVEL_ZOOMING = 4
+Const LEVEL_START_ZOOM = 5
+Const LEVEL_REVERSE_ZOOM = 6
+Const LEVEL_INTO_VORTEX = 7
+
+'baddie types
+Const BAD_SPIKE = 1
+Const BAD_BULLET = -1
+Const BAD_SPINNER = 2
+Const BAD_FLIPPER = 3
+Const BAD_TANKER = 4
+Const BAD_PULSAR = 5
+Const BAD_FUSEBALL = 6
+
+Const PLAYERSPEED# = 0.25 '5 positions per edge  0,.25,.5,.75,1
+
+
+' lists of objects
+Global POINT_LIST:TList = New TList
+Global FUSEPOINT_LIST:TList = New TList
+Global EGG_LIST:TList = New TList
+Global EXPLOSION_LIST:TList = New TList
+Global SHOT_LIST:TList = New TList
+Global BADDIE_LIST:TList = New TList
+
+
+Global theLevel:Level
+Global current_level = 0
+Global current_color = 0
+Global current_board = 0
+Global tubes = 0
+Global hiscore = 0
+
+Global leveldata[64,3+32]  '  Closed/Open, YCenter, YOFFSET, 16 x,y pairs
+
+Global eggsleft
+Global maxeggs
+Global enemiesleft
+Global hatchingeggs
+
+Global MainPlayer:Player
+Global superzapper = 2
+Global superzapperdisplay = 0
+Global startbonus = 0
+Global zapchan:TChannel = AllocChannel()
+
+Global canflip = True
+Global flipflipspeed = 15
+Global pulseflipspeed = 15
+Global fuseclimbspeed = 1
+Global tankerclimbspeed = 1
+
+Global pulsecount = 0
+Global pulsespeed = 1
+Global pulsing = False
+Global pulse_zh# 
+Global pulsesalive = False
+
+Global fusex#[5,6,7]
+Global fusey#[5,6,7]
+Global fuseball_count
+Global fuseball_frame
+
+Global globalclock
+Global enemyreleaserate = 30
+Global hatchrate = 1
+Global rimit = False
+Global onrim = False
+
+Global showdebug
+
+LoadSfx()
+ReadFuseballData()
+ReadLevelData()
+
+theLevel = Level.Create()
+MainPlayer = Player.Create()
+
+Game()
+
+'BoardMaker()
+
+
+
+Function BoardMaker()
+
+       Local showcord = False
+       Local index = 0
+       Local cb = 0
+       Local xp[16]
+       Local yp[16]
+       Local c 
+       While Not KeyHit(key_escape)
+
+               c = leveldata[cb,0]
+               k = 70
+               CCenterY = leveldata[cb,1]
+               YOFFSET =  leveldata[cb,2]
+       
+       
+               For Local a = 0 Until 16
+                       xp[a] = leveldata[cb,3+a*2]+400
+                       yp[a] = leveldata[cb,3+a*2+1]+300
+                       If index = a 
+                               DrawOval xp[a]-4,yp[a]-4,8,8
+                       Else
+                               DrawOval xp[a]-2,yp[a]-2,4,4
+                       EndIf
+
+                       If a > 0
+                               DrawLine xp[a-1],yp[a-1],xp[a],yp[a]
+                       EndIf
+                       If showcord Then DrawText "("+(xp[a]-400)+","+(yp[a]-300)+")",xp[a]-30,yp[a]-20
+               Next
+               If c
+                       DrawLine xp[15],yp[15],xp[0],yp[0]
+               EndIf
+               
+               If KeyHit(key_c) Then showcord = 1-showcord
+               If KeyHit(key_b) Then cb = cb + 1 ; If cb > 47 Then cb = 0
+               If KeyHit(key_v) Then cb = cb - 1 ; If cb < 0 Then cb = 47
+               
+               If KeyHit(key_COMMA) Then index = index - 1;If index < 0 Then index = 15
+               If KeyHit(key_PERIOD) Then index = index + 1;If index > 15 Then index = 0       
+
+               If KeyHit(key_left) Then leveldata[cb,3+index*2]:-10
+               If KeyHit(key_right) Then leveldata[cb,3+index*2]:+10
+               If KeyHit(key_up) Then leveldata[cb,3+index*2+1]:-10
+               If KeyHit(key_down) Then leveldata[cb,3+index*2+1]:+10
+
+               DrawText cb,10,10
+               
+               If KeyHit(key_s)
+                       DebugLog "'Level "+cb
+                       Local s$ = "DefData "+c+","+leveldata[cb,1]+","+leveldata[cb,2]+","
+                       For Local a = 0 Until 16
+                               s$ = s$ + Int(leveldata[cb,3+a*2]) +","+ Int(leveldata[cb,3+a*2+1])
+                               If a < 15 Then s$=s$+","
+                       Next
+                       DebugLog s$
+               EndIf
+               Flip
+               Delay 30
+               Cls
+       Wend
+               
+End Function
+
+
+
+
+
+
+
+Type Player
+       Field e_Index        'the edge the player is on
+       Field zPos                       ' player height
+       Field shottimer = 3      ' delay between shots timer
+       Field score
+       Field oldscore
+       Field bonusmencnt = 0   ' keep track of when bonus man is due
+       Field dying                             
+       Field men = 3
+       Field deathcount
+       Field deathtype
+       Field bonusdisplay
+       Field scl#=0.5          ' where on the edge 0.0, 0.25, 0.5, 0.75, 1.0
+       Field schan:TChannel = Null ' send all shot audio through this channel
+
+       
+       Method SetEdge(index)
+               e_index = index
+       EndMethod
+
+
+       Method AddShot()
+               Shot.Create(theLevel.edges[e_Index],zPos)
+       EndMethod
+
+       Method ShiftLeft()
+               PlaySound(ticksfx)
+               If e_Index=0
+                       If theLevel.continuous
+                               e_Index = theLevel.e_Cnt-1
+                       EndIf
+               Else
+                       e_Index:-1
+               EndIf
+       EndMethod
+
+       Method ShiftRight()
+               PlaySound(ticksfx)
+               If e_Index=theLevel.e_cnt-1
+                       If theLevel.continuous
+                               e_Index = 0
+                       EndIf
+               Else
+                       e_Index:+1
+               EndIf
+       EndMethod
+
+       Method Update()
+       
+               ' fire!
+               If KeyDown(KEY_LCONTROL)
+                       If shottimer > 2
+                               If deathcount = 0 ' no control when dying
+                                       If CountList(SHOT_LIST) < 12
+                                               Self.AddShot()
+                                               PlaySound(shotsfx, schan)
+                                               shottimer = 0
+                                       EndIf
+                               EndIf
+                       EndIf
+               EndIf
+               shottimer:+1
+               
+               ' superzapper
+               If KeyHit(KEY_SPACE)
+                       If deathcount = 0
+                               If superzapper > 0 
+                                       baddies.superZapit(superzapper)
+                                       superzapper:-1
+                               EndIf
+                       EndIf
+               EndIf
+               
+               ' rotate 
+               If KeyDown(KEY_LEFT)
+                       If deathcount = 0
+                               If theLevel.continuous
+                                       scl:-PLAYERSPEED
+                                       If scl<0 Then
+                                               Self.ShiftLeft()
+                                               scl = 1
+                                       EndIf
+                               Else
+                                       If e_index > 0
+                                               scl:-PLAYERSPEED
+                                               If scl<0 Then
+                                                       Self.ShiftLeft()
+                                                       scl = 1
+                                               EndIf
+                                       Else
+                                               scl:-PLAYERSPEED
+                                               If scl < 0 Then
+                                                       scl = 0
+                                               EndIf
+                                       EndIf
+                               EndIf
+                       EndIf
+               EndIf
+               
+               ' rotate other direction
+               If KeyDown(KEY_RIGHT)
+                       If deathcount = 0
+                               If theLevel.continuous
+                                       scl:+PLAYERSPEED
+                                       If scl>1 Then
+                                               Self.ShiftRight()
+                                               scl = 0
+                                       EndIf
+                               Else
+                                       If e_index < theLevel.e_cnt-1
+                                               scl:+PLAYERSPEED
+                                               If scl > 1 Then
+                                                       Self.ShiftRight()
+                                                       scl = 0
+                                               EndIf
+                                       Else
+                                               scl:+PLAYERSPEED
+                                               If scl > 1 Then
+                                                       scl = 1
+                                               EndIf
+                                       EndIf
+                               EndIf
+                       EndIf
+               EndIf
+       
+               ' this edge will be player colour
+               theLevel.edges[e_Index].hasplayer = True
+               
+               'we're dying if deathcount has been set to > 0
+               If deathcount > 0
+                       deathcount:-1
+                       If deathcount = 0
+                               men:-1
+                               deathtype = 0
+                       EndIf
+               EndIf
+               
+               'check score for bonus
+               If score <> oldscore
+                       If Int(score/10000) > bonusmencnt
+                               men:+1
+                               bonusdisplay = 100
+                               bonusmencnt = score/10000
+                               PlaySound(bonusmansfx)
+                       EndIf
+                       ' keep track of high score
+                       If score > hiscore
+                               hiscore = score
+                       EndIf
+               EndIf
+
+               'time to show rainbow pattern - for bonus man
+               If bonusdisplay > 0
+                       If theLevel.state <> LEVEL_BEGIN
+                               bonusdisplay:-1
+                       EndIf
+               EndIf
+
+       EndMethod
+
+       
+       Method Draw()
+               SetRotation 0
+               'Draw it
+               Local zz#,zh#
+               Local x#[8],y#[8]
+               Select theLevel.state
+                       Case LEVEL_BEGIN
+                               zPos = theLevel.depth                           
+                               zz = theLevel.position+theLevel.depth-zPos
+                               zh# = (10.0)*(1.0-zz/1500.0)
+                       Case LEVEL_READY
+                               zPos = theLevel.depth                           
+                               zz = theLevel.position+theLevel.depth-zPos
+                               zh# = 20.0+10-Abs(scl-0.5)*10.0
+                       Case LEVEL_PLAYER_DYING
+                               Select deathtype
+                                       Case KILLED_BY_FLIPPER
+                                               zz = theLevel.position+theLevel.depth-zPos' +180-deathcount*3
+                                               zh# = 20.0+10-Abs(scl-0.5)*10.0
+                                               zh = zh * (deathcount*3)/180.0
+                                       Case KILLED_BY_PULSAR
+                                               zz = theLevel.position - Sin(deathcount*1.5)*100 +100
+                                               zh# = 20.0+10-Abs(scl-0.5)*10.0
+                                       Case KILLED_BY_BULLET
+                                               zz = theLevel.position + Sin(deathcount*1.5)*20 -20
+                                               zh# = 20.0+10-Abs(scl-0.5)*10.0
+                                       Default
+                                               zPos = theLevel.depth                           
+                                               zz = theLevel.position+theLevel.depth-zPos
+                                               zh# = 2+zPos/10-Abs(scl-0.5)*zPos/40    
+                               End Select
+                       Case LEVEL_COMPLETE
+                               zPos = theLevel.depth                           
+                               zz = theLevel.position+theLevel.depth-zPos
+                               zh# = 2+zPos/10-Abs(scl-0.5)*zPos/40    
+                       Case LEVEL_START_ZOOM
+                               zPos = theLevel.depth                           
+                               zz = theLevel.position+theLevel.depth-zPos
+                               zh# = 2+zPos/10-Abs(scl-0.5)*zPos/40    
+                       Case LEVEL_ZOOMING
+                               'zPos = theLevel.depth                          
+                               zz = theLevel.position+theLevel.depth-zPos
+                               zh# = 30.0-Abs(scl-0.5)*zPos/40
+                       Case LEVEL_REVERSE_ZOOM
+                               zz = theLevel.position+theLevel.depth-zPos
+                               zh# = 2+zPos/10-Abs(scl-0.5)*zPos/40
+               EndSelect
+               Local e:Edge = theLevel.edges[e_Index]
+               TForm(e.p1.x, e.p1.y,zz,x[0],y[0])
+               TForm(e.p2.x, e.p2.y,zz,x[1],y[1])
+
+               Local xn#
+               Local yn#
+               
+               Local xd# = x[1]-x[0]
+               Local yd# = y[1]-y[0]
+               Local sz# = Sqr(xd*xd + yd*yd)
+               ' find a perpendicular line to the outside edge of the web
+               If sz = 0
+                       xn# = 0
+                       yn# = 0
+               Else
+                       xn# = -yd/sz
+                       yn# = xd/sz
+               EndIf
+               If scl > 0.0 And scl < 1.0
+                       x[4] = x[1]-(xd)*scl + xn*zh
+                       y[4] = y[1]-(yd)*scl + yn*zh
+               
+                       x[2] = x[1]-(xd)*0.3 - xn*zh/2
+                       y[2] = y[1]-(yd)*0.3 - yn*zh/2
+               
+                       x[3] = x[1]-(xd)*0.6 - xn*zh/2
+                       y[3] = y[1]-(yd)*0.6 - yn*zh/2
+               
+                       x[5] = x[1]-(xd)*scl + xn*zh/2
+                       y[5] = y[1]-(yd)*scl + yn*zh/2
+               
+                       x[6] = x[1]-(xd)*0.8
+                       y[6] = y[1]-(yd)*0.8
+               
+                       x[7] = x[1]-(xd)*0.2
+                       y[7] = y[1]-(yd)*0.2
+                       
+               Else
+                       ' extreme ends of motion
+                       If scl >.5
+                               x[4] = x[1]-(xd)*scl + xn*zh
+                               y[4] = y[1]-(yd)*scl + yn*zh
+                       
+                               x[2] = x[1]-(xd)*0.3 - xn*zh/2
+                               y[2] = y[1]-(yd)*0.3 - yn*zh/2
+                       
+                               x[3] = x[1]-(xd)*0.6 - xn*zh/2
+                               y[3] = y[1]-(yd)*0.6 - yn*zh/2
+                       
+                               x[6] = x[1]-(xd)*0.9' + xn*zh/8
+                               y[6] = y[1]-(yd)*0.9' + yn*zh/8
+
+                               x[5] = x[1]-(xd)*0.9 + xn*zh/2
+                               y[5] = y[1]-(yd)*0.9 + yn*zh/2
+                                               
+                               x[7] = x[1]-(xd)*0.8 + xn*zh
+                               y[7] = y[1]-(yd)*0.8 + yn*zh
+
+                               x[1] = x[1]-(xd)*0.7 + xn*zh*1.5
+                               y[1] = y[1]-(yd)*0.7 + yn*zh*1.5
+                       Else
+                               x[4] = x[1]-(xd)*scl + xn*zh
+                               y[4] = y[1]-(yd)*scl + yn*zh
+                       
+                               x[2] = x[1]-(xd)*0.3 - xn*zh/2
+                               y[2] = y[1]-(yd)*0.3 - yn*zh/2
+                       
+                               x[3] = x[1]-(xd)*0.6 - xn*zh/2
+                               y[3] = y[1]-(yd)*0.6 - yn*zh/2
+                       
+                               x[7] = x[1]-(xd)*0.1' + xn*zh/8
+                               y[7] = y[1]-(yd)*0.1' + yn*zh/8
+
+                               x[5] = x[1]-(xd)*0.1 + xn*zh/2
+                               y[5] = y[1]-(yd)*0.1 + yn*zh/2
+                       
+                               x[6] = x[1]-(xd)*0.2 + xn*zh
+                               y[6] = y[1]-(yd)*0.2 + yn*zh
+                       
+                               x[0] = x[1]-(xd)*0.3 + xn*zh*1.5
+                               y[0] = y[1]-(yd)*0.3 + yn*zh*1.5
+                       EndIf           
+               EndIf           
+               Color(COL_CLAW)
+               If deathtype <> 5
+                       ' normal claw draw
+                       DrawLine x[0],y[0],x[4],y[4]
+                       DrawLine x[1],y[1],x[4],y[4]
+                       DrawLine x[0],y[0],x[3],y[3]
+                       DrawLine x[1],y[1],x[2],y[2]
+                       
+                       DrawLine x[5],y[5],x[6],y[6]
+                       DrawLine x[5],y[5],x[7],y[7]            
+                       DrawLine x[3],y[3],x[6],y[6]
+                       DrawLine x[2],y[2],x[7],y[7]
+               Else
+                       'death by fuseball
+                       If (deathcount/4)Mod 4 >1 SetColor 255,255,255
+                       For Local i = 0 To 7
+                               Local rv = Rand(0,360)
+                               Local sr = Rnd(4,40)*(60-deathcount)/60
+                               DrawRect (x[2]+x[3])/2+Cos(rv)*sr,(y[2]+y[3])/2+Sin(rv)*sr,2,2
+                       Next            
+               EndIf
+               
+               If showdebug
+                       DrawText zPos+" "+zh,600,10
+               EndIf
+               
+       EndMethod
+
+
+       Method DrawMenLeft()
+       
+               Local zz#,zh#
+               Local x#[8],y#[8]
+               zh# = 10.0
+               x[0] = 30
+               y[0] = 60
+               x[1] = 0
+               y[1] = 60
+
+               Local xn#
+               Local yn#
+               
+               Local xd# = -30
+               Local yd# = 0
+               Local sz# = 30
+               xn# = 0
+               yn# = -1
+               x[4] = x[1]-(xd)*.5 + xn*zh
+               y[4] = y[1]-(yd)*.5 + yn*zh
+       
+               x[2] = x[1]-(xd)*0.3 - xn*zh/2
+               y[2] = y[1]-(yd)*0.3 - yn*zh/2
+       
+               x[3] = x[1]-(xd)*0.6 - xn*zh/2
+               y[3] = y[1]-(yd)*0.6 - yn*zh/2
+       
+               x[5] = x[1]-(xd)*.5 + xn*zh/2
+               y[5] = y[1]-(yd)*.5 + yn*zh/2
+       
+               x[6] = x[1]-(xd)*0.8' + xn*zh/8
+               y[6] = y[1]-(yd)*0.8' + yn*zh/8
+       
+               x[7] = x[1]-(xd)*0.2' + xn*zh/8
+               y[7] = y[1]-(yd)*0.2' + yn*zh/8
+               
+               Color(COL_CLAW)
+               Local m = men;If m > 5 Then m = 5
+               For Local t = 1 To m
+                       DrawLine x[0]+t*40-30,y[0],x[4]+t*40-30,y[4]
+                       DrawLine x[1]+t*40-30,y[1],x[4]+t*40-30,y[4]
+                       DrawLine x[0]+t*40-30,y[0],x[3]+t*40-30,y[3]
+                       DrawLine x[1]+t*40-30,y[1],x[2]+t*40-30,y[2]
+               
+                       DrawLine x[5]+t*40-30,y[5],x[6]+t*40-30,y[6]
+                       DrawLine x[5]+t*40-30,y[5],x[7]+t*40-30,y[7]            
+                       DrawLine x[3]+t*40-30,y[3],x[6]+t*40-30,y[6]
+                       DrawLine x[2]+t*40-30,y[2],x[7]+t*40-30,y[7]
+               Next
+               If men > 5
+                       DrawString( men,6*40+5-30,50,2.0)
+               EndIf
+       EndMethod
+
+       Function Create:Player()
+               Local p:Player = New Player     
+               p.zPos = 400
+               p.schan = AllocChannel()
+               Return p
+       EndFunction
+       
+EndType
+
+
+
+
+Type Point
+       Field x#,y#,xd#,yd#
+       Field xtarget#,ytarget#
+       Field xrate#,yrate#
+       Field xoriginal#,yoriginal#
+
+       Field e0:edge
+       Field e1:edge
+       
+       Function Create:Point( x#, y# )
+               Local p:Point = New Point
+               p.x=x
+               p.y=y
+               p.xoriginal# = x
+               p.yoriginal# = y
+               p.xtarget# = x
+               p.ytarget# = y
+               POINT_LIST.AddLast( p )         
+               Return p
+       EndFunction
+
+       Method SetPointXY( x#, y# )
+               x=x
+               y=y
+               xoriginal# = x
+               yoriginal# = y
+       EndMethod
+       
+       Method Update()
+               If Abs(xd) > 0.001
+                       xd = xd - xrate
+               Else
+                       xd = 0
+                       xtarget = x
+                       xrate = 0
+               EndIf
+               x = x + xrate
+               If Abs(yd) > 0.001
+                       yd = yd - yrate
+               Else
+                       yd = 0
+                       ytarget = y
+                       xrate = 0
+               EndIf
+               y = y + yrate
+       End Method 
+       
+       Method ResetPoint()
+               x=xoriginal
+               y=yoriginal
+               xtarget = xoriginal#
+               ytarget = yoriginal#
+               xrate = 0
+               yrate = 0
+               xd = 0
+               yd = 0          
+       End Method 
+       
+       Method MorphPoint(xt#,yt#,xr#,yr#)
+               x = xtarget
+               y = ytarget
+               xtarget = xt
+               ytarget = yt
+               xd = xtarget-x
+               yd = ytarget-y          
+               xrate = Abs(xr)*Sgn(xd)
+               yrate = Abs(yr)*Sgn(yd)
+       End Method 
+               
+       Function UpdatePoints()
+               Local p:Point
+               For p=EachIn POINT_LIST
+                       p.Update()
+               Next
+       EndFunction
+       
+       Function ResetPoints()
+               Local p:Point
+               For p=EachIn POINT_LIST
+                       p.ResetPoint()
+               Next
+       EndFunction
+       
+EndType
+
+
+
+
+
+
+
+
+
+Type Edge
+       Field index
+       Field p1:point
+       Field p2:point
+       Field angle
+       Field pulsing
+       Field haspulser = False
+       Field hasplayer = False
+       Field bcol
+       
+       Field spike:Spikes
+       
+       Field xx#,yy#
+       
+       Method Draw( zd1#, zd2#, layer )
+               If zd1<1 zd1=1
+               If zd2<1 zd2=1
+               
+               'draw the edge at zero position,
+               'the depth line and the far point
+               Local x#[4],y#[4]
+               TForm p1.x,p1.y,zd1, x[0],y[0]
+               TForm p1.x,p1.y,zd2, x[1],y[1]
+               
+               TForm p2.x,p2.y,zd1, x[2],y[2]
+               TForm p2.x,p2.y,zd2, x[3],y[3]
+               
+               If pulsing
+                       'SetBlend LIGHTBLEND    
+       
+                       SetLineWidth 2
+                       If (pulsecount) Mod 8 > 3
+                               Color(COL_PULSARS)
+                       Else
+                               Color(COL_BULLETS)
+                       EndIf
+                       DrawLine x[0],y[0],x[1],y[1]
+                       DrawLine x[3],y[3],x[2],y[2]
+                               
+               Else
+               
+                       'SetBlend LIGHTBLEND    
+                       SetLineWidth 2
+
+                       If hasplayer 
+                               Color(COL_CLAW)
+                       Else
+                               If (superzapperdisplay/2) Mod 4 > 1
+                                       Color(COL_TANKERS)
+                               Else
+                                       Color(COL_LEVEL)
+                               EndIf
+                       EndIf
+                       If layer = 0 And mainPlayer.bonusdisplay > 0
+                               Color(bcol)
+                       EndIf
+                       If layer = 0 Or hasplayer
+                               DrawLine x[0],y[0],x[1],y[1]
+                               DrawLine x[3],y[3],x[2],y[2]
+                       EndIf
+                       
+                       If (superzapperdisplay/2) Mod 4 > 1
+                               Color(COL_TANKERS)
+                       Else
+                               Color(COL_LEVEL)
+                       EndIf
+                       DrawLine x[1],y[1],x[3],y[3]'bottom
+                       If haspulser = False
+                               DrawLine x[0],y[0],x[2],y[2]'top
+                       EndIf
+               EndIf           
+               SetLineWidth 1
+
+               If showdebug Then DrawText angle,x[0],y[0]
+       EndMethod
+
+       Function Create:Edge(p1:Point, p2:Point)
+               Local e:Edge = New edge
+               
+               'assign the points
+               e.p1=p1
+               e.p2=p2
+               
+               'linkem up
+               p1.e1=e
+               p2.e0=e
+               
+               'store the midpoint for speeding up
+               e.xx =( ( p2.x - p1.x ) / 2.0 ) + p1.x
+               e.yy =( ( p2.y - p1.y ) / 2.0 ) + p1.y
+                       
+               Return e
+       EndFunction
+EndType
+
+
+
+Type Level
+       Field depth#    = 400
+       Field position# = 1500
+       Field state     = LEVEL_BEGIN
+       Field continuous = True
+       Field cnt
+       Field hasspikes = False
+       Field hasflippers = False
+       Field hastankers = False
+       Field hastankersp = False
+       Field hastankersf = False
+       Field hasfuseballs = False
+       Field haspulsars = False
+       
+       'Field points:TList
+       Field edges:Edge[20]
+       Field e_cnt
+
+       Method AddPoint:Point(x#,y#)
+               Local p:Point = Point.Create( x, y )
+               'points.AddLast( p )
+               Return p
+       EndMethod
+
+       Method AddEdge:Edge( p1:Point, p2:point )
+               Local e:Edge = Edge.Create( p1, p2 )
+               edges[e_cnt] = e
+               e_cnt:+1
+               e.index = e_cnt
+               Return e
+       EndMethod
+
+       Method Update()
+               Select state
+                       Case LEVEL_BEGIN
+                               If cnt = 0 Then PlaySound(zoominsfx)
+                               cnt = cnt + 1
+                               If position>50
+                                       position:-10
+                                       CCenterY = -(position-50)/5 + leveldata[current_board+tubes,1]
+                               Else
+                                       state=LEVEL_READY
+                                       CCenterY = leveldata[current_board+tubes,1]
+                               EndIf
+                       Case LEVEL_READY
+                               ZOFFSET = 5
+                               mainplayer.zPos = depth
+                       Case LEVEL_PLAYER_DYING
+                               ZOFFSET = 5
+                               If mainplayer.deathcount = 1
+                                       state=LEVEL_INTO_VORTEX
+                                       cnt = 0
+                               EndIf
+                       Case LEVEL_INTO_VORTEX
+                               cnt:+1
+                               ZOFFSET:+3
+                               If cnt > 60
+                                       state=LEVEL_READY
+                                       Baddies.ConvertBaddieToEggs()
+                                       cnt = 0
+                                       ZOFFSET=5
+                               EndIf
+                       Case LEVEL_START_ZOOM
+                               k = 70
+                               ZOFFSET = 5
+                               mainplayer.zPos = depth
+                               cnt = cnt + 1
+                               If cnt > 20 
+                                       state = LEVEL_ZOOMING
+                                       mainPlayer.deathcount = 0
+                                       cnt = 0
+                                       PlaySound(zoomoutsfx)
+                               EndIf
+                       Case LEVEL_ZOOMING
+                               If ZOFFSET < -40
+                                       k = k + 2
+                                       If k > 70+30 Then k = k + 2
+                                       If mainplayer.zPos < 10
+                                               state = LEVEL_COMPLETE
+                                               ZOFFSET = 5
+                                               cnt = 0
+                                       Else
+                                               mainplayer.zPos:-3                      
+                                       EndIf
+                               Else
+                                       ZOFFSET = ZOFFSET - 2
+                                       mainplayer.zPos:-3
+                               EndIf
+                       Case LEVEL_REVERSE_ZOOM
+                               k=k-4
+                               If k<70 Then k = 70
+                               ZOFFSET:+1
+                               If ZOFFSET > 5
+                                       ZOFFSET = 5                                     
+                                       cnt = cnt + 1
+                                       If cnt > 20
+                                               If CountList(EGG_LIST) = 0
+                                                       state = LEVEL_START_ZOOM
+                                               Else
+                                                       state = LEVEL_READY
+                                               EndIf
+                                               cnt = 0
+                                               k=70
+                                               mainplayer.deathcount = 0                                               
+                                       EndIf
+                                       mainplayer.zPos = depth                                 
+                               EndIf                   
+                       Case LEVEL_COMPLETE
+                               cnt = cnt + 1
+                               If cnt > 60
+                                       If startbonus > 0
+                                               mainplayer.score:+startbonus 
+                                               startbonus = 0
+                                       EndIf
+
+                                       ZOFFSET = 5
+                                       mainplayer.zPos = depth
+                                       state = LEVEL_BEGIN
+                                       ClearLevel()
+                                       current_level:+1
+                                       If current_level > 16*6-1
+                                               current_level = 0
+                                               tubes = tubes+16
+                                               If tubes > 32 Then tubes = 0
+                                       EndIf
+                                       current_board = current_level Mod 16
+                                       current_color = current_level/16
+                                       SetUpLevel()
+                                       SetUpEnemies()
+                                       superzapper = 2
+                                       MainPlayer.SetEdge( 7 )
+                                       cnt = 0
+                                       position = 1500
+                                       CCenterY = -(position-50)/5 + leveldata[current_board+tubes,1]
+                                       FlushKeys()
+                               EndIf                           
+                                       
+               EndSelect
+               For Local a=0 Until e_cnt
+                       edges[a].pulsing = False
+                       edges[a].haspulser = False
+                       edges[a].hasplayer = False
+                       If mainplayer.bonusdisplay Mod 4 = 3
+                               edges[a].bcol = Rand(0,5)
+                       EndIf
+               Next
+               If superzapperdisplay > 0 Then superzapperdisplay:-1
+       EndMethod
+
+
+       Method UpdateAngles()
+               Local a
+               For a=0 Until e_cnt             
+                       edges[a].angle = GetAngle#( edges[a].p2.x, edges[a].p2.y, edges[a].p1.x, edges[a].p1.y, edges[(a+1)Mod e_cnt].p1.x, edges[(a+1)Mod e_cnt].p1.y)
+               Next
+               If theLevel.continuous = False
+                       edges[14].angle = 0 
+               EndIf
+           For a=0 Until e_cnt
+                       edges[a].xx =( ( edges[a].p2.x - edges[a].p1.x ) / 2.0 ) + edges[a].p1.x
+               edges[a].yy =( ( edges[a].p2.y - edges[a].p1.y ) / 2.0 ) + edges[a].p1.y
+       Next
+               a=0
+               If theLevel.continuous = False
+                       edges[a].xx =( ( edges[a].p2.x - edges[a].p1.x ) / 2.0 ) + edges[a].p1.x
+               edges[a].yy =( ( edges[a].p2.y - edges[a].p1.y ) / 2.0 ) + edges[a].p1.y                
+               EndIf
+       End Method
+       
+       
+       Method Draw()
+               Local a=0
+               Local oldz
+               Select state
+                       Case LEVEL_INTO_VORTEX 
+                               oldz = ZOFFSET  
+                               ZOFFSET = 5             
+               EndSelect
+               
+               For a=0 Until e_cnt
+                       edges[a].Draw(position,position+depth,0)
+               Next
+               For a=0 Until e_cnt
+                       edges[a].Draw(position,position+depth,1)
+               Next
+               
+               Select state
+                       Case LEVEL_INTO_VORTEX 
+                               ZOFFSET = oldz
+               EndSelect
+               
+       EndMethod
+
+       Function Create:Level()
+               Local l:Level = New Level
+               'l.points = New TList
+               Return l
+       EndFunction
+       
+       Method mutate()
+           Local a=0
+           For a=0 Until e_cnt
+                       Local xt# = Rnd(-1,1)
+                       Local yt# = Rnd(-1,1)
+                       Local xr# = xt/16
+                       Local yr# = yt/16
+                       edges[a].p1.Morphpoint(xt+edges[a].p1.x,yt+edges[a].p1.y,xr,yr)
+       Next
+               a=0
+               If theLevel.continuous = False
+                       Local xt# = Rnd(-1,1)
+                       Local yt# = Rnd(-1,1)
+                       Local xr# = xt/16
+                       Local yr# = yt/16
+                       edges[a].p2.Morphpoint(xt+edges[a].p2.x,yt+edges[a].p2.y,xr,yr)                 
+               EndIf
+       EndMethod
+       
+       Function LevelSelect()
+
+               Local done = False      
+               Local lv = -1
+               Local index = current_level/2
+               If index > 42 Then index = 42
+               Local sel = 0
+
+               While lv = -1
+                       If KeyHit(key_left)
+                               sel:-1
+                               If sel < 0
+                                       sel = 0
+                                       index:-1
+                                       If index < 0 Then index = 0
+                               EndIf
+                               PlaySound(ticksfx)
+                       EndIf
+                       If KeyHit(KEY_RIGHT)
+                               sel:+1
+                               If sel > 4
+                                       sel = 4
+                                       index:+1
+                                       If index > 43 Then index = 43
+                               EndIf
+                               PlaySound(ticksfx)
+                       EndIf
+                       
+                       Cls 
+                       SetColor 255,255,0
+                       DrawString("SELECT STARTING LEVEL",100,10,6.0)
+                       DrawString("HI SCORE  "+hiscore,180,500,6.0)
+                       
+                       For Local br = 0 To 4
+                               DrawSmallLevel((index+br)*2,190+br*120,300,br=sel)
+                       Next
+                       SetColor 0,255,0        
+                       DrawString("LEVEL",80,300-50,2.0)
+       
+                       SetColor 255,0,0
+                       DrawString("BONUS",80,300+50,2.0)                       
+                       
+                       If KeyHit(KEY_LCONTROL)
+                               lv = (index+sel)*2
+                               Local col = lv/16
+                               startbonus = (lv)*(3000+col*1000)+col*7000+((lv)>3)*(lv)*4000                           
+                       EndIf
+                       
+                       If KeyHit(key_t) Then tubes:+16; If tubes > 32 Then tubes = 0
+                       
+                       If KeyHit(KEY_ESCAPE) Then done = True;lv=-2
+                       Globalclock:+1
+                       Flip
+                       Delay 16                
+               Wend
+               
+               If lv > -1
+                       current_level = lv
+                       current_board = lv Mod 16
+                       current_color = lv/16
+                       
+                       SetUpLevel()
+                       SetUpEnemies()
+       
+                       superzapper = 2         
+                       MainPlayer.SetEdge(7)
+                       theLevel.state = LEVEL_BEGIN
+               EndIf
+               
+               Return done
+       
+       End Function
+       
+
+       Function DrawSmallLevel(lv,xoff,yoff,h)
+       
+               Local col = lv/16
+               current_color = col
+               Local b = lv Mod 16
+
+               Local sc# = 1.0         
+               Local x1,x2,y1,y2
+               Local c = leveldata[b+tubes,0]
+               CCenterY = leveldata[b+tubes,1]
+               YOFFSET =  leveldata[b+tubes,2]
+               
+               Color(COL_LEVEL)
+               If h And (Globalclock Mod 30 < 16) Then Color(Rand(0,7));sc = (Globalclock Mod 30)/20.0
+
+               For Local a = 0 Until 15
+                       x1 = Float(leveldata[b+tubes,3+a*2])/8*sc
+                       y1 = Float(leveldata[b+tubes,3+a*2+1])/8*sc
+                       x2 = Float(leveldata[b+tubes,3+a*2+2])/8*sc
+                       y2 = Float(leveldata[b+tubes,3+a*2+3])/8*sc
+                       DrawLine x1+xoff,y1+yoff,x2+xoff,y2+yoff
+               Next
+               If c
+                       x1 = Float(leveldata[b+tubes,3])/8*sc
+                       y1 = Float(leveldata[b+tubes,3+1])/8*sc
+                       DrawLine x1+xoff,y1+yoff,x2+xoff,y2+yoff
+               EndIf
+       
+               SetColor 0,255,0        
+               DrawString(b+1+16*col,xoff-5,yoff-50,2.0)
+
+               SetColor 255,0,0
+               Local l$ = (lv)*(3000+col*1000)+col*7000+((lv)>3)*(lv)*4000
+               Local ln = Len(l$)*5
+               DrawString(l$,xoff-ln,yoff+50,2.0)
+               
+       End Function
+
+
+       
+EndType
+
+
+
+Type Shot
+       Field e:edge  ' the edge its on
+       Field z#      ' its position
+       Field r#      ' rotation
+       Field xx#,yy#
+       
+       Method Draw()
+               Color(COL_BULLETS)
+
+               Local zz# = theLevel.depth-z+theLevel.position
+               Local sz# = TFormSZ(4,zz)
+               Local pxx#,pyy#
+               
+               xx = e.xx
+               yy = e.yy
+               
+               TForm(xx,yy,zz,pxx,pyy)
+               
+               For Local a=0 Until 360 Step 45
+                       SetRotation r+a
+                       DrawLine pxx+sz,pyy+sz,pxx-sz,pyy-sz
+               Next
+               r:+15
+               SetRotation 0
+       EndMethod
+
+       Method Update()
+               z:-6
+               Local bad:Baddies
+               If z<0
+                       SHOT_LIST.Remove(Self)
+                       Return
+               Else
+                       'check for collisions
+                       For bad = EachIn BADDIE_LIST
+                               If bad.CheckColl(e,z)
+                                       SHOT_LIST.Remove(Self)
+                                       Return
+                               EndIf
+                       Next
+               EndIf
+       EndMethod
+
+       Function Create:Shot(e:Edge, zPos)
+               Local ns:Shot = New Shot
+               ns.e = e
+               ns.xx =e.xx
+               ns.yy =e.yy
+               ns.z  = zPos '+5
+               SHOT_LIST.AddLast( ns )
+               Return ns
+       EndFunction
+
+       Function UpdateShots()
+               Local s:shot
+               For s=EachIn SHOT_LIST
+                       s.Update()
+               Next
+       EndFunction
+       
+       Function DrawShots()
+               Local s:shot
+               For s=EachIn SHOT_LIST
+                       s.Draw()
+               Next
+       EndFunction
+       
+EndType
+
+
+
+
+
+
+
+
+Type Explosion
+       Field x,y
+       Field cnt '60
+       Field scale#
+       
+       Method Draw()
+               Color(COL_BULLETS)
+               For Local t = 0 To 7
+                       Local xd = Sin(t*45)*Cos(cnt*3)*scale 
+                       Local yd = Cos(t*45)*Cos(cnt*3)*scale
+                       DrawLine x-xd,y-yd,x+xd,y+yd
+               Next
+       EndMethod
+
+       Method Update()
+               cnt:-3
+               If cnt < 0 Then EXPLOSION_LIST.Remove(Self)
+       EndMethod
+
+       Function Create:Explosion(x,y,height)
+               Local ex:Explosion = New Explosion 
+               ex.x = x
+               ex.y =y
+               ex.cnt = 30
+               ex.scale# = height/20
+               EXPLOSION_LIST.AddLast( ex )
+               Return ex
+       EndFunction
+
+       Function UpdateDrawExplosions()
+               Local s:Explosion
+               For s=EachIn EXPLOSION_LIST
+                       s.Update()
+               Next
+               For s=EachIn EXPLOSION_LIST
+                       s.Draw()
+               Next
+       EndFunction
+
+EndType
+
+
+
+
+
+' points displayed when a fuseball is shot
+' 250/500/750/1000
+Type fusepoint
+       Field x,y
+       Field cnt '60
+       Field scale#
+       Field pts$
+       
+       Method Draw()
+               Color(COL_BULLETS)
+               DrawString(pts,x,y,scale)       
+       EndMethod
+
+       Method Update()
+               cnt:-1
+               If cnt < 0 Then FUSEPOINT_LIST.Remove(Self)
+       EndMethod
+
+       Function Create:fusepoint(x,y,height,pt)
+               Local ex:fusepoint = New fusepoint
+               ex.cnt = 30
+               ex.pts = pt
+               ex.scale# = height/64+.5
+               ex.x = x -ex.scale*1.5
+               ex.y = y
+               FUSEPOINT_LIST.AddLast( ex )
+               Return ex
+       EndFunction
+
+       Function UpdateDrawFusePoints()
+               Local s:fusepoint
+               For s=EachIn FUSEPOINT_LIST
+                       s.Update()
+               Next
+               For s=EachIn FUSEPOINT_LIST
+                       s.Draw()
+               Next
+       EndFunction
+       
+EndType
+
+
+
+
+
+' enemies in the vortex!
+Type Egg
+       Field e_index
+       Field height
+       Field act
+       Field cnt
+       Field hdir
+       Field dir
+
+       Method DrawStats(x,y)
+               DrawText "i= "+e_Index+"  a="+act+" h="+Int(height)+" c="+cnt+" d="+hdir,x,y
+       End Method
+       
+       Method Hatch()
+               Local typ = -1
+               While typ < 0           
+                       ' turn it into a baddie
+                       typ = Rand(0,(7-(enemiesleft=0)*3))
+                       Select typ
+                               Case 0'flipper
+                                       If theLevel.hasflippers
+                                               flipper.Create(e_Index,0,0)
+                                       Else
+                                               typ = -1
+                                       EndIf
+                               Case 1'tank
+                                       If theLevel.hastankers
+                                               Local car = -1
+                                               While car < 0
+                                                       car = Rand(0,2)
+                                                       Select car
+                                                               Case 0
+                                                                       ' carry flippers
+                                                                       If theLevel.hasflippers
+                                                                               Tanker.Create(e_Index, Rand(1,2),0,0)                   
+                                                                       Else
+                                                                               car = -1
+                                                                       EndIf
+                                                               Case 1
+                                                                       ' carry fuseballs
+                                                                       If theLevel.hastankersf
+                                                                               Tanker.Create(e_Index, 0,0,Rand(1,2))                                                           
+                                                                       Else
+                                                                               car = -1
+                                                                       EndIf
+                                                               Case 2
+                                                                       ' carry pulsars
+                                                                       If theLevel.hastankersp
+                                                                               Tanker.Create(e_Index, 0,Rand(1,2),0)
+                                                                       Else
+                                                                               car = -1
+                                                                       EndIf
+                                                       End Select
+                                               Wend
+                                       Else
+                                               typ = -1
+                                       EndIf
+                               Case 4,5,6,7'spinner
+                                       If theLevel.hasspikes
+                                               spinner.Create( e_Index ,Rand(2.0,4.0))
+                                       Else
+                                               typ = -1
+                                       EndIf
+                               Case 2'fuseball
+                                       If theLevel.hasfuseballs
+                                               fuseball.Create(e_Index,0,0)
+                                       Else
+                                               typ = -1
+                                       EndIf
+                               Case 3'pulsar
+                                       If theLevel.haspulsars
+                                               Pulsar.Create(e_Index,0,0)                      
+                                       Else
+                                               typ = -1
+                                       EndIf           
+                       End Select
+               Wend
+               EGG_LIST.Remove(Self)
+       End Method
+               
+       Method Update()
+       
+               Select act
+                       Case 0 'move from edge to edge
+                               cnt:+1
+                               If cnt > 7
+                                       height:+hdir
+                                       If height >= -1 Or height <= -20 Or Rand(0,100) > 95 Then hdir=-hdir 
+                                       cnt = 0
+                                       If dir = 1
+                                               If e_Index=theLevel.e_cnt-1
+                                                       If theLevel.continuous
+                                                               e_Index = 0
+                                                       Else
+                                                               dir = 1-dir
+                                                       EndIf
+                                               Else
+                                                       e_Index:+1
+                                               EndIf
+                                       Else
+                                               If e_Index = 0
+                                                       If theLevel.continuous
+                                                               e_Index = theLevel.e_Cnt-1
+                                                       Else
+                                                               dir = 1-dir
+                                                       EndIf
+                                               Else
+                                                       e_Index:-1
+                                               EndIf
+                                       EndIf
+                                       If theLevel.state=LEVEL_READY
+                                               If Rand(0,100) > 95-hatchrate
+                                                       If enemiesleft + hatchingeggs < 12
+                                                               act = 1
+                                                               hatchingeggs:+1
+                                                       EndIf
+                                               EndIf
+                                       EndIf
+                               EndIf
+                       Case 1 'move towards web
+                               cnt:+1
+                               If cnt > 7
+                                       height:+1
+                                       If height >= 0 Then act = 2
+                                       cnt=0
+                               EndIf
+                       Case 2 'hatch
+                               hatch()
+                               hatchingeggs:-1
+               End Select
+       
+       End Method
+       
+       Method Draw()
+       
+               Local zz# = theLevel.depth-height*20+theLevel.position
+               Local pxx#,pyy#
+               Local xx# = theLevel.Edges[e_Index].xx
+               Local yy# = theLevel.Edges[e_Index].yy
+               
+               TForm(xx,yy,zz,pxx,pyy)
+               Color(COL_FLIPPERS)
+               Plot(pxx,pyy)
+               
+       End Method
+       
+       Function Create:Egg(index)
+               Local e:Egg = New Egg
+               e.e_index = index
+               e.height = -10
+               e.cnt = 0
+               e.act = 0
+               e.hdir = 1
+               e.dir = Rand(0,1)
+               EGG_LIST.AddLast( e )
+               Return e
+       EndFunction
+
+       Function UpdateEggs()
+               Local e:egg
+               For e = EachIn EGG_LIST
+                       e.Update()
+               Next
+       EndFunction
+       
+       Function DrawEggs()
+               Local e:egg
+               Local cnt = 0
+               For e = EachIn EGG_LIST
+                       e.Draw()
+                       If showdebug Then e.DrawStats(400,cnt*12)               
+                       cnt = cnt + 1
+               Next
+       EndFunction
+       
+End Type
+
+
+
+
+
+
+
+
+Type Baddies
+       Field OnEdge:Edge
+       Field e_Index  'used to traverse theLevel edgelist
+       Field baddietype = 0
+       Field dietime = 0
+       Field height#
+       
+       Method Draw() Abstract
+       Method DrawStats(x,y) Abstract
+       Method Zapit(t) Abstract
+       Method Update() Abstract
+       Method CheckColl(e:edge,z#) Abstract 'shots->enemy
+       Method CheckPlayerColl() Abstract 'enemy->player
+       
+       Function UpdateBaddies()
+               onrim = True
+               Local b:Baddies
+               For b = EachIn BADDIE_LIST
+                       If theLevel.state = LEVEL_ZOOMING Or theLevel.state = LEVEL_REVERSE_ZOOM
+                               If b.baddietype = BAD_SPIKE Then b.Update() ' only spikes
+                       Else
+                               b.Update()
+                               If b.baddietype > BAD_SPIKE 
+                                       If b.height < 400
+                                               onrim = False
+                                       EndIf                           
+                               EndIf           
+                       EndIf
+               Next
+               For b = EachIn BADDIE_LIST
+                       If theLevel.state = LEVEL_ZOOMING Or theLevel.state = LEVEL_REVERSE_ZOOM
+                               If b.baddietype = BAD_SPIKE Then b.CheckPlayerColl()' only spikes
+                       Else
+                               If theLevel.state <> LEVEL_PLAYER_DYING Then b.CheckPlayerColl()        
+                       EndIf
+               Next
+       EndFunction
+       
+       Function DrawBaddies()
+               Local b:Baddies
+               Local cnt = 0 
+               For b = EachIn BADDIE_LIST
+                       If theLevel.state = LEVEL_ZOOMING Or theLevel.state = LEVEL_REVERSE_ZOOM
+                               If b.baddietype = BAD_SPIKE ' only spikes kill when zooming
+                                       b.Draw()
+                                       If showdebug Then b.DrawStats(10,cnt*12)
+                               EndIf
+                       Else
+                               b.Draw()
+                               If showdebug Then b.DrawStats(10,cnt*12)
+                       EndIf
+                       cnt:+1
+               Next
+       EndFunction
+       
+       Function ConvertBaddieToEggs()
+               ' player just died - reset the enemies to eggs
+               enemiesleft = 0
+               Local b:Baddies
+               For b = EachIn BADDIE_LIST
+                       If b.baddietype > BAD_SPIKE  ' non spikes or bullets
+                               BADDIE_LIST.Remove(b)
+                               ' eggs yet to be created + live eggs
+                               If eggsleft + CountList(EGG_LIST) < maxeggs
+                                       eggsleft:+1
+                               EndIf
+                       Else
+                               If b.baddietype = BAD_BULLET  'remove bullets, keep spikes
+                                       BADDIE_LIST.Remove(b)
+                               EndIf
+                       EndIf
+               Next
+               ' only strat with max 16 eggs
+               If CountList(EGG_LIST) > 16
+                       eggsleft:+(CountList(EGG_LIST)-16)
+                       Local cnt = 0
+                       For Local e:egg = EachIn EGG_LIST
+                               cnt:+1
+                               If cnt > 16
+                                       EGG_LIST.Remove(e)
+                               EndIf
+                       Next
+               EndIf
+       End Function
+       
+       Function SuperZapit(strength)
+       
+               Local b:Baddies
+               Local cnt = 4
+               If strength = 2
+                       ' zap them all
+                       superzapperdisplay = 60
+                       For b = EachIn BADDIE_LIST
+                               If b.baddietype <> 1
+                                       If b.Zapit(cnt) Then cnt = cnt + 2
+                               EndIf
+                       Next
+               Else
+                       ' find biggest threat and kill it
+                       Local i = mainplayer.e_index
+                       Local b_best:baddies = Null
+                       Local best_d = 16
+                       Local best_h = 0
+                       Local best_b = 0
+                       For b = EachIn BADDIE_LIST
+                               If b.baddietype > 1
+                                       Local d
+                                       If theLevel.continuous
+                                               d = -(i - b.e_index) 'how far from player
+                                               If Abs(d) > 8 Then d = -d
+                                       Else
+                                               d = -(i - b.e_index)
+                                       EndIf
+                                       d = Abs(d)
+                                       If d < best_d+2
+                                               If b.height > best_h
+                                                       b_best = b
+                                                       best_d = d
+                                                       best_h = b.height
+                                                       best_b = b.baddietype
+'                                                      DebugLog("b="+b.baddietype+" i="+b.e_index+" d="+d+" h="+b.height)
+                                               Else
+                                                       If d < best_d
+                                                               b_best = b
+                                                               best_d = d
+                                                               best_h = b.height
+                                                               best_b = b.baddietype                                                   
+'                                                              DebugLog("+ b="+b.baddietype+" i="+b.e_index+" d="+d+" h="+b.height)
+                                                       Else
+                                                               ' same d, pick the meaner one
+                                                               If b.baddietype > best_b
+                                                                       b_best = b
+                                                                       best_d = d
+                                                                       best_h = b.height
+                                                                       best_b = b.baddietype                                                   
+'                                                                      DebugLog("++ b="+b.baddietype+" i="+b.e_index+" d="+d+" h="+b.height)
+                                                               EndIf
+                                                       EndIf
+                                               EndIf
+                                       EndIf
+                               EndIf
+                       Next
+                       If b_best <> Null
+'                              DebugLog("Zap b="+b_best.baddietype+" i="+b_best.e_index+" d="+best_d+" h="+best_h)                     
+                               b_best.Zapit(4)
+                               superzapperdisplay = 60                 
+                       EndIf
+
+               EndIf
+       
+       End Function
+       
+EndType
+
+
+Type Bullets Extends Baddies
+       Field height# ' its position
+       Field r#      ' rotation
+       Field xx#,yy#
+       
+       Method Draw()
+               Color(COL_BULLETS)
+               Local zz# = theLevel.depth-height+theLevel.position
+               Local sz# = TFormSZ(6,zz)
+               Local pxx#,pyy#
+               
+               xx = onEdge.xx
+               yy = onEdge.yy
+               
+               TForm(xx,yy,zz,pxx,pyy)
+               
+               For Local a=0 Until 360 Step 45
+                       SetRotation r+a
+                       DrawLine pxx+sz,pyy,pxx-sz,pyy
+               Next
+               r:+15
+               SetRotation 0
+       EndMethod
+
+       Method Update()
+               height:+3
+               If height > theLevel.depth
+                       BADDIE_LIST.Remove(Self)
+                       Return
+               EndIf
+       EndMethod
+
+       Method CheckColl(e:edge,z#)
+               If e = OnEdge
+                       If z < height
+                               MainPlayer.Score = MainPlayer.Score+25
+                               BADDIE_LIST.Remove(Self)
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+       
+       Method CheckPlayerColl()
+               If MainPlayer.e_Index = e_index
+                       If theLevel.depth-height < 8
+                               PlaySound(killedbybulletsfx)
+                               BADDIE_LIST.Remove(Self)
+                               KillPlayer(KILLED_BY_BULLET)
+                               Return
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method DrawStats(x,y)
+       End Method
+
+       Method ZapIt(t)
+               Return False
+       End Method
+       
+       Function Create:Bullets(index, depth)
+               PlaySound(bulletsfx)
+               Local b:Bullets = New Bullets
+               b.OnEdge = theLevel.edges[index]
+               b.e_Index= index
+               b.xx = b.onEdge.xx
+               b.yy = b.onEdge.yy
+               b.height = depth
+               b.baddietype = BAD_BULLET
+               BADDIE_LIST.AddLast b
+               Return b
+       EndFunction
+       
+EndType
+
+
+
+
+Type Tanker Extends Baddies
+       Field cargo_flipper             'flipper,pulsar,fuseball  1 or 2 of them
+       Field cargo_pulsar
+       Field cargo_fuseball
+       Field xx#,yy#
+       Field hasbullets
+       
+       Method Draw()
+               Color(COL_TANKERS)
+               Local x#[2],y#[2]
+               Local zz# = theLevel.depth-height+theLevel.position
+               xx = onEdge.xx
+               yy = onEdge.yy
+
+               TForm(xx,yy,zz,x[0],y[0])
+               Local scale# '= height/theLevel.depth*24.0+1
+               scale = TFormSZ(26,zz)+1
+               
+               Local scale3# = scale/3
+               DrawLine x[0],y[0]-scale3,x[0]-scale,y[0]
+               DrawLine x[0],y[0]-scale,x[0]+scale3,y[0]
+               DrawLine x[0],y[0]+scale,x[0]-scale3,y[0]
+               DrawLine x[0],y[0]+scale3,x[0]+scale,y[0]
+
+               DrawLine x[0],y[0]+scale,x[0]+scale,y[0]
+               DrawLine x[0],y[0]+scale,x[0]-scale,y[0]
+               DrawLine x[0],y[0]-scale,x[0]+scale,y[0]
+               DrawLine x[0],y[0]-scale,x[0]-scale,y[0]
+
+               DrawLine x[0],y[0]+scale3,x[0]+scale3,y[0]
+               DrawLine x[0],y[0]+scale3,x[0]-scale3,y[0]
+               DrawLine x[0],y[0]-scale3,x[0]+scale3,y[0]
+               DrawLine x[0],y[0]-scale3,x[0]-scale3,y[0]
+
+               DrawLine x[0],y[0]+scale3,x[0],y[0]+scale
+               DrawLine x[0],y[0]-scale3,x[0],y[0]-scale
+               DrawLine x[0]+scale3,y[0],x[0]+scale,y[0]
+               DrawLine x[0]-scale3,y[0],x[0]-scale,y[0]
+               
+               If cargo_fuseball
+                       'draw fuse in the middle
+                       Color(COL_FLIPPERS)
+                       DrawLine x[0],y[0],x[0],y[0]+scale3
+                       Color(COL_SPIKERS)
+                       DrawLine x[0],y[0],x[0],y[0]-scale3
+                       Color(COL_PULSARS)
+                       DrawLine x[0],y[0],x[0]+scale3,y[0]
+                       Color(COL_CLAW)
+                       DrawLine x[0],y[0],x[0]-scale3,y[0]                     
+               Else
+                       If cargo_pulsar
+                               'draw pulsar in the middle
+                               Color(COL_PULSARS)
+                               DrawLine x[0]-scale3,y[0],x[0],y[0]+scale3/2
+                               DrawLine x[0],y[0]+scale3/2,x[0],y[0]-scale3/2
+                               DrawLine x[0],y[0]-scale3/2,x[0]+scale3,y[0]
+                       EndIf
+               EndIf
+       EndMethod
+       
+       Method ReleaseCargo(stillborn)
+               If cargo_flipper > 0
+                       Local dir = 1-Rand(0,1)*2
+                       For Local d = 1 To cargo_flipper
+                               Local e = e_index
+                               If dir = 1
+                                       If e=0
+                                               If theLevel.continuous
+                                                       e = theLevel.e_Cnt-1
+                                               EndIf
+                                       Else
+                                               e:-1
+                                       EndIf
+                               Else
+                                       If e=theLevel.e_cnt-1
+                                               If theLevel.continuous
+                                                       e = 0
+                                               EndIf
+                                       Else
+                                               e:+1
+                                       EndIf
+                               EndIf                           
+                               Local c:flipper = flipper.Create(e,1,height)
+                               c.dir = -dir
+                               If stillborn Then c.dietime = 8
+                               dir = -dir
+                       Next
+               EndIf
+               If cargo_fuseball > 0
+                       Local dir = 1-Rand(0,1)*2
+                       For Local d = 1 To cargo_fuseball 
+                               Local e = e_index
+                               If dir = 1                      
+                                       If e=0
+                                               If theLevel.continuous
+                                                       e = theLevel.e_Cnt-1
+                                               EndIf
+                                       Else
+                                               e:-1
+                                       EndIf
+                               Else
+                                       If e=theLevel.e_cnt-1
+                                               If theLevel.continuous
+                                                       e = 0
+                                               EndIf
+                                       Else
+                                               e:+1
+                                       EndIf
+                               EndIf                           
+                               Local c:fuseball= fuseball.Create(e,0,height)
+                               c.dir = -dir
+                               If stillborn Then c.dietime = 8                         
+                               dir = -dir
+                       Next
+               EndIf
+               If cargo_pulsar > 0
+                       Local dir = 1-Rand(0,1)*2
+                       For Local d = 1 To cargo_pulsar 
+                               Local e = e_index
+                               If dir = 1                      
+                                       If e=0
+                                               If theLevel.continuous
+                                                       e = theLevel.e_Cnt-1
+                                               EndIf
+                                       Else
+                                               e:-1
+                                       EndIf
+                               Else
+                                       If e=theLevel.e_cnt-1
+                                               If theLevel.continuous
+                                                       e = 0
+                                               EndIf
+                                       Else
+                                               e:+1
+                                       EndIf
+                               EndIf                           
+                               Local c:pulsar = pulsar.Create(e,0,height)
+                               c.dir = -dir
+                               If stillborn Then c.dietime = 8                                                         
+                               dir = -dir
+                       Next
+               EndIf
+       EndMethod
+       
+       Method ZapIt(t)
+               dietime = t 'die after t tics
+               Return True
+       End Method
+       
+       Method Update()
+               If dietime > 0
+                       dietime:-1
+                       If dietime = 0 'die
+                               PlaySound(zapsfx,zapchan)
+                               Local xx#,yy#,zz1#
+                               MainPlayer.Score = MainPlayer.Score+200
+                               ReleaseCargo(True) ' it's cargo will die too
+                               zz1 = theLevel.position + theLevel.depth - height
+                               TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)
+                               Explosion.Create(xx,yy,height)                          
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1
+                               Return          
+                       EndIf
+               EndIf
+               height:+2
+               If height < 380
+                       If Rand(0,100) > 98 And hasbullets Then bullets.Create(e_index,height);hasbullets:-1
+               EndIf
+               If height > theLevel.depth-15
+                       ReleaseCargo(False)
+                       BADDIE_LIST.Remove(Self)
+                       enemiesleft:-1
+               EndIf
+       EndMethod
+
+       Method CheckColl(e:edge,z#)
+               If e = OnEdge
+                       If z < height
+                               Local xx#,yy#,zz1#
+                               MainPlayer.Score = MainPlayer.Score+200
+                               ReleaseCargo(False)
+                               zz1 = theLevel.position + theLevel.depth - height
+                               TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)
+                               Explosion.Create(xx,yy,height)  
+                               PlaySound(tankershotsfx)                        
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method CheckPlayerColl()
+               Return False
+       EndMethod       
+
+       Method DrawStats(x,y)
+               Color(COL_TANKERS)
+               DrawText "i= "+e_Index+" h="+Int(height)+" f="+cargo_flipper+" b="+cargo_fuseball+" p="+cargo_pulsar ,x,y       
+       End Method
+
+       Function Create:Tanker(index, numc,nump,numf)
+               Local t:Tanker = New Tanker
+               t.OnEdge = theLevel.edges[index]
+               t.cargo_flipper = numc
+               t.cargo_pulsar = nump
+               t.cargo_fuseball = numf
+               t.e_Index= index
+               t.xx = t.onEdge.xx
+               t.yy = t.onEdge.yy
+               t.height = 10
+               t.hasbullets = Rand(1,2)
+               t.baddietype = BAD_TANKER
+               BADDIE_LIST.AddLast t
+               enemiesleft:+1
+               Return t
+       EndFunction
+       
+EndType
+
+
+
+
+Type Flipper Extends Baddies
+       Field typ       '0 just slides up the tube
+                       '1 flips round the tube
+                                       '2 flipping on rim
+                                       '3 pausing
+       Field oldtyp
+       Field hasbullets
+       
+       Field Pause     'the pause before changing edge
+       Field dir       'direction left or right
+       Field angle#     'the angle when changing lanes
+       Field totangle#  ' the total angle to flip
+
+       Method DrawStats(x,y)
+               Color(COL_FLIPPERS)
+               DrawText "i= "+e_Index+"  d="+dir+" h="+Int(height)+" a="+Int(angle)+" t="+Int(totangle) ,x,y
+       End Method
+       
+       Method Draw()
+               Local xx#,yy#,zz1#,zz2#
+               Local x#[7],y#[7]
+               Select typ
+               Case 0 ' sliding up
+                       zz1 = theLevel.position+theLevel.depth
+                       zz2 = zz1 - height
+                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+               Case 1,2 ' flipping
+                       zz1 = theLevel.position+theLevel.depth
+                       zz2 = zz1 - height
+                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+                       If dir = -1 'pivot around p1 of dest edge  (current edge+1)
+                               TFormR(x[1],y[1],-angle+totangle, x[0],y[0])    
+                       Else
+                               TFormR(x[0],y[0],-(totangle-angle), x[1],y[1])                          
+                       EndIf                   
+               Case 3,7 'delaying
+                       zz1 = theLevel.position+theLevel.depth
+                       zz2 = zz1 - height
+                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+               End Select
+               
+               Local xn#
+               Local yn#
+               Local zh#' =  height/(theLevel.position+theLevel.depth)*24
+               zh = TFormSZ(20,zz2)
+
+               Local xd# = x[1]-x[0]
+               Local yd# = y[1]-y[0]
+               Local sz# = Sqr(xd*xd + yd*yd)
+               If sz = 0
+                       xn# = 0
+                       yn# = 0
+               Else
+                       xn# = -yd/sz
+                       yn# = xd/sz
+               EndIf
+               x[2] = x[1]-(xd)*0.3 - xn*zh/2
+               y[2] = y[1]-(yd)*0.3 - yn*zh/2
+               
+               x[3] = x[1]-(xd)*0.1 - xn*zh
+               y[3] = y[1]-(yd)*0.1 - yn*zh
+               
+               x[5] = x[1]-(xd)*0.9 - xn*zh
+               y[5] = y[1]-(yd)*0.9 - yn*zh
+               
+               x[6] = x[1]-(xd)*0.7 - xn*zh/2
+               y[6] = y[1]-(yd)*0.7 - yn*zh/2
+               
+               Color(COL_FLIPPERS)
+               DrawLine x[0],y[0],x[3],y[3]
+               DrawLine x[5],y[5],x[1],y[1]
+               DrawLine x[6],y[6],x[5],y[5]
+               DrawLine x[2],y[2],x[3],y[3]
+
+               DrawLine x[6],y[6],x[0],y[0]
+               DrawLine x[2],y[2],x[1],y[1]
+               
+       EndMethod
+
+       Method ZapIt(t)
+               dietime = t 'die after t tics
+               Return True
+       End Method
+       
+       Method Update()
+               If dietime > 0
+                       dietime:-1
+                       If dietime = 0 'die
+                               PlaySound(zapsfx,zapchan)
+                               Local xx#,yy#,zz1#
+                               zz1 = theLevel.position + theLevel.depth - height
+                               TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)
+                               Explosion.Create(xx,yy,height)
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1                          
+                               MainPlayer.Score = MainPlayer.Score+150
+                               Return          
+                       EndIf
+               EndIf
+               Select typ
+               Case 0 ' sliding up
+                       If onEdge.Spike
+                               If height < OnEdge.Spike.height
+                                       height:+2
+                               Else
+                                       oldtyp = 1
+                                       typ = 3
+                               EndIf
+                       Else
+                               If height < theLevel.Depth
+                                       height:+1
+                                       If canflip Then oldtyp=1;typ = 3
+                               Else
+                                       height = theLevel.Depth
+                                       oldtyp=2
+                                       typ = 3
+                               EndIf
+                       EndIf
+                       If Rand(0,100) > 98 And hasbullets Then bullets.Create(e_index,height);hasbullets:-1
+                       dir = FindShortDir(e_Index, MainPlayer.e_Index)
+               Case 1,2 ' flipping
+                       angle = angle + flipflipspeed
+                       If typ = 1
+                               If height < theLevel.Depth
+                                       height:+1
+                               Else
+                                       height = theLevel.Depth
+                               EndIf   
+                       EndIf
+                       totangle = theLevel.edges[e_Index].angle'-8
+                       If dir = -1
+                               Local ind = e_index-1
+                               If ind < 0 Then ind = theLevel.e_cnt-1
+                               totangle = theLevel.edges[ind].angle
+                       EndIf
+                       If angle >= totangle
+                               angle = 0
+                               If height < theLevel.Depth
+                                       oldtyp = 1
+                                       typ = 3
+                               Else
+                                       oldtyp = 2 ' return to rim case, not climbing
+                                       typ = 3
+                               EndIf                           
+                               pause = 20
+                       EndIf                           
+               Case 3 'delaying
+                       pause :-1
+                       If height < theLevel.Depth
+                               height:+1
+                       Else
+                               height = theLevel.Depth
+                       EndIf
+                       If pause <= 0
+                               typ = oldtyp                            
+
+                               If height >= theLevel.depth Then dir = FindShortDir(e_Index, MainPlayer.e_Index)
+
+                               If theLevel.continuous = False
+                                       If e_index - dir < 0 Or e_index - dir > theLevel.e_cnt-1
+                                               dir = -dir
+                                       EndIf
+                               EndIf
+                               'move to next edge
+                               If dir = 1                      
+                                       If e_Index=0
+                                               If theLevel.continuous
+                                                       e_Index= theLevel.e_Cnt-1
+                                               Else
+                                                       dir = -dir
+                                               EndIf
+                                       Else
+                                               e_Index:-1
+                                       EndIf
+                               Else
+                                       If e_Index=theLevel.e_cnt-1
+                                               If theLevel.continuous
+                                                       e_Index= 0
+                                               Else
+                                                       dir = -dir
+                                               EndIf
+                                       Else
+                                               e_Index:+1
+                                       EndIf
+                               EndIf                           
+                               OnEdge = theLevel.edges[e_Index]
+                               totangle = theLevel.edges[e_Index].angle'-8     
+                               
+                               If Rand(0,100) > 98 And hasbullets Then bullets.Create(e_index,height);hasbullets:-1
+
+                               If dir = -1
+                                       Local ind = e_index-1
+                                       If ind < 0 Then ind = theLevel.e_cnt-1
+                                       totangle = theLevel.edges[ind].angle '-8
+                               EndIf
+                               If onEdge.Spike
+                                       If height < OnEdge.Spike.height
+                                               typ = 0
+                                       EndIf
+                               Else
+                                       typ = oldtyp
+                               EndIf
+                               
+                       EndIf
+               Case 7 'killing player!
+                       'If height> 0 Then height:-3
+               End Select
+       EndMethod
+
+       Method CheckColl(e:edge,z#)
+               Local sp# = height-z
+               If e = OnEdge
+                       If sp < 16 And sp > 0
+                               Local xx#,yy#,zz1#,x#[2],y#[2]
+                               If typ = 1 Or typ = 2
+                                       zz1 = theLevel.position+theLevel.depth-height
+                                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz1,x[0],y[0])
+                                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz1,x[1],y[1])
+                                       If dir = -1 'pivot around p1 of dest edge  (current edge+1)
+                                               TFormR(x[1],y[1],-angle+totangle, x[0],y[0])    
+                                       Else
+                                               TFormR(x[0],y[0],-(totangle-angle), x[1],y[1])                          
+                                       EndIf
+                                       xx = (x[0]+x[1])/2
+                                       yy = (y[0]+y[1])/2
+                               Else
+                                       zz1 = theLevel.position + theLevel.depth - height
+                                       TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)            
+                               EndIf
+                               PlaySound(flippershotsfx)
+                               Explosion.Create(xx,yy,height)
+                               BADDIE_LIST.Remove(Self)
+                               MainPlayer.Score = MainPlayer.Score+150
+                               enemiesleft:-1
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method CheckPlayerColl()
+               If MainPlayer.e_Index = e_index
+                       If theLevel.depth = height
+                               If typ <> 1 And typ <> 2
+                                       typ=7
+                                       PlaySound(killedbyflippersfx)
+                                       KillPlayer(KILLED_BY_FLIPPER)
+                                       Return True
+                               Else
+                                       If Abs(totangle-angle) < 30
+                                               typ=7
+                                               PlaySound(killedbyflippersfx)                                           
+                                               KillPlayer(KILLED_BY_FLIPPER)
+                                               Return True             
+                                       EndIf                                   
+                               EndIf
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Function Create:flipper(index,typ = 0,height)
+               Local c:flipper = New flipper
+               c.OnEdge = theLevel.edges[index]
+               c.e_Index= index
+               c.typ    = typ
+               c.height = height
+               c.hasbullets = Rand(1,3)
+               c.baddietype = BAD_FLIPPER
+               BADDIE_LIST.AddLast c
+               enemiesleft:+1          
+               Return c
+       EndFunction
+       
+EndType
+
+
+
+
+Type Pulsar Extends Baddies
+       Field typ               
+       Field oldtyp
+       Field canflip = True
+       Field timetoflip = 0
+       
+       Field Pause     'the pause before changing edge
+       Field dir       'direction left or right
+       Field hdir
+       Field angle#     'the angle when changing lanes
+       Field totangle#
+
+       Method DrawStats(x,y)
+               Color(COL_PULSARS)
+               DrawText "i= "+e_Index+"  d="+dir+" h="+Int(height)+" a="+Int(typ)+" t="+Int(timetoflip) ,x,y
+       End Method
+       
+       Method Draw()
+               Local xx#,yy#,zz1#,zz2#
+               Local x#[7],y#[7]
+               Select typ
+               Case 0,4 ' sliding up/down
+                       zz1 = theLevel.position+theLevel.depth
+                       zz2 = zz1 - height
+                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+               Case 1,2 ' flipping
+                       zz1 = theLevel.position+theLevel.depth
+                       zz2 = zz1 - height
+                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+                       If dir = -1 'pivot around p1 of dest edge  (current edge+1)
+                               TFormR(x[1],y[1],-angle+totangle, x[0],y[0])    
+                       Else
+                               TFormR(x[0],y[0],-(totangle-angle), x[1],y[1])                          
+                       EndIf                   
+               Case 3,5,7 'delaying
+                       zz1 = theLevel.position+theLevel.depth
+                       zz2 = zz1 - height
+                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+               End Select
+               
+               Local xn#
+               Local yn#
+               Local zh# = pulse_zh#
+
+               Local xd# = x[1]-x[0]
+               Local yd# = y[1]-y[0]
+               Local sz# = Sqr(xd*xd + yd*yd)
+               If sz = 0
+                       xn# = 0
+                       yn# = 0
+               Else
+                       xn# = -yd/sz
+                       yn# = xd/sz
+               EndIf
+               x[2] = x[1]-(xd)*0.2 - xn*zh
+               y[2] = y[1]-(yd)*0.2 - yn*zh
+               x[3] = x[1]-(xd)*0.35 + xn*zh
+               y[3] = y[1]-(yd)*0.35 + yn*zh
+               x[4] = x[1]-(xd)*0.5 - xn*zh
+               y[4] = y[1]-(yd)*0.5 - yn*zh
+               x[5] = x[1]-(xd)*0.65 + xn*zh
+               y[5] = y[1]-(yd)*0.65 + yn*zh
+               x[6] = x[1]-(xd)*0.8 - xn*zh
+               y[6] = y[1]-(yd)*0.8 - yn*zh
+               
+               If pulsing
+                       Color(COL_BULLETS)
+               Else
+                       Color(COL_PULSARS)
+               EndIf
+               DrawLine x[1],y[1],x[2],y[2]
+               DrawLine x[2],y[2],x[3],y[3]
+               DrawLine x[3],y[3],x[4],y[4]
+               DrawLine x[4],y[4],x[5],y[5]
+               DrawLine x[5],y[5],x[6],y[6]
+               DrawLine x[6],y[6],x[0],y[0]
+               
+       EndMethod
+       
+       Method ZapIt(t)
+               dietime = t 'die after t tics
+               Return True
+       End Method
+       
+       Method Update()
+               If dietime > 0
+                       dietime:-1
+                       If dietime = 0 'die
+                               PlaySound(zapsfx,zapchan)
+                               Local xx#,yy#,zz1#
+                               zz1 = theLevel.position + theLevel.depth - height
+                               TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)
+                               Explosion.Create(xx,yy,height)
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1                          
+                               MainPlayer.Score = MainPlayer.Score+200
+                               Return          
+                       EndIf
+               EndIf
+               onEdge.haspulser = True
+               OnEdge.pulsing = pulsing
+               timetoflip:+1
+               Select typ
+               Case 0 ' sliding up
+                       If height < theLevel.Depth
+                               height:+1
+                               If timetoflip > 50
+                                       If Rand(0,1)
+                                               oldtyp=1;typ = 3
+                                       Else
+                                               oldtyp=0;typ = 5
+                                       EndIf
+                                       timetoflip = 0
+                               EndIf
+                       Else
+                               ' reached the top , go down or flip?
+                               height = theLevel.Depth
+                               If Rand(0,1) Or rimit
+                                       'flip 
+                                       oldtyp=1;typ = 3
+                               Else
+                                       'go down
+                                       oldtyp=4;typ = 5
+                               EndIf
+                               timetoflip = 0
+                       EndIf
+                       pause = 20
+                       dir = FindShortDir(e_Index, MainPlayer.e_Index)
+               Case 4 ' sliding down
+                       If height > 0
+                               height:-1
+                               If timetoflip > 50
+                                       If Rand(0,1) 
+                                               oldtyp=1;typ = 3
+                                       Else
+                                               oldtyp=4;typ = 5
+                                       EndIf
+                                       timetoflip = 0
+                               EndIf
+                       Else
+                               ' reached the bottom
+                               height = 0
+                               If Rand(0,1)
+                                       'flip
+                                       oldtyp=1;typ = 3
+                               Else
+                                       'go up
+                                       oldtyp=0;typ = 5
+                               EndIf
+                               timetoflip = 0                                                          
+                       EndIf
+                       pause = 20
+                       dir = FindShortDir(e_Index, MainPlayer.e_Index)
+               Case 1,2 ' flipping
+                       angle = angle + pulseflipspeed
+                       If typ = 1
+                               If height < theLevel.Depth
+                                       height:+1
+                               Else
+                                       height = theLevel.Depth
+                               EndIf   
+                       EndIf
+                       totangle = theLevel.edges[e_Index].angle'-8
+                       If dir = -1
+                               Local ind = e_index-1
+                               If ind < 0 Then ind = theLevel.e_cnt-1
+'                              If ind > theLevel.e_cnt-1 Then ind = 0
+                               totangle = theLevel.edges[ind].angle '-8
+                       EndIf
+                       If angle >= totangle
+                               angle = 0
+                               If height < theLevel.Depth
+                                       oldtyp = 0
+                                       typ = 5
+                               Else
+                                       oldtyp = 0 'made it to the rim
+                                       typ = 5
+                               EndIf                           
+                               pause = 20
+                       EndIf                           
+               Case 5 'delaying 2
+                       pause :-1
+                       If pause <= 0
+                               timetoflip = 0
+                               typ = oldtyp
+                       EndIf
+               Case 3 'delaying
+                       pause :-1
+                       If pause <= 0
+                               timetoflip = 0
+                               typ = oldtyp
+                               
+                               If theLevel.continuous = False
+                                       If e_index - dir < 0 Or e_index - dir > theLevel.e_cnt-1
+                                               dir = -dir
+                                       EndIf
+                               EndIf
+                               'move to next edge
+                               If dir = 1                      
+                                       If e_Index=0
+                                               If theLevel.continuous
+                                                       e_Index= theLevel.e_Cnt-1
+                                               Else
+                                                       dir = -dir
+                                               EndIf
+                                       Else
+                                               e_Index:-1
+                                       EndIf
+                               Else
+                                       If e_Index=theLevel.e_cnt-1
+                                               If theLevel.continuous
+                                                       e_Index= 0
+                                               Else
+                                                       dir = -dir
+                                               EndIf
+                                       Else
+                                               e_Index:+1
+                                       EndIf
+                               EndIf                           
+                               OnEdge = theLevel.edges[e_Index]
+                               totangle = theLevel.edges[e_Index].angle'-8                     
+                               If dir = -1
+                                       Local ind = e_index-1
+                                       If ind < 0 Then ind = theLevel.e_cnt-1
+                                       totangle = theLevel.edges[ind].angle '-8
+                               EndIf
+                       EndIf
+               Case 7 'killing player!
+                       'If height> 0 Then height:-3
+               End Select
+               pulsesalive = True
+       EndMethod
+
+       Method CheckColl(e:edge,z#)
+               Local sp# = height-z
+               If e = OnEdge
+                       If sp < 16 And sp > 0
+                               Local xx#,yy#,zz1#,x#[2],y#[2]
+                               If typ = 1 Or typ = 2
+                                       zz1 = theLevel.position+theLevel.depth-height
+                                       TForm(OnEdge.p1.x,OnEdge.p1.y,zz1,x[0],y[0])
+                                       TForm(OnEdge.p2.x,OnEdge.p2.y,zz1,x[1],y[1])
+                                       If dir = -1 'pivot around p1 of dest edge  (current edge+1)
+                                               TFormR(x[1],y[1],-angle+totangle, x[0],y[0])    
+                                       Else
+                                               TFormR(x[0],y[0],-(totangle-angle), x[1],y[1])                          
+                                       EndIf
+                                       xx = (x[0]+x[1])/2
+                                       yy = (y[0]+y[1])/2
+                               Else
+                                       zz1 = theLevel.position + theLevel.depth - height
+                                       TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)            
+                               EndIf
+                               Explosion.Create(xx,yy,height)
+                               PlaySound(pulsarshotsfx)                        
+                               BADDIE_LIST.Remove(Self)
+                               MainPlayer.Score = MainPlayer.Score+200
+                               enemiesleft:-1                          
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method CheckPlayerColl()
+               If MainPlayer.e_Index = e_index
+                       If theLevel.depth-height < 8
+                               If typ <> 1 And typ <> 2
+                                       PlaySound(killedbypulsarsfx)
+                                       KillPlayer(KILLED_BY_FLIPPER)
+                                       typ = 7
+                                       Return True
+                               Else
+                                       If Abs(totangle-angle) < 30
+                                               PlaySound(killedbypulsarsfx)
+                                               KillPlayer(KILLED_BY_FLIPPER)
+                                               typ = 7
+                                               Return True             
+                                       EndIf
+                               EndIf
+                       Else
+                               If typ <> 1 And typ <> 2
+                                       If pulsing
+                                               PlaySound(killedbypulsarsfx)
+                                               KillPlayer(KILLED_BY_PULSAR)
+                                               Return True
+                                       EndIf
+                               EndIf
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Function Create:Pulsar(index,typ = 0,height)
+               Local p:Pulsar = New Pulsar
+               p.OnEdge = theLevel.edges[index]
+               p.e_Index= index
+               p.typ    = typ
+               p.height = height
+               p.baddietype = BAD_PULSAR
+               BADDIE_LIST.AddLast p
+               enemiesleft:+1          
+               Return p
+       EndFunction
+
+
+       Function UpdatePulseTimers()
+               
+               pulsecount:+pulsespeed
+               If pulsecount > 180 Then pulsecount = 0
+               If pulsecount = 71 And pulsesalive Then PlaySound(pulsesfx)
+               If pulsecount > 70 And pulsecount < 110 Then pulsing = True Else pulsing = False        
+               
+               pulse_zh# = Abs((pulsecount Mod 90)-45)/4.0
+               If pulse_zh# < 2 Then pulse_zh# = 0
+               If pulse_zh# > 12 Then pulse_zh# = 12
+               
+               pulsesalive = False
+       End Function
+       
+EndType
+
+
+
+Type Fuseball Extends Baddies
+       Field act
+       Field cnt
+       Field dir
+       Field w ' position across the edge
+       
+       Method DrawStats(x,y)
+               SetColor 255,255,255
+               DrawText "i="+e_Index+" h="+Int(height)+" a="+act+" w="+w+" d="+dir ,x,y
+       End Method
+
+       Method Draw()
+               Local xx#,yy#,zz1#,zz2#,x#[2],y#[2]
+               zz1# = theLevel.position+theLevel.depth
+               zz2# = zz1 - height
+               TForm(OnEdge.p1.x,OnEdge.p1.y,zz2,x[0],y[0])
+               TForm(OnEdge.p2.x,OnEdge.p2.y,zz2,x[1],y[1])
+               xx = x[1]+(x[0]-x[1]) *w/8
+               yy = y[1]+(y[0]-y[1]) *w/8
+               Local sc# '= height/theLevel.depth*7.0+1
+               sc = TFormSZ(8,zz2)+1
+
+               For Local arm = 0 To 5
+                       Select arm
+                               Case 0
+                                       Color(COL_CLAW)
+                               Case 1
+                                       Color(COL_SPIKERS)                              
+                               Case 2
+                                       Color(COL_TANKERS)
+                               Case 3
+                                       Color(COL_PULSARS)
+                               Case 4
+                                       Color(COL_FLIPPERS)
+                       End Select
+                       For Local i = 0 To 4
+                               DrawLine xx+fusex[fuseball_frame,arm,i]*sc,yy+fusey[fuseball_frame,arm,i]*sc,xx+fusex[fuseball_frame,arm,i+1]*sc,yy+fusey[fuseball_frame,arm,i+1]*sc
+                       Next
+               Next
+       EndMethod
+
+       Method ZapIt(t)
+               dietime = t 'die after t tics
+               Return True
+       End Method
+
+       Method Update()
+               If dietime > 0
+                       dietime:-1
+                       If dietime = 0 'die
+                               PlaySound(zapsfx,zapchan)
+                               Local xx#,yy#,zz1#
+                               zz1 = theLevel.position + theLevel.depth - height
+                               TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)
+                               Local sc = Int((theLevel.depth-height)/100+1)*250
+                               fusepoint.Create(xx,yy,height,sc)
+                               MainPlayer.Score = MainPlayer.Score+sc
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1                          
+                               Return          
+                       EndIf
+               EndIf   
+               cnt = cnt + 1
+               Select act
+               Case 0
+                       If cnt > 8
+                               If Rand(0,100) > 90 Then dir = -FindShortDir(e_Index, MainPlayer.e_Index)                       
+                               cnt = 0
+                               'move left or right....
+                               Select dir
+                                       Case 1
+                                               w = w + 1
+                                               If w >= 8
+                                                       w = 0
+                                                       If e_Index=theLevel.e_cnt-1
+                                                               If theLevel.continuous
+                                                                       e_Index= 0
+                                                               Else
+                                                                       w = 8
+                                                                       dir = -dir
+                                                               EndIf
+                                                       Else
+                                                               e_Index:+1
+                                                       EndIf
+                                               EndIf                           
+                                                                                               
+                                       Case -1
+                                               w = w - 1
+                                               If w =< 0
+                                                       w = 8
+                                                       If e_Index=0
+                                                               If theLevel.continuous
+                                                                       e_Index= theLevel.e_Cnt-1
+                                                               Else
+                                                                       w = 0
+                                                                       dir = -dir
+                                                               EndIf
+                                                       Else
+                                                               e_Index:-1
+                                                       EndIf
+                                               EndIf
+                               End Select
+                               OnEdge = theLevel.edges[e_Index]
+                               If w = 0 Or w = 8 
+                                       act = Rand(1,2)
+                                       If rimit Or height = 0 Then act = 1
+                               EndIf
+                       EndIf
+               Case 1 ' going up
+                       If height < theLevel.Depth
+                               height:+4
+                               If cnt > 25*(Rand(1,3))
+                                       act = 0
+                                       cnt = 0                                 
+                               EndIf
+                       Else
+                               height = theLevel.Depth
+                               act = 0
+                               cnt = 0                         
+                       EndIf
+               Case 2 ' going down
+                       If height >= 0
+                               height:-4
+                               If cnt > 25*(Rand(1,3))
+                                       act = 0
+                                       cnt = 0                                 
+                               EndIf                           
+                       Else
+                               act = 0
+                               cnt = 0                         
+                               height = 0
+                       EndIf
+               Case 7
+                       w = 3
+                       'killing player
+               End Select
+       EndMethod
+       
+       Method CheckColl(e:edge,z#)
+       
+               Local sp# = height-z
+               If e = OnEdge
+                       If sp < 16 And sp > 0
+                               If w >1 And w < 7
+                                       Local xx#,yy#,zz1#
+                                       zz1 = theLevel.position + theLevel.depth - height
+                                       TForm(OnEdge.xx,OnEdge.yy,zz1,xx,yy)
+                                       Local sc = Int((theLevel.depth-height)/100+1)*250
+                                       fusepoint.Create(xx,yy,height,sc)
+                                       MainPlayer.Score = MainPlayer.Score+sc
+                                       BADDIE_LIST.Remove(Self)
+                                       PlaySound(fuseballshotsfx)                                      
+                                       enemiesleft:-1
+                                       Return True
+                               EndIf
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method CheckPlayerColl()
+               If MainPlayer.e_Index = e_index
+                       If act = 0 And height = theLevel.depth
+                               If w > 1 And w < 7
+                                       act = 7
+                                       KillPlayer(KILLED_BY_FUSEBALL)
+                                       PlaySound(killedbyfuseballsfx)
+                                       Return True
+                               EndIf
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+               
+       Function Create:fuseball(index,act,height)
+               Local f:fuseball= New fuseball
+               f.OnEdge=theLevel.Edges[index]
+               f.height=height
+               f.act = act
+               f.e_Index = index
+               f.cnt = 0
+               f.w = 0
+               f.dir = 1
+               f.baddietype = BAD_FUSEBALL
+               BADDIE_LIST.AddLast f
+               enemiesleft:+1
+               Return f
+       EndFunction
+
+       Function UpdateFuseballTimers()
+               
+               fuseball_count:+1
+               fuseball_frame = (fuseball_count/4) Mod 4
+               
+       End Function
+       
+       
+EndType
+
+
+
+
+Type Spikes Extends Baddies
+       
+       Method DrawStats(x,y)
+               Color(COL_SPIKERS)
+               DrawText "i="+e_Index+" h="+Int(height),x,y
+       End Method
+
+       Method Draw()
+               Local oldz
+               If theLevel.state = LEVEL_INTO_VORTEX 
+                       oldz = ZOFFSET  
+                       ZOFFSET = 5
+               EndIf
+
+               Local xx#,yy#,zz1#,zz2#
+               zz1 = theLevel.position+theLevel.depth
+               zz2 = zz1 - height
+               
+               Local x#[2],y#[2]
+               xx =( ( OnEdge.p2.x - OnEdge.p1.x ) / 2.0 ) + OnEdge.p1.x
+               yy =( ( OnEdge.p2.y - OnEdge.p1.y ) / 2.0 ) + OnEdge.p1.y
+               TForm(xx,yy,zz1,x[0],y[0])
+               TForm(xx,yy,zz2,x[1],y[1])
+               Color(COL_SPIKERS)
+               DrawLine x[0],y[0],x[1],y[1]
+               Color(COL_BULLETS)
+               Plot x[1],y[1]
+               If theLevel.state = LEVEL_INTO_VORTEX 
+                       ZOFFSET = oldz
+               EndIf
+
+       EndMethod
+
+       Method ZapIt(t)
+               Return False
+       End Method
+       
+       Method Update()
+       EndMethod
+
+       Method CheckColl(e:edge,z#)
+               'check to see if shot hits it
+               If e = OnEdge
+                       If z < height
+                               height:-8
+                               MainPlayer.Score = MainPlayer.Score+1   
+                               PlaySound(spikeshotsfx)                         
+                               If height =< 0
+                                       OnEdge.Spike = Null
+                                       BADDIE_LIST.Remove(Self)
+                                       Return True
+                               EndIf
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method CheckPlayerColl()
+               If MainPlayer.e_Index = e_index
+                       If height > mainplayer.zPos And mainplayer.deathcount = 0
+                               PlaySound(killedbyspikesfx)
+                               KillPlayer(KILLED_BY_SPIKE)
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+       
+       Function Create:Spikes(index,h#)
+               Local s:Spikes = New Spikes
+               s.OnEdge=theLevel.Edges[index]
+               theLevel.Edges[index].Spike = s
+               s.e_index = index
+               s.height=h
+               s.baddietype = BAD_SPIKE
+               BADDIE_LIST.AddLast s
+               Return s
+       EndFunction
+       
+EndType
+
+
+
+
+
+Type Spinner Extends Baddies
+       Field grow_speed#
+       Field growth# = 0
+       Field r#
+       Field act
+       
+       Method DrawStats(x,y)
+               Color(COL_SPIKERS)
+               DrawText "i="+e_Index+" h="+Int(height)+" a="+act ,x,y
+       End Method
+
+       Method Draw()
+               Local xx#,yy#,zz1#,zz2#
+               zz1# = theLevel.position+theLevel.depth
+               zz2# = zz1 - height
+               Local x#,y#,xd1#,yd1#,xd2#,yd2#
+               xx = OnEdge.xx
+               yy = OnEdge.yy
+               Color(COL_SPIKERS)
+               TForm(xx,yy,zz2,x,y)
+               Local scale#' = height/theLevel.depth*16.0+1
+               scale = TFormSZ(22,zz2)+2
+
+
+               For Local sc# = 0 To -13 Step -1
+                       xd1 = Sin(r+sc*60)*sc*scale/16
+                       yd1 = Cos(r+sc*60)*sc*scale/16
+                       xd2 = Sin(r+(sc+1)*60)*(sc+1)*scale/16
+                       yd2 = Cos(r+(sc+1)*60)*(sc+1)*scale/16
+                       DrawLine x+xd1,y+yd1,x+xd2,y+yd2                
+               Next
+               r = r+45
+       EndMethod
+       
+       Method ZapIt(t)
+               dietime = t 'die after t tics
+               Return True
+       End Method
+
+       Method Update()
+               If dietime > 0
+                       dietime:-1
+                       If dietime = 0 'die
+                               PlaySound(zapsfx,zapchan)
+                               MainPlayer.Score = MainPlayer.Score+50
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1                          
+                               Return          
+                       EndIf
+               EndIf
+               Select act
+               Case 0 
+                       ' go directly to building spike
+                       act = 1
+                       
+               Case 1 ' going up/building spike
+                       If height < theLevel.Depth-4
+                               height:+grow_speed
+                               If onEdge.Spike
+                                       If height > onEdge.Spike.height
+                                               onEdge.Spike.height = height - 4
+                                               growth:+grow_speed
+                                               If growth > 100
+                                                       If Rnd(0,140) > 88
+                                                               act = 2
+                                                               If Rnd(0,100) > 70 Then bullets.Create(e_index,height)
+                                                       EndIf
+                                               EndIf
+                                       EndIf
+                               Else
+                                       OnEdge.Spike = spikes.Create(e_index,10)
+                                       OnEdge.Spike.height = height
+                               EndIf
+                       Else
+                               act = 2
+                       EndIf
+               Case 2 ' going down spike
+                       growth = 0
+                       If height > 0
+                               height:-grow_speed
+                       Else
+                               height = 0
+                               act = 0
+                               BADDIE_LIST.Remove(Self)
+                               enemiesleft:-1
+                               eggsleft:+1
+                       EndIf
+               End Select
+       EndMethod
+
+       Method CheckColl(e:edge,z#)
+               'check to see if any will hit
+               If e = OnEdge
+                       If z < height
+                               MainPlayer.Score = MainPlayer.Score+50
+                               enemiesleft:-1
+                               PlaySound(spinnershotsfx)
+                               BADDIE_LIST.Remove(Self)
+                               Return True
+                       EndIf
+               EndIf
+               Return False
+       EndMethod
+
+       Method CheckPlayerColl()
+               ' never hits the player
+               Return False
+       EndMethod
+       
+       Function Create:Spinner(index,speed#)
+               Local s:Spinner = New Spinner
+               s.OnEdge=theLevel.Edges[index]
+               s.height=0
+               s.act = 0
+               s.e_Index = index
+               s.grow_speed# = speed
+               s.baddietype = BAD_SPINNER              
+               BADDIE_LIST.AddLast s
+               enemiesleft:+1
+               Return s
+       EndFunction
+       
+EndType
+
+
+
+
+
+
+
+
+Function Game()
+
+       Local done = False
+       
+       While Not done
+               FlushKeys()
+               done = theLevel.LevelSelect()
+               mainplayer.score = 0
+               mainplayer.men = 2
+               mainplayer.bonusmencnt = 0
+               FlushKeys()
+               If Not done
+                       'main loop
+                       Local gamedone = False
+                       While Not gamedone 
+                               If KeyHit(KEY_ESCAPE) Then gamedone = True
+                               Local tim = MilliSecs()
+                               globalclock = globalclock + 1   
+                       
+                               If (globalclock Mod enemyreleaserate = 0)
+                                       For Local a = 0 To 5
+                                       If eggsleft > 0 
+                                               Egg.Create(Rand(0,theLevel.e_cnt-2+(theLevel.continuous)))
+                                               eggsleft:-1
+                                       EndIf
+                                       Next
+                               EndIf
+                       
+                               point.UpdatePoints()
+                               theLevel.Update()
+                               theLevel.UpdateAngles()
+                               If theLevel.state <> LEVEL_INTO_VORTEX
+                                       pulsar.UpdatePulseTimers()
+                                       fuseball.UpdateFuseBallTimers()
+                                       shot.UpdateShots()
+                                       egg.UpdateEggs()
+                                       If theLevel.state <> LEVEL_COMPLETE Then Baddies.UpdateBaddies()
+                                       MainPlayer.Update()
+                               EndIf
+                               
+                               If theLevel.state <> LEVEL_COMPLETE
+                                       theLevel.Draw()
+                                       shot.DrawShots()
+                                       egg.DrawEggs()
+                                       Baddies.DrawBaddies()
+                                       explosion.UpdateDrawExplosions()        
+                                       fusepoint.UpdateDrawFusePoints()
+                       
+                                       If theLevel.state <> LEVEL_INTO_VORTEX Then MainPlayer.Draw()
+                               Else
+                                       If startbonus > 0
+                                               DrawString("BONUS",300,170,10)
+                                               Local l$ = startbonus
+                                               Local ln = Len(l$)                                      
+                                               DrawString(startbonus,400-ln*20,270,10)
+                                       EndIf                                   
+                                       DrawString("SUPERZAPPER RECHARGE",120,420,6)
+                               EndIf
+                       
+                               Color(COL_CLAW)
+                               MainPlayer.DrawMenLeft()        
+                               DrawString(MainPlayer.Score,10,10,6.0)
+                               Color(COL_INFO)
+                               DrawString((current_level+1),400-6*(current_level>8),10,3.0) 
+                                       
+                               tim = 16-(MilliSecs()-tim)
+                               If tim > 0 Then Delay tim
+                               
+                               If eggsleft = 0 And CountList(EGG_LIST) = 0
+                                       If enemiesleft = 0 Or onrim = True
+                                               If theLevel.state = LEVEL_READY
+                                                       theLevel.state = LEVEL_START_ZOOM
+                                               EndIf
+                                       Else
+                                               rimit = True
+                                       EndIf
+                               EndIf
+                       
+'                              If KeyHit(key_u) Then YOFFSET = YOFFSET - 10
+'                              If KeyHit(key_j) Then YOFFSET = YOFFSET + 10
+'                              DrawText YOFFSET ,700,0
+'                              If KeyHit(key_i) Then CCenterY = CCenterY - 10
+'                              If KeyHit(key_k) Then CCenterY = CCenterY + 10
+'                              DrawText CCenterY,700,20
+                               
+                               If showdebug DrawString(theLevel.state+" ("+eggsleft+")("+CountList(EGG_LIST)+")("+enemiesleft+")",400,40,5.0)
+                               If KeyDown(KEY_LSHIFT)
+                                       If KeyHit(key_s) Then superzapper = 2
+                                       If KeyHit(key_b) Then mainplayer.score:+10000
+                                       If KeyHit(key_z) Then theLevel.state = LEVEL_START_ZOOM
+                                       If KeyHit(key_m) Then theLevel.mutate()
+                                       If KeyHit(key_n) Then point.ResetPoints()
+                                       If KeyHit(key_t) Then tubes:+16; If tubes > 32 Then tubes = 0
+                                       If KeyHit(key_d) Then showdebug = 1-showdebug
+                               EndIf
+                       
+                               Local skip = False
+                               While KeyDown(key_f1) And Not skip 
+                                       Delay 100
+                                       If KeyHit(key_f2) Then skip = True
+                               Wend
+                               
+                                                       
+                       
+                               If mainplayer.men < 0 Then gameover();gamedone = True
+
+                               Flip
+                               Cls                     
+                       Wend
+                       ClearLevel()
+               EndIf
+       Wend
+End Function
+
+
+
+
+Function GameOver()
+
+       Local done = False      
+       Local sc# = .2
+       Local scd# = .05
+       Local s$ = "GAME OVER"
+       While Not done
+               
+               Cls 
+               SetColor 0,255,0
+               DrawString(s$,400-sc*25,200,sc)
+
+               DrawString(MainPlayer.Score,10,10,6.0)
+               DrawString(current_level,400,10,3.0) 
+               
+               If KeyHit(KEY_SPACE) Then done = True
+
+               If KeyHit(KEY_ESCAPE) Then done = True
+               
+               sc = sc + scd
+               If sc > 4 Or sc < .1 Then scd = -scd;If s$ = "GAME OVER" Then s$ = "PRESS ZAP" Else s$ = "GAME OVER"
+               
+               Flip
+               Delay 16
+       Wend
+       
+End Function
+
+
+
+
+
+Function KillPlayer(nme)
+
+       Select nme
+               Case KILLED_BY_BULLET
+                       mainplayer.deathcount = 60
+                       theLevel.state = LEVEL_PLAYER_DYING
+                       mainplayer.deathtype = KILLED_BY_BULLET
+               Case KILLED_BY_PULSAR
+                       mainplayer.deathcount = 60
+                       theLevel.state = LEVEL_PLAYER_DYING
+                       mainplayer.deathtype = KILLED_BY_PULSAR
+               Case KILLED_BY_SPIKE
+                       mainplayer.deathcount = 60
+                       theLevel.state = LEVEL_REVERSE_ZOOM
+                       mainplayer.deathtype = KILLED_BY_SPIKE
+                       Baddies.ConvertBaddieToEggs()
+               Case KILLED_BY_FLIPPER
+                       mainplayer.deathcount = 60
+                       theLevel.state = LEVEL_PLAYER_DYING
+                       mainplayer.deathtype = KILLED_BY_FLIPPER
+               Case KILLED_BY_FUSEBALL
+                       mainplayer.deathcount = 60
+                       theLevel.state = LEVEL_PLAYER_DYING
+                       mainplayer.deathtype = KILLED_BY_FUSEBALL
+       End Select
+       
+End Function
+
+
+
+
+Function FindShortDir(from_i, to_i)
+       
+       Local d
+       If theLevel.continuous
+'              d = -(MainPlayer.e_Index - e_Index) 'how far from player
+               d = -(to_i - from_i) 'how far from player
+               If Abs(d) > 8 Then d = -Sgn(d) Else d = Sgn(d) 'take the shorter route
+               If d = 0 Then d = 1 - Rand(0,1)*2 '-1 or 1                                      
+       Else
+               d = -Sgn(to_i - from_i)
+               If d = 0 Then d = 1 - Rand(0,1)*2 '-1 or 1
+       EndIf
+       Return d
+       
+End Function
+
+
+
+
+Function Color(c)
+
+       Select current_color
+               Case 0 'level 1-16
+                       Select c
+                               Case COL_BULLETS
+                                       SetColor 255,255,255
+                               Case COL_CLAW
+                                       SetColor 255,255,0
+                               Case COL_TANKERS
+                                       SetColor 255,0,255
+                               Case COL_FLIPPERS
+                                       SetColor 255,0,0
+                               Case COL_PULSARS
+                                       SetColor 0,255,255
+                               Case COL_SPIKERS
+                                       SetColor 0,255,0
+                               Case COL_LEVEL
+                                       SetColor 0,0,255
+                               Case COL_INFO
+                                       SetColor 0,0,255
+                       End Select
+               Case 1 'level 17-32
+                       Select c
+                               Case COL_BULLETS
+                                       SetColor 255,255,255
+                               Case COL_CLAW
+                                       SetColor 0,255,0
+                               Case COL_TANKERS
+                                       SetColor 0,0,255
+                               Case COL_FLIPPERS
+                                       SetColor 255,0,255
+                               Case COL_PULSARS
+                                       SetColor 255,255,0
+                               Case COL_SPIKERS
+                                       SetColor 0,255,255
+                               Case COL_LEVEL
+                                       SetColor 255,0,0
+                               Case COL_INFO
+                                       SetColor 255,0,0
+                       End Select              
+               Case 2 'level 33-48
+                       Select c
+                               Case COL_BULLETS
+                                       SetColor 255,255,255
+                               Case COL_CLAW
+                                       SetColor 0,0,255
+                               Case COL_TANKERS
+                                       SetColor 0,255,255
+                               Case COL_FLIPPERS
+                                       SetColor 0,255,0
+                               Case COL_PULSARS
+                                       SetColor 255,0,255
+                               Case COL_SPIKERS
+                                       SetColor 255,0,0
+                               Case COL_LEVEL
+                                       SetColor 255,255,0
+                               Case COL_INFO
+                                       SetColor 255,255,0
+                       End Select              
+               Case 3 'level 49-64                     
+                       Select c
+                               Case COL_BULLETS
+                                       SetColor 255,255,255
+                               Case COL_CLAW
+                                       SetColor 0,0,255
+                               Case COL_TANKERS
+                                       SetColor 255,0,255
+                               Case COL_FLIPPERS
+                                       SetColor 0,255,0
+                               Case COL_PULSARS
+                                       SetColor 255,255,0
+                               Case COL_SPIKERS
+                                       SetColor 255,0,0
+                               Case COL_LEVEL
+                                       SetColor 0,255,255
+                               Case COL_INFO
+                                       SetColor 0,255,255
+                       End Select
+
+               Case 4 'level 65-80
+                       Select c
+                               Case COL_BULLETS
+                                       SetColor 255,255,255
+                               Case COL_CLAW
+                                       SetColor 255,255,0
+                               Case COL_TANKERS
+                                       SetColor 255,0,255
+                               Case COL_FLIPPERS
+                                       SetColor 255,0,0
+                               Case COL_PULSARS
+                                       SetColor 0,255,255
+                               Case COL_SPIKERS
+                                       SetColor 0,255,0
+                               Case COL_LEVEL
+                                       SetColor 0,0,0
+                               Case COL_INFO
+                                       SetColor 0,0,255
+                       End Select
+               
+               Case 5 'level 81-96
+                       Select c
+                               Case COL_BULLETS
+                                       SetColor 255,255,255
+                               Case COL_CLAW
+                                       SetColor 255,0,0
+                               Case COL_TANKERS
+                                       SetColor 255,0,255
+                               Case COL_FLIPPERS
+                                       SetColor 255,255,0
+                               Case COL_PULSARS
+                                       SetColor 0,255,255
+                               Case COL_SPIKERS
+                                       SetColor 0,0,255
+                               Case COL_LEVEL
+                                       SetColor 0,255,0
+                               Case COL_INFO
+                                       SetColor 0,255,0
+                       End Select
+               
+       End Select                      
+
+End Function
+
+
+
+
+
+
+
+
+Function ClearLevel()
+
+       ' delete all eggs and baddies
+       Local e:egg
+       For e = EachIn EGG_LIST
+               EGG_LIST.Remove(e)
+       Next
+       
+       Local b:Baddies
+       For b = EachIn BADDIE_LIST
+               BADDIE_LIST.Remove(b)
+       Next
+
+       Local s:shot
+       For s=EachIn SHOT_LIST
+               SHOT_LIST.remove(s)
+       Next
+
+       Local p:Point
+       For p=EachIn POINT_LIST
+               POINT_LIST.Remove(p)
+       Next
+       
+       For Local a = 0 Until 16
+               theLevel.Edges[a] = Null
+       Next
+       theLevel.E_cnt = 0
+
+       eggsleft = 0
+       enemiesleft = 0
+       hatchingeggs = 0        
+
+End Function
+
+
+
+
+Function SetUpLevel()
+
+       Local p1:Point = Null
+       Local p2:Point = Null
+       Local fp:Point = Null
+       
+       theLevel.continuous = leveldata[current_board+tubes,0]
+       k = 70
+       CCenterY = leveldata[current_board+tubes,1]
+       YOFFSET =  leveldata[current_board+tubes,2]
+
+       For Local a = 0 Until 16
+               p1 = theLevel.AddPoint( Float(leveldata[current_board+tubes,3+a*2]),Float(leveldata[current_board+tubes,3+a*2+1]))
+               If p2
+                       theLevel.AddEdge(p1,p2)
+               Else
+                       fp = p1
+               EndIf
+               p2=p1
+       Next
+       If theLevel.continuous
+               Local lastedge:edge = theLevel.AddEdge(fp,p2)
+       EndIf
+               
+End Function
+
+
+
+Function SetUpEnemies()
+
+       Local lv = current_level
+
+       enemiesleft = 0
+       eggsleft = 10+lv*2+current_board*2
+       If eggsleft > 100 Then eggsleft = 100
+       maxeggs = eggsleft
+       For Local t = 0 To 3
+               eggsleft:-1
+               Egg.Create(Rand(0,theLevel.e_cnt-2+(theLevel.continuous)))
+       Next
+       
+       theLevel.hasflippers = True
+       theLevel.hastankers = False
+       theLevel.hasspikes = False
+       theLevel.hasfuseballs = False
+       theLevel.haspulsars = False
+       theLevel.hastankersp = False
+       theLevel.hastankersf = False
+               
+       If current_board > 2 Or lv > 47 Then theLevel.hasspikes = True
+       If lv > 9 Then theLevel.hasfuseballs = True
+       If lv > 1 Then theLevel.hastankers = True
+       If lv > 15 Then theLevel.haspulsars = True
+       If lv > 20 Then theLevel.hastankersp = True
+       If lv > 31 Then theLevel.hastankersf = True
+
+       If theLevel.hasspikes
+               For Local a = 0 To theLevel.e_cnt-1
+                       Spikes.Create(a,60.0)
+               Next
+       EndIf
+       
+       enemyreleaserate = 60
+       hatchrate = lv/8
+       rimit = False
+
+       flipflipspeed = 15+lv/5  'degrees
+       pulseflipspeed = 15+lv/9
+       fuseclimbspeed = lv/2  ' not used yet
+       
+       If lv = 0 Then canflip = False Else canflip = True
+       
+       hatchingeggs = 0
+
+End Function
+
+
+
+
+
+
+
+
+
+
+Function ReadFuseballData()
+
+       Local x,y
+
+       For Local frame = 0 To 3
+               For Local arm = 0 To 4
+                       For Local i = 0 To 5
+                               ReadData x
+                               ReadData y
+                               fusex[frame,arm,i] = Float(x)/6.0
+                               fusey[frame,arm,i] = Float(y)/6.0
+                       Next
+               Next
+       Next
+
+End Function
+
+DefData 0,0, 7,-5, 6,-8, 9,-10, 7,-13, 11,-15
+DefData 0,0, 6,3, 6,6, 10,4, 12,4, 13,12
+DefData 0,0, 2,7, -4,10, 1,14, -4,17, 1,20
+DefData 0,0, -7,4, -7,1, -9,1, -11,6, -14,8
+DefData 0,0, -4,-5, -3,-10, -5,-13, -9,-13, -9,-15
+
+DefData 0,0, 6,-8, 5,-11, 9,-14, 7,-18, 6,-20
+DefData 0,0, 7,-3, 6,6, 10,6, 6,11, 11,16
+DefData 0,0, -3,8, -7,6, -5,12, -7,17, -3,21
+DefData 0,0, -6,3, -7,-4, -10,2, -11,-4, -18,4
+DefData 0,0, -3,-6, 2,-11, -4,-13, 2,-16, -2,-21
+
+DefData 0,0, 5,-8, 7,-7, 7,-12, 10,-16, 14,-14
+DefData 0,0, 7,1, 8,5, 11,6, 10,9, 14,10
+DefData 0,0, -5,6, -6,11, -3,11, -6,16, -6,19
+DefData 0,0, -6,1, -8,4, -11,3, -14,5, -16,6
+DefData 0,0, -2,-8, -7,-8, -5,-14, -8,-14, -10,-11
+
+DefData 0,0, 6,-6, 7,-12, 11,-6, 12,-12, 16,-12
+DefData 0,0, 6,5, 6,8, 11,9, 12,14, 16,14
+DefData 0,0, -3,6, -4,10, -9,11, -6,18, -9,21
+DefData 0,0, -4,2, -6,1, -7,2, -12,1, -15,6
+DefData 0,0, 1,-11, 3,-8, 5,-14, 3,-17, 6,-24
+
+
+
+
+Function ReadLevelData()
+
+       Local l,t,v
+       
+       For Local l = 0 To 47
+               For Local t = 0 To 34
+                       ReadData v
+                       leveldata[l,t] = v
+               Next
+       Next
+
+End Function
+
+
+Include "boarddata.bmx"
diff --git a/samples/tempest/transformfunctions.bmx b/samples/tempest/transformfunctions.bmx
new file mode 100644 (file)
index 0000000..b172722
--- /dev/null
@@ -0,0 +1,159 @@
+Strict 
+
+' run in 800X600
+Const CWidth#=800 
+Const CHeight#=600
+
+Global K# = 50
+
+Global CCenterX#=CWidth/2.0
+Global CCenterY#=CHeight/3.0
+
+Global YOFFSET = 128
+Global XOFFSET = 0
+Global ZOFFSET = 5
+
+
+
+' Return the dot product AB Â· BC.
+Function DotProduct#( Ax#,Ay#,Bx#,By#,Cx#,Cy#)
+
+       Local BAx#
+       Local BAy#
+       Local BCx#
+       Local BCy#
+       
+    ' Get the vectors' coordinates.
+    BAx = Ax - Bx
+    BAy = Ay - By
+    BCx = Cx - Bx
+    BCy = Cy - By
+
+    ' Calculate the dot product.
+    Return (BAx * BCx + BAy * BCy)
+
+End Function
+
+
+
+
+' Return the cross product AB x BC.
+Function CrossProductLength#( Ax#,Ay#,Bx#,By#,Cx#,Cy#)
+
+       Local BAx#
+       Local BAy#
+       Local BCx#
+       Local BCy#
+
+    ' Get the vectors' coordinates.
+    BAx = Ax - Bx
+    BAy = Ay - By
+    BCx = Cx - Bx
+    BCy = Cy - By
+
+    ' Calculate the Z coordinate of the cross product.
+       Return(BAx * BCy - BAy * BCx)
+       
+End Function
+
+
+
+' Return the angle ABC.
+Function GetAngle#( Ax#,Ay#,Bx#,By#,Cx#,Cy#)
+
+       Local dot_product#
+       Local cross_product#
+       Local angle#
+
+    ' Get the dot product and cross product.
+    dot_product = DotProduct(Ax, Ay, Bx, By, Cx, Cy)
+    cross_product = CrossProductLength(Ax, Ay, Bx, By, Cx, Cy)
+
+    ' Calculate the angle.
+    angle = MyATan2(cross_product, dot_product)
+       If angle = 0 Then angle = 180
+
+       ' ...handle if angle > 180 case
+       ' find point ax2,ay2 - rotated -90 degrees
+       ' find new angle2
+       ' if angle2 is > 90, then angle = 360-angle
+       If angle <> 180
+               Local px# = ax
+               Local py# = ay
+               Local rang = -1
+               If angle < 90 Then rang = -(179-angle)
+               TFormR(bx,by, rang, px#,py#)
+               dot_product = DotProduct(px, py, Bx, By, Cx, Cy)
+       cross_product = CrossProductLength(px, py, Bx, By, Cx, Cy)
+           ' Calculate the angle.
+       Local angle2 = MyATan2(cross_product, dot_product)
+               If angle2 > 90 Then angle=360-angle
+       EndIf
+       
+       Return Abs(angle Mod 360)
+
+End Function
+
+
+
+
+' Return the angle with tangent opp/hyp.
+Function MyATan2#(opp#, adj#)
+
+       Local angle#
+
+    ' Get the basic angle.
+    If Abs(adj) < 0.0001 Then
+        angle = 90 
+    Else
+        angle = Abs(ATan(opp / adj))
+    End If
+
+    ' See if we are in quadrant 2 or 3.
+    If adj < 0 Then
+        angle = 180-angle 
+    End If
+
+    ' See if we are in quadrant 3 or 4.
+    If opp < 0 Then
+        angle = -angle
+    End If
+
+    ' Return the result.
+    Return angle
+
+End Function
+
+
+
+
+
+
+
+'scale 
+Function TFormSZ#(x#, z#)
+       z:+ZOFFSET '50 
+       Return (x/(z/K))
+EndFunction
+
+
+' rotate xr,yr around xc,yc
+Function TFormR(xc#,yc#, angle, xr# Var,yr# Var)
+       Local x# = (xr-xc)
+       Local y# = (yr-yc)
+       xr = Cos(angle)*x - Sin(angle)*y
+       yr = Sin(angle)*x + Cos(angle)*y
+       xr = xc+xr
+       yr = yc+yr
+End Function
+
+
+'scale based on z
+Function TForm(x#, y#, z#, x2d# Var, y2d# Var )
+       z:+ZOFFSET
+       y:+YOFFSET
+       x:+XOFFSET
+       x2d = CCenterX+(x/(z/K)) 
+       y2d = CCenterY+(y/(z/K))
+EndFunction
+
diff --git a/samples/tempest/vectorfont.bmx b/samples/tempest/vectorfont.bmx
new file mode 100644 (file)
index 0000000..4c11018
--- /dev/null
@@ -0,0 +1,306 @@
+Strict 
+
+'Framework BRL.D3D7Max2D
+Import BRL.Retro
+
+
+Type bbdigit
+       Field x1#,y1#,x2#,y2#
+End Type
+
+Global letterlen[128]
+Global letters:bbdigit[128,8]
+SetUpVectorFont()
+
+
+
+'Test()
+Function Test()
+
+       Graphics 800,600,0
+
+       Local sc# = 3.0
+       Local dir = 1
+
+       While Not KeyHit(key_escape) 
+
+       Cls
+       sc = sc + .1*dir
+       If sc > 10 Or sc < 1 Then dir = -dir
+       DrawString(" !"+Chr$(30)+"#$%&'()*+,-./",400-sc*40,200-sc*15,sc)
+       DrawString("0123456789:;<=>?",400-sc*40,225-sc*10,sc)
+       DrawString("@ABCDEFGHIJKLMNO",400-sc*40,250-sc*5,sc)
+       DrawString("PQRSTUVWXYZ[\]^_",400-sc*40,275+sc*5,sc)
+       DrawString("`abcdefghijklmno",400-sc*40,300+sc*10,sc)
+       DrawString("pqrstuvwxyz{|}~~" ,400-sc*40,325+sc*15,sc)
+       Flip
+       
+       Delay 16+sc*5
+       Wend
+
+End Function
+
+
+
+
+
+
+
+Function SetUpVectorFont()
+
+       RestoreData letterdata
+       
+       Local np,t,s
+       
+       For t = 0 To 127
+               letterlen[t] = -1
+       Next
+       
+       For t = 32 To 127
+               ReadData np     'number of lines in letter (max 6)  x1,y1, x2,y2
+               letterlen[t] = np-1
+               For s = 0 To letterlen[t]
+                       letters[t,s] = New bbdigit
+                       ReadData letters[t,s].x1
+                       ReadData letters[t,s].y1
+                       ReadData letters[t,s].x2
+                       ReadData letters[t,s].y2
+               Next
+       Next
+End Function
+
+
+Function DrawDigit(d,xd,yd,sc#)
+       Local t
+'      If d > 32 And d < 128
+'              If letterlen[d] > -1
+                       For t = 0 To letterlen[d]
+                               DrawLine letters[d,t].x1*sc+xd,letters[d,t].y1*sc+yd,letters[d,t].x2*sc+xd,letters[d,t].y2*sc+yd
+                       Next    
+'              EndIf
+'      EndIf
+End Function
+
+
+Function DrawString(st$,xd,yd,sc#)
+       Local s,d,ln,t
+       
+       ln = Len(st$)
+       For s = 0 To ln-1
+               d = Asc(Mid$(st$,s+1,1))
+'              If d > 32 And d < 128
+'                      If letterlen[d] > -1
+                               For t = 0 To letterlen[d]
+                                       DrawLine letters[d,t].x1*sc+xd+sc*5*s,letters[d,t].y1*sc+yd,letters[d,t].x2*sc+xd+sc*5*s,letters[d,t].y2*sc+yd
+                               Next    
+'                      EndIf
+'              EndIf
+       Next
+End Function
+
+
+
+
+' **************************  vector text data  *******************************************
+' chars 32-127
+' spc!"#$%&'()*+`-,/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_"
+
+#letterdata
+' spc
+DefData        0
+' !
+DefData        2,      2,0, 2,4,       2,5, 2,6
+' ""
+DefData        2,      1,1, 1,3,       3,1, 3,3
+' #
+DefData        4,      1,0, 1,6,       3,0, 3,6,       0,2, 4,2,       0,4, 4,4
+' $
+DefData        6,      0,1, 0,3,       0,3, 4,3,       4,3, 4,5,       4,5, 0,5,       0,1, 4,1,       2,0, 2,6
+' %
+DefData        3,      3,0, 1,6,       1,1, 1,2,       3,4, 3,5
+' &
+DefData        6,      0,1, 4,5,       0,1, 1,0,       1,0, 2,1,       2,1, 0,4,       0,4, 2,6,       2,6, 4,4
+' '
+DefData        1,      3,1, 2,2
+' (
+DefData        3,      3,0, 1,2,       1,2, 1,4,       1,4, 3,6
+' )
+DefData        3,      1,0, 3,2,       3,2, 3,4,       3,4, 1,6
+' *
+DefData        3,      1,1, 3,5,       1,5, 3,1,       0,3, 4,3
+' +
+DefData        2,      2,2, 2,4,       1,3, 3,3
+' ,
+DefData        1,      2,5, 2,6
+' -
+DefData        1,      1,3, 3,3
+' .
+DefData        1,      2,5, 2,5
+' /
+DefData        1,      4,0, 0,6
+' 0
+DefData        4,      0,0, 0,6,       0,6, 4,6,       4,6, 4,0,       4,0, 0,0
+' 1
+DefData        1,      2,0, 2,6
+' 2
+DefData        5,      0,0, 4,0,       4,0, 4,3,       4,3, 0,3,       0,3, 0,6,       0,6, 4,6
+' 3
+DefData        4,      0,0, 4,0,       4,0, 4,6,       4,6, 0,6,       2,3, 4,3
+' 4
+DefData        3,      0,0, 0,3,       0,3, 4,3,       4,0, 4,6
+' 5
+DefData        5,      0,0, 4,0,       0,0, 0,3,       0,3, 4,3,       4,3, 4,6,       0,6, 4,6
+' 6
+DefData        4,      0,0, 0,6,       0,3, 4,3,       4,3, 4,6,       0,6, 4,6
+' 7
+DefData        2,      0,0, 4,0,       4,0, 4,6
+' 8
+DefData        5,      0,0, 0,6,       0,6, 4,6,       4,6, 4,0,       4,0, 0,0,       0,3, 4,3
+' 9
+DefData        4,      0,0, 4,0,       4,0, 4,6,       0,0, 0,3,       0,3, 4,3
+' :
+DefData        2,      2,1, 2,1,       2,5, 2,5
+' ;
+DefData        2,      2,1, 2,1,       2,5, 2,6
+' <
+DefData        2,      4,0, 1,3,       1,3, 4,6
+' =
+DefData        2,      1,2, 3,2,       1,4, 3,4
+' >
+DefData        2,      0,0, 3,3,       3,3, 0,6
+' ?
+DefData        6,      1,1, 1,0,       1,0, 3,0,       3,0, 3,2,       3,2, 2,3,       2,3, 2,4,       2,5, 2,6
+' @
+DefData        6,      2,2, 2,4,       2,4, 4,4,       4,4, 4,0,       4,0, 0,0,       0,0, 0,6,       0,6, 4,6
+' A (65)
+DefData        5,      2,0, 0,2,       2,0, 4,2,       0,2, 0,6,       4,2, 4,6,       0,3, 4,3
+' B
+DefData        6,      0,0, 0,6,       0,6, 4,6,       4,6, 4,3,       4,3, 0,3,       0,0, 3,0,       3,0, 3,3
+' C
+DefData        3,      0,0, 0,6,       0,6, 4,6,       0,0, 4,0
+' D
+DefData        6,      0,0, 0,6,       0,6, 2,6,       2,6, 4,4,       4,4, 4,2,       4,2, 2,0,       2,0, 0,0
+' E
+DefData        4,      0,0, 0,6,       0,6, 4,6,       0,0, 4,0,       0,3, 2,3
+' F
+DefData        3,      0,0, 0,6,       0,0, 4,0,       0,3, 2,3
+' G
+DefData        5,      0,0, 0,6,       0,6, 4,6,       0,0, 4,0,       4,6, 4,3,       4,3, 2,3
+' H
+DefData        3,      0,0, 0,6,       0,3, 4,3,       4,0, 4,6
+' I
+DefData        3,      0,0, 4,0,       0,6, 4,6,       2,0, 2,6
+' J
+DefData        4,      3,0, 4,0,       4,0, 4,6,       4,6, 2,6,   2,6, 1,4
+' K
+DefData        4,      0,0, 0,6,       0,3, 2,3,       2,3, 4,0,       2,3, 4,6
+' L
+DefData        2,      0,0, 0,6,       0,6, 4,6
+' M
+DefData        4,      0,0, 0,6,       0,0, 2,3,       2,3, 4,0,       4,0, 4,6
+' N
+DefData        3,      0,0, 0,6,       0,0, 4,6,       4,6, 4,0
+' O
+DefData        4,      0,0, 0,6,       0,6, 4,6,       4,6, 4,0,       4,0, 0,0
+' P
+DefData        4,      0,0, 0,6,       0,0, 4,0,       0,3, 4,3,       4,3, 4,0
+' Q
+DefData        6,      0,0, 0,6,       0,6, 2,6,       2,6, 4,4,       4,4, 4,0,       4,0, 0,0,   4,6, 2,4
+' R
+DefData        5,      0,0, 0,6,       0,0, 4,0,       0,3, 4,3,       4,0, 4,3,       2,3, 4,6
+' S
+DefData        5,      0,0, 0,3,       0,3, 4,3,       4,3, 4,6,       4,6, 0,6,       0,0, 4,0
+' T
+DefData        2,      0,0, 4,0,       2,0, 2,6
+' U
+DefData        3,      0,0, 0,6,       0,6, 4,6,       4,6, 4,0
+' V
+DefData        4,      0,0, 0,3,       0,3, 2,6,       2,6, 4,3,       4,3, 4,0
+' W
+DefData        4,      0,0, 1,6,       1,6, 2,4,       2,4, 3,6,       3,6, 4,0
+' X
+DefData        2,      0,0, 4,6,       0,6, 4,0
+' Y
+DefData        3,      0,0, 2,3,       2,3, 4,0,       2,3, 2,6
+' Z
+DefData        3,      0,0, 4,0,       4,0, 0,6,       0,6, 4,6
+' [ 
+DefData        3,      3,0, 1,0,       1,0, 1,6,   1,6, 3,6
+' \
+DefData        1,      0,0, 4,6
+' ]
+DefData        3,      1,0, 3,0,       3,0, 3,6,       3,6, 1,6
+' ^
+DefData        2,      1,2, 2,0,       2,0, 3,2
+' _
+DefData        1,      0,7, 4,7
+' `
+DefData        1,      1,1, 2,2
+' a  (97)
+DefData        5,      0,2, 4,2,       4,2, 4,6,       4,6, 0,6,       0,6, 0,3,       0,3, 4,3
+' b
+DefData        4,      0,0, 0,6,       0,6, 4,6,       4,6, 4,2,       4,2, 0,2
+' c
+DefData        3,      0,2, 0,6,       0,6, 4,6,       0,2, 4,2
+' d
+DefData        4,      4,0, 4,6,       4,6, 0,6,       0,6, 0,2,       0,2, 4,2
+' e
+DefData        5,      4,6, 0,6,       0,6, 0,2,       0,2, 4,2,       4,2, 4,3,   4,3, 1,3
+' f
+DefData        3,      4,0, 2,0,       2,0, 2,6,       1,2, 3,2
+' g
+DefData        5,      0,7, 4,7,       4,7, 4,2,       4,2, 0,2,       0,2, 0,6,       0,6, 4,6
+' h
+DefData        3,      0,0, 0,6,       0,2, 4,2,       4,2, 4,6
+' i
+DefData        2,      2,2, 2,6,       2,1, 2,1
+' j
+DefData        4,      3,1, 3,1,       3,2, 3,7,       3,7, 0,7,   0,7, 0,5
+' k
+DefData        3,      0,0, 0,6,       0,4, 3,2,       0,4, 3,6
+' l
+DefData        1,      2,0, 2,6
+' m
+DefData        4,      0,6, 0,2,       0,2, 4,2,       2,2, 2,4,       4,2, 4,6
+' n
+DefData        4,      0,2, 0,6,       0,3, 1,2,       1,2, 4,2,   4,2, 4,6
+' o
+DefData        4,      0,2, 0,6,       0,6, 4,6,       4,6, 4,2,       4,2, 0,2
+' p
+DefData        4,      0,2, 0,7,       0,2, 4,2,       0,6, 4,6,       4,2, 4,6
+' q
+DefData        4,      0,2, 0,6,       0,6, 4,6,       4,2, 4,7,       0,2, 4,2
+' r
+DefData        3,      0,2, 0,6,       0,3, 1,2,       1,2, 4,2
+' s
+DefData        5,      4,2, 0,2,       0,2, 0,4,       0,4, 4,4,       4,4, 4,6,       4,6, 0,6
+' t
+DefData        2,      0,2, 4,2,       2,0, 2,6
+' u
+DefData        3,      0,2, 0,6,       0,6, 4,6,       4,6, 4,2
+' v
+DefData        2,      0,2, 2,6,       2,6, 4,2
+' w
+DefData        4,      0,2, 1,6,       1,6, 2,4,       2,4, 3,6,       3,6, 4,2
+' x
+DefData        2,      0,2, 4,6,       0,6, 4,2
+' y
+DefData        2,      0,2, 2,5,       4,2, 1,7
+' z
+DefData        3,      0,2, 4,2,       4,2, 0,6,       0,6, 4,6
+' {
+DefData        4,      3,0, 2,0,       2,0, 2,6,   2,6, 3,6,   1,3, 2,3
+' |
+DefData        1,      2,0, 2,6
+' }
+DefData        4,      1,0, 2,0,       2,0, 2,6,       2,6, 1,6,   2,3, 3,3
+' ~  (126) 
+DefData        5,      0,3, 0,1,       0,1, 2,1,       2,1, 2,3,   2,3, 4,3,   4,3, 4,1
+
+' <-
+DefData        3,      3,1, 0,3,       0,3, 3,5,       0,3, 4,3
+' checkmark
+DefData        2,      0,4, 2,6,       2,6, 4,0
+' ->
+DefData        3,      1,1, 4,3,       4,3, 1,5,       0,3, 4,3
+
diff --git a/samples/threads/background_loading.bmx b/samples/threads/background_loading.bmx
new file mode 100644 (file)
index 0000000..10ce606
--- /dev/null
@@ -0,0 +1,220 @@
+
+
+
+
+
+' -----------------------------------------------------------------------------
+' MAKE SURE "Threaded Build" IS CHECKED IN THE Program -> Build Options menu!
+' -----------------------------------------------------------------------------
+
+
+
+
+
+' -----------------------------------------------------------------------------
+' Loading screen...
+' -----------------------------------------------------------------------------
+
+AppTitle = "Multi-threaded loading screen demo..."
+
+' How to display an animated loading screen while loading images...
+
+' Because only the main program thread can interact with DirectX/OpenGL,
+' we have to use BlitzMax TPixmaps in the threaded loading routine.
+
+' That's because BlitzMax's TImage is tied to the DirectX/OpenGL 'context',
+' while pixmaps are just blocks of memory that the CPU can manipulate.
+
+' After loading from disk, they can be 'loaded' from the in-memory TPixmap
+' into proper images via LoadImage.
+
+' You could just use DrawPixmap to skip this step, but you then can't use'
+' realtime scaling, rotation, etc.
+
+' The threaded function LoadPixmaps is at the bottom of this code...
+
+' -----------------------------------------------------------------------------
+' This is used to simulate slower loading in the LoadPixmaps thread...
+' -----------------------------------------------------------------------------
+
+Global TestDelay = 1000 ' Simulating more/larger images, 3D models, etc...
+
+' -----------------------------------------------------------------------------
+' Set up global TMap...
+' -----------------------------------------------------------------------------
+
+Global Pixmaps:TMap = CreateMap ()
+
+' -----------------------------------------------------------------------------
+' Add list of pixmap filenames to be added to the Pixmaps TMap...
+' -----------------------------------------------------------------------------
+
+AddPixmap ("bluboing.png")
+AddPixmap ("bluegem.png")
+AddPixmap ("boing.png")
+AddPixmap ("dead.png")
+AddPixmap ("greengem.png")
+AddPixmap ("redgem.png")
+
+' -----------------------------------------------------------------------------
+' Set up display...
+' -----------------------------------------------------------------------------
+
+Graphics 640, 480
+SetClsColor 32, 96, 128
+SetMaskColor 255, 0, 255
+AutoMidHandle True
+
+' -----------------------------------------------------------------------------
+' Start the LoadPixmaps thread...
+' -----------------------------------------------------------------------------
+
+thread:TThread = CreateThread (LoadPixmaps, Null)
+
+' -----------------------------------------------------------------------------
+' This is the loading screen! Some movement and colours while pixmaps load...
+' -----------------------------------------------------------------------------
+
+r = 0; g = 255; b = 127
+
+' -----------------------------------------------------------------------------
+' Do this routine until the thread has finished its work...
+' -----------------------------------------------------------------------------
+
+While ThreadRunning (thread) ' Important!
+
+       Cls
+
+       r = r + 8; If r > 255 Then r = 0
+       g = g - 4; If g > 255 Then g = 0
+       b = b + 2; If b > 255 Then b = 0
+
+       SetColor 0, 0, 0        
+       DrawRect MouseX (), MouseY (), 32, 32
+
+       SetColor r, g, b
+       DrawRect MouseX (), MouseY (), 30, 30
+
+       SetColor 0, 0, 0
+       DrawText "Slow-ding, please wait...", 20, 20
+       SetColor 255, 255, 255
+       DrawText "Slow-ding, please wait...", 18, 18
+
+       Flip
+
+Wend
+
+' -----------------------------------------------------------------------------
+' Right, the thread has finished. Should have a nice TMap filled with pixmaps!
+' -----------------------------------------------------------------------------
+
+' Just re-setting colours, 'scuse me...
+
+r = 255; g = 255; b = 255
+SetColor r, g, b
+
+' -----------------------------------------------------------------------------
+' Create a list of TImage objects and load the pixmaps into them...
+' -----------------------------------------------------------------------------
+
+images:TList = CreateList ()
+
+For p$ = EachIn MapKeys (Pixmaps)
+       ListAddLast images, LoadImage (TPixmap (MapValueForKey (Pixmaps, p$)))
+Next
+
+' In reality, you would probably load each image based on the filename in the
+' map. You could just pass each filename you passed to AddPixmap at the start,
+' for example (untested)...
+
+' rocket:TImage = LoadImage (TPixmap (MapValueForKey (Pixmaps, "boing.png")))
+
+' -----------------------------------------------------------------------------
+' Free the map and all TPixmap objects it holds...
+' -----------------------------------------------------------------------------
+
+ClearMap Pixmaps
+
+' -----------------------------------------------------------------------------
+' Yay... into the main game! Woo! Fun!
+' -----------------------------------------------------------------------------
+
+Repeat
+
+       Cls
+       
+       x = 0
+       y = 0
+
+       SetRotation ang#; ang = ang + 1; If ang > 360 Then ang = 0
+       
+       ' Draw all images...
+       
+       For i:TImage = EachIn images
+       
+               DrawImage i, x, y
+               x = x + 96
+               y = y + 96
+       Next
+
+       SetRotation 0
+
+       SetColor 0, 0, 0        
+       DrawRect MouseX (), MouseY (), 32, 32
+       SetColor 255, 255, 255
+       DrawRect MouseX (), MouseY (), 30, 30
+       
+       SetColor 0, 0, 0        
+       DrawText "All done! We're in-game now! Fun, fun, fun...", 20, 20
+       SetColor 255, 255, 255
+       DrawText "All done! We're in-game now! Fun, fun, fun...", 18, 18
+
+       Flip
+       
+Until KeyHit (KEY_ESCAPE)
+
+End
+
+' -----------------------------------------------------------------------------
+' Helper function for anyone scared of maps...
+' -----------------------------------------------------------------------------
+
+Function AddPixmap (p$)
+
+       ' Maps are similar to lists, but associated two values with each other;
+       ' in this case, a filename and a TPixmap pointer, which is Null here.
+       
+       ' The LoadPixmaps function will load the pixmap for each filename in the
+       ' map, and associated the resulting TPixmap with that filename.
+       
+       MapInsert (Pixmaps, p$, New TPixmap)
+       
+End Function
+
+' -----------------------------------------------------------------------------
+' The threaded pixmap loading function...
+' -----------------------------------------------------------------------------
+
+' No mutexes are needed here since the global Pixmaps:TMap is only accessed by
+' the main program after this thread is finished...
+
+Function LoadPixmaps:Object (data:Object)
+
+       ' Iterate through the global Map...
+       
+       For p$ = EachIn MapKeys (Pixmaps)
+       
+               ' Load pixmaps into the existing [Null] TPixmap slots for each
+               ' filename...
+
+               pix:TPixmap = LoadPixmap (p$)
+               MapInsert (Pixmaps, p$, pix)
+               
+               ' Fake delay to simulate loading bigger images for this demo!
+               
+               Delay TestDelay
+               
+       Next
+
+End Function
+
diff --git a/samples/threads/bluboing.png b/samples/threads/bluboing.png
new file mode 100644 (file)
index 0000000..386786d
Binary files /dev/null and b/samples/threads/bluboing.png differ
diff --git a/samples/threads/bluegem.png b/samples/threads/bluegem.png
new file mode 100644 (file)
index 0000000..7785967
Binary files /dev/null and b/samples/threads/bluegem.png differ
diff --git a/samples/threads/boing.png b/samples/threads/boing.png
new file mode 100644 (file)
index 0000000..4b365ed
Binary files /dev/null and b/samples/threads/boing.png differ
diff --git a/samples/threads/dead.png b/samples/threads/dead.png
new file mode 100644 (file)
index 0000000..18df9cc
Binary files /dev/null and b/samples/threads/dead.png differ
diff --git a/samples/threads/greengem.png b/samples/threads/greengem.png
new file mode 100644 (file)
index 0000000..6d190ef
Binary files /dev/null and b/samples/threads/greengem.png differ
diff --git a/samples/threads/redgem.png b/samples/threads/redgem.png
new file mode 100644 (file)
index 0000000..0239bf6
Binary files /dev/null and b/samples/threads/redgem.png differ
diff --git a/samples/threads/threaded image downloader.bmx b/samples/threads/threaded image downloader.bmx
new file mode 100644 (file)
index 0000000..1068696
--- /dev/null
@@ -0,0 +1,317 @@
+
+
+
+
+
+' -----------------------------------------------------------------------------
+' MAKE SURE "Threaded Build" IS CHECKED IN THE Program -> Build Options menu!
+' -----------------------------------------------------------------------------
+
+
+' You may have to tell your firewall to let this program through...
+
+
+
+' -----------------------------------------------------------------------------
+' Global mutex and abort 'signal' checked in thread...
+' -----------------------------------------------------------------------------
+Global abortmutex:TMutex = CreateMutex ()
+Global abort = 0
+
+' -----------------------------------------------------------------------------
+Global Bail = 3 ' How many times to attempt download of each image...
+' -----------------------------------------------------------------------------
+
+' Number of image URLs in array below...
+
+Const PicNum = 7
+Global Pic$ [PicNum]
+
+Pic [0] = ConvURL ("http://www.blitzbasic.com/img/platypus.jpg")
+Pic [1] = ConvURL ("http://www.blitzbasic.com/img/auto_cross_racing.jpg")
+Pic [2] = ConvURL ("http://www.blitzbasic.com/img/super_gerball.jpg")
+Pic [3] = ConvURL ("http://www.blitzbasic.com/img/tank_universal.jpg")
+Pic [4] = ConvURL ("http://www.blitzbasic.com/img/tecno.jpg")
+Pic [5] = ConvURL ("http://www.blitzbasic.com/img/master_of_defence.jpg")
+Pic [6] = ConvURL ("http://www.blitzbasic.com/img/kingdom_elemental_tactics.jpg")
+
+' -----------------------------------------------------------------------------
+' D E M O . . .
+' -----------------------------------------------------------------------------
+
+AppTitle = "Threaded image downloader..."
+
+Graphics 640, 480
+SetClsColor 64, 96, 128
+AutoMidHandle True
+
+' -----------------------------------------------------------------------------
+' Player type stores downloaded images and their co-ords...
+' -----------------------------------------------------------------------------
+
+Type Player
+
+       Field x:Float = Rnd (GraphicsWidth ())
+       Field y:Float = Rnd (GraphicsHeight ())
+
+       Field xs:Float = Rnd (10)
+       Field ys:Float = Rnd (10)
+
+       Field ang:Float = Rnd (360)
+       Field angspeed:Float = Rnd (-5, 5)
+       
+       Field scale:Float = Rnd (1.0, 3.0)
+       
+       Field image:TImage
+
+End Type
+
+' -----------------------------------------------------------------------------
+' List of Player objects...
+' -----------------------------------------------------------------------------
+
+PlayerList:TList = CreateList ()
+
+' -----------------------------------------------------------------------------
+' Spawn first thread...
+' -----------------------------------------------------------------------------
+
+index = 0 ' Picture index in Pic [] array...
+
+Print ""; Print "Downloading " + Pic [index]
+
+pixthread:TThread = CreateThread (DownloadPixmap, Pic [index])
+
+alldone = 0
+
+Repeat
+
+       ' This variable is set when all images have been downloaded:
+               
+       If Not alldone
+
+               If Not ThreadRunning (pixthread)
+
+                       ' WaitThread contains the result of the last thread (now finished)...
+                       
+                       pix:TPixmap = TPixmap (WaitThread (pixthread))
+       
+                       ' If a valid pixmap was returned, create a new 'Player' object
+                       ' and load the pixmap as an image...
+                       
+                       If pix
+                               p:Player = New Player
+                               p.image = LoadImage (pix)
+                               ListAddLast PlayerList, p
+                       EndIf
+
+                       ' Check we still have more images to load...
+                               
+                       If index < PicNum - 1
+                       
+                               ' OK... next!
+                               
+                               index = index + 1
+                               
+                               Print ""; Print "Downloading " + Pic [index]
+                               
+                               ' Last image thread is done/processed, so create a new one!
+                               
+                               pixthread = CreateThread (DownloadPixmap, Pic [index])
+                               
+                       Else
+                               Print ""; Print "All images loaded!"
+                               alldone = 1 ' All images in array loaded!
+                       EndIf
+
+               EndIf
+
+       EndIf
+
+       Cls
+
+       ' Draw all loaded images...
+       
+       For p:Player = EachIn PlayerList
+
+               p.x = p.x + p.xs
+               If p.x < 0 Or p.x > GraphicsWidth () - 1
+                       p.xs = -p.xs
+               EndIf
+
+               p.y = p.y + p.ys
+               If p.y < 0 Or p.y > GraphicsHeight () - 1
+                       p.ys = -p.ys
+               EndIf
+
+               SetScale p.scale, p.scale
+
+               p.ang = p.ang + p.angspeed
+               SetRotation p.ang
+
+               DrawImage p.image, p.x, p.y
+       
+               SetScale 1, 1
+               SetRotation 0
+               
+               If alldone
+                       txt$ = "All images loaded!"
+               Else
+                       txt$ = "Loading images in background..."
+               EndIf
+               
+               SetColor 0, 0, 0
+               DrawText txt$, 20, 20
+               SetColor 255, 255, 255
+               DrawText txt$, 18, 18
+               
+       Next
+       
+       Flip
+
+Until KeyHit (KEY_ESCAPE)
+
+' Lock the abort mutex so we can safely modify the global abort variable, which
+' is then checked by the thread to allow a safe exit...
+
+LockMutex abortmutex
+       abort = True
+UnlockMutex abortmutex
+
+' The mutex is unlocked by the DownloadPixmap thread before returning,
+' but it may already have exited. I think, hence the UnlockMutex above,
+' just in case...
+
+' Now wait to make sure the thread has finished...
+
+WaitThread pixthread
+
+' Done!
+
+End
+
+' -----------------------------------------------------------------------------
+' Threaded pixmap downloader...
+' -----------------------------------------------------------------------------
+
+Function DownloadPixmap:TPixmap (data:Object)
+
+       img$ = String (data)
+       
+       Local pix:TPixmap               ' Downloaded pixmap...
+       
+       Local url:TStream               ' Download stream...
+       Local copy:TStream              ' Local copy of download...
+       
+       Local count:Int         ' Byte count during download...
+       
+       Local retry:Int         ' If download fails, retry 'Bail' times...
+       Local quit:Int                  ' Too many fails, exit...
+       
+       Repeat
+
+               Print ""
+               Print "Attempting new download..."
+               Print ""
+               
+               url = ReadStream (img$)
+
+               If url
+
+                       ' Create local copy...
+                       
+                       copy = WriteStream ("local.jpg")
+                       
+                       If copy
+                       
+                               ' Reset byte count...
+                               
+                               count = 0
+
+                               Repeat
+
+                                       ' Try to lock mutex, to check global abort variable, which
+                                       ' is set to True before exiting program...
+                                       
+                                       LockMutex abortmutex
+                                       
+                                       If abort
+                                               
+                                               ' Aaaaaaahhhh!!! We're going down!!!
+
+                                               UnlockMutex abortmutex
+                                               
+                                               ' Close all streams! Batten down the hatches!
+                                               
+                                               CloseStream url
+                                               CloseStream copy
+                                               
+                                               ' Abandon ship!
+                                               
+                                               Return Null
+
+                                       Else
+
+                                               ' Not aborting, so unlock the mutex...
+                                               
+                                               UnlockMutex abortmutex
+                                               
+                                               ' Not every efficient (one byte at a time), but works as a demo...
+                                               
+                                               WriteByte copy, ReadByte (url)
+
+                                               ' Count bytes downloaded...
+                                               
+                                               count = count + 1
+                                               If count Mod 1024 = 0 Then Print count + " bytes downloaded in background"
+
+                                       EndIf
+
+                               Until Eof (url)
+
+                               CloseStream copy
+
+                               ' Try to load pixmap...
+                               
+                               pix = LoadPixmap ("local.jpg")
+                               
+                       EndIf
+                                               
+                       CloseStream url
+
+               EndIf
+
+               ' Download failed? Retry 'Bail' times...
+               
+               If pix = Null
+
+                       retry = retry + 1
+
+                       If retry = Bail
+                       
+                               quit = True
+                               Print "Failed to download after " + Bail + " attempts..."
+                       
+                       Else
+                       
+                               Print "Retrying..."
+                               
+                       EndIf
+
+               EndIf
+                               
+       Until pix Or quit
+
+       If pix = Null
+               DebugLog "Oops... problem loading " + img$
+       EndIf
+       
+       Return pix ' May still be Null after 'Bail' failed attempts...
+       
+End Function
+
+' Convert real URL to BlitzMax stream-friendly URL...
+
+Function ConvURL$ (url$)
+       Return Replace (url$, "://", "::")
+End Function
diff --git a/samples/threads/threads.bmx b/samples/threads/threads.bmx
new file mode 100644 (file)
index 0000000..b4c1123
--- /dev/null
@@ -0,0 +1,96 @@
+
+
+
+
+' -----------------------------------------------------------------------------
+' MAKE SURE "Threaded Build" IS CHECKED IN THE Program -> Build Options menu!
+' -----------------------------------------------------------------------------
+
+
+
+
+
+' -----------------------------------------------------------------------------
+' Simple thread demo...
+' -----------------------------------------------------------------------------
+
+' Mutexes are used to allow only one thread to access a variable or object in
+' memory.
+
+' A thread (including the main program's thread) can call LockMutex
+' on a mutex, and if another thread has already locked the mutex, it will
+' wait until the other thread has unlocked the mutex, then gain the lock. It's
+' important that a thread calls UnlockMutex when it's done what it needs to do!
+
+' The main program's thread and the spawned thread will both attempt to lock
+' this mutex throughout, waiting on each other if they can't lock it...
+
+Global Mutex = CreateMutex ()
+
+' Try commenting out the above line, then scroll back through the output of
+' the program, and you should see that the threads are fighting for access to
+' the output console, creating intermeshing, gibberish text...
+
+Print ""
+Print "NOTE: Output of the two threads may not always alternate between 'Main' and 'Thread'..."
+Print ""
+
+' Create thread using Test () function and pass Null parameter...
+
+thread:TThread = CreateThread (Test, Null)
+
+' The new thread has now started. Do some stuff in the main program...
+
+For a = 1 To 100
+
+       ' Other thread may be using the Print command (which isn't thread-friendly),
+       ' so LockMutex will wait until the thread has unlocked the mutex, and then
+       ' lock it so main program can call Print. It will then unlock the mutex so
+       ' the other thread can continue if it's ready (ie. waiting at its own
+       ' LockThread call)...
+       
+       If Mutex Then LockMutex (Mutex)
+               Print "Main: " + a
+       If Mutex Then UnlockMutex (Mutex)
+
+       ' Note: You'd normally just do this like the Rem'd out code below! The
+       ' "If Mutex" check here is to allow you to comment out the line
+       ' "Global Mutex = CreateMutex ()" to see why mutexes are needed...
+
+       ' You would also not normally use LockMutex so heavily, as it will
+       ' slow things down if over-used...
+       
+       Rem
+       
+               LockMutex (Mutex)
+                       Print "Main: " + a
+               UnlockMutex (Mutex)
+       
+       End Rem
+       
+Next
+
+' Other thread may still be running, so wait for it to end...
+
+WaitThread (thread)
+
+End
+
+' -----------------------------------------------------------------------------
+' Test function. Locks same mutex as main program, or waits until it
+' can do so, calls Print, then unlocks the mutex so main program can
+' lock it and proceed...
+' -----------------------------------------------------------------------------
+
+Function Test:Object (data:Object)
+
+       For a = 1 To 100
+
+               If Mutex Then LockMutex (Mutex)
+                       Print "--------> Thread: " + a
+               If Mutex Then UnlockMutex (Mutex)
+
+       Next
+
+End Function
+