implementation module gameobjectutils import StdBool, StdList import StdMaybe import gameCrossCall_12 import fixed, gamehandle, gst CompressBools :: !(!Bool, !Bool, !Bool, !Bool, !Bool, !Bool, !Bool, !Bool) -> Int CompressBools (b7, b6, b5, b4, b3, b2, b1, b0) = ((toInt01 b7) << 7) bitor ((toInt01 b6) << 6) bitor ((toInt01 b5) << 5) bitor ((toInt01 b4) << 4) bitor ((toInt01 b3) << 3) bitor ((toInt01 b2) << 2) bitor ((toInt01 b1) << 1) bitor ((toInt01 b0) << 0) toInt01 :: !Bool -> Int toInt01 True = 1 toInt01 False = 0 // store an objectrec in the game engine SetObjectRec :: !InstanceID !ObjectCode !GameObjectRec ![SpriteID] !*OSToolbox -> (!GRESULT, !*OSToolbox) SetObjectRec id ot or spr tb = WinSetObjectRec id ot or.subcode or.active or.pos.x or.pos.y or.size.w or.size.h or.offset.x or.offset.y ((findlistvalue or.currentsprite spr) bitor (or.currentsprite << 16)) (CompressBools (False, r270, r180, r90, or.displayoptions.mirrorupdown, or.displayoptions.mirrorleftright, or.displayoptions.stretch, or.displayoptions.blink)) or.ownbounds or.bouncebounds or.collidebounds or.forgetdistance.x or.forgetdistance.y or.framecounter (layerpositionint or.layer) (fix or.acceleration.rx) (fix or.acceleration.ry) (fix or.speed.rx) (fix or.speed.ry) (FVToInt or.bounce.fvx) (FVToInt or.bounce.fvy) (fix or.maxspeed.rx) (fix or.maxspeed.ry) (FVToInt or.slowdown.fvx) (FVToInt or.slowdown.fvy) or.skipmove (((CompressBools (False, False, opt.removemapcode, opt.freeze, opt.automirrorupdown, opt.automirrorleftright, vdir, hdir)) << 8) bitor (CompressBools ( opt.static, opt.allowkeyboardrepeat, opt.checkkeyboard, False, False, opt.ignorelevelbounds, False, False))) tb where opt = or.options hdir = case opt.hdirection of DirLeft -> True DirRight -> False vdir = case opt.vdirection of DirUp -> True DirDown -> False (r90,r180,r270) = case or.displayoptions.rotation of Rotate90 -> (True, False, False) Rotate180 -> (False, True, False) Rotate270 -> (False, False, True) NoRotation -> (False, False, False) layerpositionint :: LayerPosition -> Int layerpositionint InFront = EVERYTHING layerpositionint (AtLayer n) = n FVToInt :: FV -> Int FVToInt (Factor r) = (~ (fix r)) FVToInt (Value r) = (fix r) findlistvalue :: !Int ![Int] -> Int findlistvalue _ [] = 0 findlistvalue 1 [x:xs] = x findlistvalue n [x:xs] | n == 1 = x | n > 1 = findlistvalue (n-1) xs | otherwise = ~n // load an GameObjectRec from the game engine GetObjectRec :: !Int !*OSToolbox -> (!GRESULT, !ObjectCode, !GameObjectRec, !*OSToolbox) GetObjectRec id tb # (ot, st, act, x, y, w, h, xofs, yofs, spr, do, bnds, bncbnds, colbnds, fx, fy, time, lyr, xacc, yacc, xv, yv, xbnc, ybnc, maxxv, maxyv, xsl, ysl, md, opt, result, tb) = WinGetObjectRec id tb = (result, ot, {subcode = st, active = act, size = {w=w,h=h}, pos = {x=x,y=y}, offset = {x=xofs,y=yofs}, currentsprite = (spr >> 16), displayoptions = {blink = (not ((do bitand DO_BLINK) == 0)), stretch = (not ((do bitand DO_STRETCH) == 0)), mirrorleftright = (not ((do bitand DO_MIRROR_LEFT_RIGHT) == 0)), mirrorupdown = (not ((do bitand DO_MIRROR_UP_DOWN) == 0)), rotation = (if (not ((do bitand DO_ROTATE_90) == 0)) Rotate90 (if (not ((do bitand DO_ROTATE_180) == 0)) Rotate180 (if (not ((do bitand DO_ROTATE_270) == 0)) Rotate270 NoRotation))) }, ownbounds = bnds, bouncebounds = bncbnds, collidebounds = colbnds, forgetdistance = {x=fx,y=fy}, framecounter = time, layer = if (lyr == EVERYTHING) InFront (AtLayer lyr), acceleration = {rx=fxr xacc,ry=fxr yacc}, speed = {rx=fxr xv,ry=fxr yv}, bounce = {fvx=IntToFV xbnc,fvy=IntToFV ybnc}, maxspeed = {rx=fxr maxxv,ry=fxr maxyv}, slowdown = {fvx=IntToFV xsl,fvy=IntToFV ysl}, skipmove = md, options = { // fixed = (not ((opt bitand OO_FIXED) == 0)) // , ignorestaticbounds = (not ((opt bitand OO_IGNORE_STATIC_BOUNDS) == 0)) ignorelevelbounds = (not ((opt bitand OO_IGNORE_LEVEL_BOUNDS) == 0)) // , bounceatcollisions = (not ((opt bitand OO_BOUNCE_AT_COLLISIONS) == 0)) // , checkmapcodes = (not ((opt bitand OO_CHECK_MAP_CODES) == 0)) , checkkeyboard = (not ((opt bitand OO_CHECK_KEYBOARD) == 0)) , allowkeyboardrepeat = (not ((opt bitand OO_ALLOW_KEYBOARD_REPEAT) == 0)) , static = (not ((opt bitand OO_STATIC) == 0)) , hdirection = (if ((opt bitand OO_LAST_DIRECTION_LEFT) == 0) DirRight DirLeft) , vdirection = (if ((opt bitand OO_LAST_DIRECTION_UP) == 0) DirDown DirUp) , automirrorleftright = (not ((opt bitand OO_AUTO_MIRROR_LEFT_RIGHT) == 0)) , automirrorupdown = (not ((opt bitand OO_AUTO_MIRROR_UP_DOWN) == 0)) , freeze = (not ((opt bitand OO_FREEZE) == 0)) , removemapcode = (not ((opt bitand OO_REMOVE_MAP_CODE) == 0)) } }, tb) where IntToFV :: !Int -> FV IntToFV x | x < 0 = Factor (~ (fxr x)) | otherwise = Value (fxr x) // get the definition of an object by it's ObjectType getobject :: !ObjectCode !(GameHandle .gs) -> Maybe (GameObjectHandleLS (GSt .gs)) getobject objcode gamehnd # curlevel = hd gamehnd.levels` # objectlist = curlevel.objects` # found = filter cmpobjtypes objectlist | isEmpty found = Nothing = Just (hd found) where cmpobjtypes :: !(GameObjectHandleLS .gst) -> Bool cmpobjtypes (GameObjectHandleLS ot) = ot.objectcode` == objcode // store the definition of an object in the game definition putobject :: !(GameObjectHandleLS (GSt .gs)) !(GameHandle .gs) -> GameHandle .gs putobject obj gamehnd # curlevel = hd gamehnd.levels` # newobjlist = replaceobj curlevel.objects` obj [] # curlevel = {curlevel & objects`=newobjlist} = {gamehnd & levels`=[curlevel]} where replaceobj :: ![GameObjectHandleLS .gst] (GameObjectHandleLS .gst) ![GameObjectHandleLS .gst] -> [GameObjectHandleLS .gst] replaceobj [] _ l = l /* replaceobj [x:xs] y | x.objecttype` == y.objecttype` = [y:replaceobj xs y] | otherwise = [x:replaceobj xs y] */ // optimization: replaceobj [GameObjectHandleLS x:xs] obj=:(GameObjectHandleLS y) l | x.objectcode` == y.objectcode` = l ++ [obj:xs] | otherwise = replaceobj xs obj (l ++ [GameObjectHandleLS x]) // find object state in tuple list findinstance :: ![(a,b)] a -> Maybe b | ==a findinstance [] _ = Nothing findinstance [(x,y):s] z | x == z = Just y | otherwise = findinstance s z // replace object state in tuple list updateinstance :: a b ![(a,b)] -> [(a,b)] | ==a updateinstance _ _ [] = [] /* updateinstance v w [(x,y):z] | v == x = [(v,w):updateinstance v w z] | otherwise = [(x,y):updateinstance v w z] */ // optimization: updateinstance v w l = updinst v w l [] where updinst _ _ [] l = l updinst v w [(x,y):z] l | v == x = l ++ [(v,w):z] | otherwise = updinst v w z ([(x,y)] ++ l) // remove object from tuple list removeinstance :: a ![(a,b)] -> [(a,b)] | ==a removeinstance _ [] = [] /* removeinstance v [(x,y):z] | v == x = removeinstance v z | otherwise = [(x,y):removeinstance v z] */ // optimization: removeinstance v l = reminst v l [] where reminst _ [] _ = [] reminst v [(x,y):z] l | v == x = l ++ z | otherwise = reminst v z ([(x,y)] ++ l) // create a DirectionSet from an integer value (0-15) makeDirectionSet :: !Int -> DirectionSet makeDirectionSet x # top = (((x >> 0) bitand 1) == 1) left = (((x >> 1) bitand 1) == 1) bottom = (((x >> 2) bitand 1) == 1) right = (((x >> 3) bitand 1) == 1) = {top=top,left=left,bottom=bottom,right=right} fromDirectionSet :: !DirectionSet -> Int fromDirectionSet d = CompressBools (False, False, False, False, d.right, d.bottom, d.left, d.top) toBoundMapCode :: !(!Int,!DirectionSet) -> Int toBoundMapCode (c, d) = (c << 8) + (fromDirectionSet d) fromBoundMapCode :: !Int -> (!Int,!DirectionSet) fromBoundMapCode x = (x >> 8, makeDirectionSet x)