| @@ -0,0 +1,2 @@ | |||
| # ld40 | |||
| Ludum Dare 40 - Theme : "The more you have, the worse it is" | |||
| @@ -0,0 +1,56 @@ | |||
| <html> | |||
| <head> | |||
| <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> | |||
| <meta property="og:image" content="http://ncannasse.fr/file/ld40/screen.png"/> | |||
| <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'/> | |||
| <title>Taffle Game</title> | |||
| </head> | |||
| <body style="background-color : #F9F7F7; color : #eef"> | |||
| <style type="text/css"> | |||
| a { | |||
| color : #844; | |||
| text-decoration : none; | |||
| } | |||
| p { | |||
| color : #888; | |||
| font-family: 'Open Sans', sans-serif; | |||
| } | |||
| </style> | |||
| <center> | |||
| <div style="position : relative; width : 832px"> | |||
| <canvas id="webgl" style="width:832px;height:832px"></canvas> | |||
| </div> | |||
| <p> | |||
| <b>Arrows</b> : Move / <b>Space</b> : Rewind | |||
| - | |||
| <i>Game created for LudumDare #40 in 48 hours by <a href="http://twitter.com/ncannasse">@ncannasse</a></i> | |||
| </p> | |||
| <p> | |||
| Sources : <a href="http://github.com/ncannasse/ld40">Github</a> | Built with <a href="http://haxe.org">Haxe</a> | Rate <a href="https://ldjam.com/events/ludum-dare/40/jonathan-the-sorcerer">on this page</a> | |||
| </p> | |||
| </center> | |||
| <script type="text/javascript" src="ld40.js"></script> | |||
| <script type="text/javascript"> | |||
| var _gaq = _gaq || []; | |||
| _gaq.push(['_setAccount', 'UA-34409935-1']); | |||
| _gaq.push(['_trackPageview']); | |||
| (function() { | |||
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | |||
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |||
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | |||
| })(); | |||
| </script> | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,8 @@ | |||
| -lib heaps | |||
| -lib castle | |||
| -cp src | |||
| -js ld40.js | |||
| -main Game | |||
| -D windowSize=832x832 | |||
| -dce full | |||
| -D release | |||
| @@ -0,0 +1,28 @@ | |||
| { "compressionlevel":-1, | |||
| "height":20, | |||
| "infinite":false, | |||
| "layers":[ | |||
| { | |||
| "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |||
| "height":20, | |||
| "id":1, | |||
| "name":"Tile Layer 1", | |||
| "opacity":1, | |||
| "type":"tilelayer", | |||
| "visible":true, | |||
| "width":20, | |||
| "x":0, | |||
| "y":0 | |||
| }], | |||
| "nextlayerid":2, | |||
| "nextobjectid":1, | |||
| "orientation":"orthogonal", | |||
| "renderorder":"right-down", | |||
| "tiledversion":"2020.04.10", | |||
| "tileheight":32, | |||
| "tilesets":[], | |||
| "tilewidth":32, | |||
| "type":"map", | |||
| "version":1.2, | |||
| "width":20 | |||
| } | |||
| @@ -0,0 +1 @@ | |||
| private typedef Init = haxe.macro.MacroType < [cdb.Module.build("data.cdb")] > ; | |||
| @@ -0,0 +1,489 @@ | |||
| import hxd.res.DynamicText.Key; | |||
| import h3d.pass.Default; | |||
| import ent.Entity; | |||
| import ent.Object; | |||
| import hxd.Key in K; | |||
| class EnvPart extends h2d.SpriteBatch.BatchElement { | |||
| public var speed : Float; | |||
| public var rspeed : Float; | |||
| public function new(t) { | |||
| super(t); | |||
| x = Math.random() * Game.LW * 32; | |||
| y = Math.random() * Game.LH * 32; | |||
| speed = 6 + Math.random() * 3; | |||
| rspeed = 0.02 * (1 + Math.random()); | |||
| } | |||
| } | |||
| @:publicFields | |||
| class Game extends hxd.App { | |||
| static var LW = 13; | |||
| static var LH = 13; | |||
| static var LAYER_SOIL = 0; | |||
| static var LAYER_ENT_UNDER = 1; | |||
| static var LAYER_COL = 2; | |||
| static var LAYER_ENT = 3; | |||
| static var LAYER_CARRY = 4; | |||
| static var LAYER_HERO = 5; | |||
| static var LAYER_PARTS = 6; | |||
| static var LAYER_ENVP = 7; | |||
| static var LAYER_END = 8; | |||
| var currentLevel : Int; | |||
| var tiles : h2d.Tile; | |||
| var level : Data.Level; | |||
| var soils : Array<Data.Soil>; | |||
| var entities : Array<ent.Entity> = []; | |||
| var world : h2d.Layers; | |||
| var dbgCol : h2d.TileGroup; | |||
| var soilLayer : h2d.TileGroup; | |||
| var pad : hxd.Pad; | |||
| var allActive : Bool; | |||
| var bg : h2d.Object; | |||
| var clouds = []; | |||
| var parts : h2d.SpriteBatch; | |||
| var way : Float = 1.; | |||
| var bmpTrans : h2d.Bitmap; | |||
| var hueShaderHalf = new h3d.shader.ColorMatrix(); | |||
| var hueValue = 0; | |||
| var title : h2d.Bitmap; | |||
| var end : h2d.Bitmap; | |||
| var errorSound: hxd.res.Sound; | |||
| function loadGame() { | |||
| haxe.Timer.delay(function() { | |||
| for( e in entities.copy() ) | |||
| if( e.hasFlag(NeedActive) ) | |||
| e.remove(); | |||
| bg.visible = false; | |||
| parts.visible = false; | |||
| var t = new h3d.mat.Texture(LW * 32, LH * 32, [Target]); | |||
| var old = world.filter; | |||
| world.filter = null; | |||
| world.drawTo(t); | |||
| world.filter = old; | |||
| bmpTrans = new h2d.Bitmap(h2d.Tile.fromTexture(t)); | |||
| bg.visible = true; | |||
| parts.visible = true; | |||
| initLevel(); | |||
| world.add(bmpTrans, LAYER_ENT - 1); | |||
| },0); | |||
| } | |||
| function initLevel() | |||
| { | |||
| level = Data.level.all[currentLevel]; | |||
| if( level == null ) | |||
| return; | |||
| soils = level.soils.decode(Data.soil.all); | |||
| while( soilLayer.numChildren > 0 ) | |||
| soilLayer.getChildAt(0).remove(); | |||
| // Build game board | |||
| var empty = tiles.sub(0, 2 * 32, 32, 32); | |||
| var edgeTile = tiles.sub(2*32, 2 * 32, 32, 32); | |||
| soilLayer.clear(); | |||
| for( y in 0...LH ) { | |||
| for( x in 0...LW ) { | |||
| var index = x + y * LW; | |||
| var s = soils[x + y * LW]; | |||
| if(x > 1 && x < 11 && y > 1 && y < 11) | |||
| { | |||
| // check if it is the corner or center tile | |||
| if((x==y || (x + y) == 12)&& (x == 2 || x == 6 || x == 10) ) | |||
| { | |||
| soilLayer.add(x * 32, y * 32, edgeTile); | |||
| } | |||
| else | |||
| { | |||
| soilLayer.add(x * 32, y * 32, empty); | |||
| } | |||
| } | |||
| // place object on the board | |||
| createObject(x, y); | |||
| } | |||
| } | |||
| // Handle interactions | |||
| var prevKind = null; | |||
| var clickedObjKind = null; | |||
| var clickedObj = null; | |||
| var isFirstClick = true; | |||
| var sX = 0, sY = 0; | |||
| var eX = 0, eY = 0; | |||
| var interaction = new h2d.Interactive(1000, 1000, soilLayer); | |||
| var count = 0; | |||
| interaction.onClick = function(event : hxd.Event) { | |||
| var xPos = Std.int((event.relX)/32); | |||
| var yPos = Std.int((event.relY)/32); | |||
| if (isFirstClick == true){ | |||
| sX = xPos; | |||
| sY = yPos; | |||
| //trace (isFirstClick); | |||
| clickedObj = Std.downcast(pick(sX, sY), Object); | |||
| if(clickedObj != null) | |||
| { | |||
| isFirstClick = false; | |||
| // Treat the purple circle and the purple gem as same kind | |||
| if (isKing(clickedObj.kind)) | |||
| clickedObjKind = Data.ObjectKind.Exit; | |||
| else | |||
| clickedObjKind = clickedObj.kind; | |||
| } | |||
| } | |||
| else{ | |||
| trace (prevKind); | |||
| eX = xPos; | |||
| eY = yPos; | |||
| isFirstClick = true; | |||
| //trace (isFirstClick); | |||
| var destinationObj = Std.downcast(pick(eX, eY), Object); | |||
| var isAcceptableMove = true; | |||
| if (destinationObj == null && // destination tile is empty | |||
| clickedObj != null && // you have clicked an object to move | |||
| prevKind != clickedObjKind && // alternating turns | |||
| (eX == sX || eY == sY)) // moving horizontally or vertically | |||
| { | |||
| // Check that there are no blockade between start and end | |||
| var isHorizontal = false; | |||
| var distanceToMove = 0; | |||
| var tempX = sX; | |||
| var tempY = sY; | |||
| if (eX == sX){ | |||
| distanceToMove = eY - sY; | |||
| if (distanceToMove < 0){ | |||
| tempY--; | |||
| } | |||
| else{ | |||
| tempY++; | |||
| } | |||
| } | |||
| else if (eY == sY){ | |||
| isHorizontal = true; | |||
| distanceToMove = eX - sX; | |||
| if (distanceToMove < 0){ | |||
| tempX--; | |||
| } | |||
| else{ | |||
| tempX++; | |||
| } | |||
| } | |||
| trace ('sX, sY: ' + sX + ',' + sY); | |||
| trace ('eX, eY: ' + eX + ',' + eY); | |||
| trace ('isHorizontal: ' + isHorizontal); | |||
| trace ('distanceToMove: ' + distanceToMove); | |||
| while (distanceToMove != 0){ | |||
| var oB = Std.downcast(pick(tempX, tempY), Object); | |||
| trace ('tempX, tempY: ' + tempX + ',' + tempY); | |||
| if (oB == null && isHorizontal){ | |||
| if (distanceToMove < 0) | |||
| tempX--; | |||
| else | |||
| tempX++; | |||
| } | |||
| else if (oB == null && !isHorizontal){ | |||
| if (distanceToMove < 0) | |||
| tempY--; | |||
| else | |||
| tempY++; | |||
| } | |||
| else if (oB != null){ | |||
| trace ('oB is not null '); | |||
| isAcceptableMove = false; | |||
| break; | |||
| } | |||
| if (distanceToMove > 0) | |||
| distanceToMove--; | |||
| else | |||
| distanceToMove++; | |||
| } | |||
| // check if a non-player object is moving to the cornre | |||
| if((eX == 2 || eX == 10) && (eY == 2 || eY == 10)) | |||
| { | |||
| if (!isKing(clickedObj.kind)){ | |||
| isAcceptableMove = false; | |||
| } | |||
| } | |||
| // Move the object | |||
| if (isAcceptableMove){ | |||
| // remove from the source position | |||
| clickedObj.remove(); | |||
| // create the object in the destination position | |||
| var movedObj = new ent.Object(clickedObj.kind, eX, eY); | |||
| if ((eX == 2 || eX == 10) && (eY == 2 || eY == 10)){ | |||
| // End game if reached the corner | |||
| if (isKing(movedObj.kind)){ | |||
| displayEnd(); | |||
| } | |||
| } | |||
| prevKind = clickedObjKind; | |||
| //To Do: Add Logic for Capture | |||
| /*if (eX == sX){ | |||
| if (distanceToMove > 0){ | |||
| var obJ = Std.downcast(pick(eX, eY + 2), Object); | |||
| var Obj = Std.downcast(pick(eX, eY + 1), Object); | |||
| if (obJ != null && Obj != null){ | |||
| if (obJ.kind == movedObj.kind && Obj.kind != movedObj.kind){ | |||
| if (movedObj.kind == Square3) | |||
| movedObj.kind = Exit; | |||
| else if (obJ.kind == Square3){ | |||
| obJ.kind = Exit; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| }*/ | |||
| } | |||
| } | |||
| else | |||
| { | |||
| isAcceptableMove = false; | |||
| } | |||
| if(!isAcceptableMove && errorSound != null) | |||
| { | |||
| errorSound.play(false, 0.5 + Math.random() * 0.5); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| function displayEnd() { | |||
| end = new h2d.Bitmap(hxd.Res.end_png.toTile()); | |||
| end.scale(1); | |||
| world.add(end, LAYER_END); | |||
| // Pause for 5 sec and then end the game | |||
| haxe.Timer.delay(function() { | |||
| Game.restartGame(); | |||
| }, 5000); | |||
| } | |||
| function createObject(x, y) : ent.Entity { | |||
| var myX = x * 1; | |||
| var myY = y * 1; | |||
| if(x==6 && y == 6) | |||
| { | |||
| return new ent.Object(Square2, x, y); | |||
| } | |||
| else if ( ((x > 4 && x < 8) && ((y == 2) || (y == 10))) || | |||
| ((y > 4 && y < 8) && ((x == 2) || (x == 10))) || | |||
| (x == 6 && (y == 3 || y == 9)) || | |||
| (y == 6 && (x == 3 || x == 9)) | |||
| ) | |||
| { | |||
| return new ent.Object(Square1, x, y); | |||
| } | |||
| else if ( (x == 6 && (y > 3 && y < 6)) || | |||
| (x == 6 && (y > 6 && y < 9)) || | |||
| (y == 6 && (x > 3 && x < 6)) || | |||
| (y == 6 && (x > 6 && x < 9)) | |||
| ) | |||
| { | |||
| return new ent.Object(Exit, x, y); | |||
| } | |||
| return null; | |||
| } | |||
| function isKing(kind : Data.ObjectKind ){ | |||
| return (kind == Square2); | |||
| } | |||
| function getSoil( x, y ) : Data.SoilKind { | |||
| if( x < 0 || y < 0 || x >= LW || y >= LH ) | |||
| return Block; | |||
| return soils[x + y * LH].id; | |||
| } | |||
| function pick( x : Float, y : Float ) { | |||
| var ix = Std.int(x); | |||
| var iy = Std.int(y); | |||
| for( e in entities ) | |||
| { | |||
| if( Std.int(e.x) == ix && Std.int(e.y) == iy ) | |||
| { | |||
| return e; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| override function init() { | |||
| errorSound = hxd.Res.load("sfx/error.wav").toSound(); | |||
| // preload sounds | |||
| for( s in hxd.Res.load("sfx") ) | |||
| s.toSound().getData(); | |||
| s2d.scaleMode = Stretch(LW * 32, LH * 32); | |||
| currentLevel = 1; | |||
| world = new h2d.Layers(s2d); | |||
| world.filter = new h2d.filter.Bloom(0.5,0.2,3); | |||
| tiles = hxd.Res.tiles.toTile(); | |||
| soilLayer = new h2d.TileGroup(tiles); | |||
| bg = new h2d.Object(world); | |||
| bg.filter = new h2d.filter.Blur(3); | |||
| bg.filter.smooth = true; | |||
| var tbg = tiles.sub(32 * 3, 64, 32, 32); | |||
| tbg.scaleToSize(LW * 32, LH * 32); | |||
| new h2d.Bitmap(tbg, bg).addShader(hueShaderHalf); | |||
| // Display background clouds | |||
| var rnd = new hxd.Rand(42); | |||
| var ctiles = [for( i in 0...3 ) tiles.sub(i * 32 * 3, 192, 32 * 3, 64, -32 * 3 >> 1, -32)]; | |||
| for( i in 0...100 ) { | |||
| var b = new h2d.Bitmap(ctiles[rnd.random(ctiles.length)], bg); | |||
| b.smooth = true; | |||
| b.addShader(hueShaderHalf); | |||
| clouds.push({ sc : 0.7 + rnd.rand(), x : rnd.rand() * (LW * 32 + 200) - 100, y : rnd.rand() * (LH * 32 + 200) - 100, speed : rnd.rand() + 1, spr : b, t : Math.random() * Math.PI * 2 }); | |||
| } | |||
| // Display the flying snow | |||
| var ptiles = hxd.Res.envParts.toTile().split(); | |||
| parts = new h2d.SpriteBatch(ptiles[0]); | |||
| world.add(parts, LAYER_ENVP); | |||
| for( i in 0...100 ) | |||
| parts.add(new EnvPart(ptiles[Std.random(ptiles.length)])); | |||
| world.add(soilLayer, LAYER_SOIL); | |||
| pad = hxd.Pad.createDummy(); | |||
| hxd.Pad.wait(function(p) pad = p); | |||
| // Display title and instruction to start game | |||
| title = new h2d.Bitmap(hxd.Res.title.toTile(), world); | |||
| var tf = new h2d.Text(hxd.res.DefaultFont.get(), title); | |||
| tf.textColor = 0; | |||
| tf.text = "Press space to start"; | |||
| tf.x=180; | |||
| tf.y = 180; | |||
| } | |||
| override function update( dt : Float ) { | |||
| dt *= 60; // old dt support | |||
| if( bmpTrans != null ) { | |||
| bmpTrans.alpha -= 0.05 * dt; | |||
| if( bmpTrans.alpha < 0 ) { | |||
| bmpTrans.tile.getTexture().dispose(); | |||
| bmpTrans.remove(); | |||
| bmpTrans = null; | |||
| } | |||
| } | |||
| for( e in entities.copy() ) | |||
| e.update(dt); | |||
| var ang = -0.3; | |||
| for( c in clouds ) { | |||
| var ds = c.speed * dt * 0.3 * way; | |||
| c.t += ds * 0.01; | |||
| c.spr.setScale(1 + Math.sin(c.t) * 0.2); | |||
| c.spr.scaleX *= c.sc; | |||
| c.x += Math.cos(ang) * ds; | |||
| c.y += Math.sin(ang) * ds; | |||
| c.spr.x = c.x; | |||
| c.spr.y = c.y; | |||
| if( c.x > LW * 32 + 100 ) | |||
| c.x -= LW * 32 + 300; | |||
| if( c.y > LH * 32 + 100 ) | |||
| c.y -= LH * 32 + 300; | |||
| if( c.x < -100 ) | |||
| c.x += LW * 32 + 300; | |||
| if( c.y < -100 ) | |||
| c.y += LH * 32 + 300; | |||
| } | |||
| parts.hasRotationScale = true; | |||
| for( p in parts.getElements() ) { | |||
| var p = cast(p, EnvPart); | |||
| var ds = dt * p.speed * way; | |||
| p.x += Math.cos(ang) * ds; | |||
| p.y += Math.sin(ang) * ds; | |||
| p.rotation += ds * p.rspeed; | |||
| if( p.x > LW * 32 ) | |||
| p.x -= LW * 32; | |||
| if( p.y > LH * 32 ) | |||
| p.y -= LH * 32; | |||
| if( p.y < 0 ) | |||
| p.y += LH * 32; | |||
| if( p.x < 0 ) | |||
| p.x += LW * 32; | |||
| } | |||
| if( title != null && title.alpha < 1 ) { | |||
| title.alpha -= 0.01 * dt; | |||
| if( title.alpha < 0 ) { | |||
| title.remove(); | |||
| title = null; | |||
| } | |||
| } | |||
| if( title != null && title.alpha == 1 ) { | |||
| if(K.isPressed(K.SPACE)) { | |||
| title.alpha = 0.99; | |||
| loadGame(); | |||
| } | |||
| } | |||
| } | |||
| public static var inst : Game; | |||
| static function main() { | |||
| #if js | |||
| hxd.Res.initEmbed(); | |||
| #else | |||
| hxd.res.Resource.LIVE_UPDATE = true; | |||
| hxd.Res.initLocal(); | |||
| #end | |||
| Data.load(hxd.Res.data.entry.getText()); | |||
| inst = new Game(); | |||
| } | |||
| static function restartGame() { | |||
| Game.main(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,81 @@ | |||
| package ent; | |||
| class Entity { | |||
| var game : Game; | |||
| public var inf : Data.Object; | |||
| public var kind : Data.ObjectKind; | |||
| public var x : Float; | |||
| public var y : Float; | |||
| public var spr : h2d.Anim; | |||
| public function new( kind, x : Int, y : Int ) { | |||
| game = Game.inst; | |||
| this.kind = kind; | |||
| inf = Data.object.get(kind); | |||
| this.x = x + 0.5; | |||
| this.y = y + 0.5; | |||
| spr = new h2d.Anim(getAnim(), 15); | |||
| game.world.add(spr, hasFlag(Under) ? Game.LAYER_ENT_UNDER : Game.LAYER_ENT); | |||
| game.entities.push(this); | |||
| } | |||
| public function hasFlag(f) { | |||
| return inf.flags.has(f); | |||
| } | |||
| public function isOccupied() { | |||
| if( getObj(Std.int(x), Std.int(y)) != null ) | |||
| return true; | |||
| return false; | |||
| } | |||
| public function isCollide( with : ent.Entity ) { | |||
| return true; | |||
| } | |||
| function getObj( x : Int, y : Int, ?k : Data.ObjectKind, ?flags : Array<Data.Object_flags> ) { | |||
| for( e in game.entities ) { | |||
| var o = Std.downcast(e, Object); | |||
| if( o == null || o.carried || o == this ) continue; | |||
| if( Std.int(o.x) != x || Std.int(o.y) != y ) continue; | |||
| if( flags != null ) { | |||
| var ok = true; | |||
| for( f in flags ) | |||
| if( !o.inf.flags.has(f) ) { | |||
| ok = false; | |||
| break; | |||
| } | |||
| if( !ok ) continue; | |||
| } | |||
| if( k == null || o.kind == k ) | |||
| return o; | |||
| } | |||
| return null; | |||
| } | |||
| public function canPick() { | |||
| return false; | |||
| } | |||
| public function remove() { | |||
| spr.remove(); | |||
| game.entities.remove(this); | |||
| } | |||
| function getAnim() { | |||
| return [game.tiles.sub(inf.image.x * 32, inf.image.y * 32, 32, 32, -16, -16)]; | |||
| } | |||
| public function update( dt : Float ) { | |||
| spr.x = Std.int(x * 64) / 2; | |||
| spr.y = Std.int(y * 64) / 2; | |||
| } | |||
| function toString() { | |||
| return kind + "(" + Std.int(x) + "," + Std.int(y) + ")"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,132 @@ | |||
| package ent; | |||
| import Data.ObjectKind; | |||
| class Object extends Entity { | |||
| var speed = 0.2; | |||
| var angle = 0.; | |||
| var wasCarried = false; | |||
| var color : h3d.shader.ColorAdd; | |||
| var pulse : Float = 0.; | |||
| var hintAct : h2d.Anim; | |||
| public var active : Bool; | |||
| public var carried(default, set) : Bool = false; | |||
| public function new(k, x, y) { | |||
| super(k, x, y); | |||
| switch( kind ) { | |||
| case Square1, Square2, Square3, Wings: | |||
| var a = new h2d.Anim([for( i in 0...9 ) game.tiles.sub(i * 32, 256 + (kind == Wings ? 64 : kind == Square2 ? 32 : 0), 32, 32, -16, -16)], 20, spr); | |||
| a.loop = false; | |||
| a.onAnimEnd = function() { | |||
| haxe.Timer.delay(function() { | |||
| a.currentFrame = 0; | |||
| }, 200 + Std.random(400)); | |||
| }; | |||
| if( kind == Square3 ) | |||
| a.adjustColor({ hue : Math.PI / 2 }); | |||
| hintAct = a; | |||
| case Plate1, Plate2, Plate3, Plate4: | |||
| game.soilLayer.add(Std.int(x) * 32, Std.int(y) * 32, game.tiles.sub(64, 32, 32, 32)); | |||
| spr.alpha = 0.8; | |||
| case Hero: | |||
| game.soilLayer.add(Std.int(x) * 32, Std.int(y) * 32, game.tiles.sub(0, 96, 32, 32)); | |||
| spr.alpha = 1; | |||
| default: | |||
| } | |||
| } | |||
| function set_carried(b) { | |||
| var ix = Std.int(x); | |||
| var iy = Std.int(y); | |||
| if( b ) | |||
| active = false; | |||
| wasCarried = carried; | |||
| game.world.add(spr, b ? Game.LAYER_CARRY : Game.LAYER_ENT); | |||
| return carried = b; | |||
| } | |||
| override function isCollide( with : ent.Entity ) { | |||
| return with != null && with.kind != Hero; | |||
| } | |||
| override function canPick() { | |||
| if( hasFlag(Under) ) | |||
| return false; | |||
| if( carried ) | |||
| return false; | |||
| return true; | |||
| } | |||
| override function getAnim() { | |||
| return switch( kind ) { | |||
| case Exit: | |||
| [for( i in 0...6 ) game.tiles.sub(i * 32, 160, 32, 32, -16, -16)]; | |||
| default: | |||
| super.getAnim(); | |||
| } | |||
| } | |||
| override public function update(dt:Float) { | |||
| if( hintAct != null ) | |||
| hintAct.visible = !active; | |||
| else if( active ) { | |||
| pulse += dt * 0.1; | |||
| spr.adjustColor({ saturation : Math.abs(Math.sin(pulse)) * 0.5, lightness : Math.abs(Math.sin(pulse)) * 0.2 }); | |||
| } else if( pulse != 0 ) { | |||
| pulse %= Math.PI; | |||
| pulse += dt * 0.1; | |||
| if( pulse > Math.PI ) | |||
| pulse = 0; | |||
| spr.adjustColor({ saturation : Math.abs(Math.sin(pulse)) * 0.5, lightness : Math.abs(Math.sin(pulse)) * 0.2 }); | |||
| } | |||
| if( spr.scaleX < 1 ) { | |||
| spr.scale(Math.pow(1.05, dt)); | |||
| if( spr.scaleX > 1 ) { | |||
| spr.setScale(1); | |||
| spr.smooth = false; | |||
| } | |||
| } | |||
| var ix = Std.int(x), iy = Std.int(y); | |||
| switch( kind ) { | |||
| case Exit: | |||
| if( game.allActive ) { | |||
| spr.speed = 15; | |||
| } else { | |||
| spr.speed = 0; | |||
| spr.currentFrame = 0; | |||
| } | |||
| case Square1: | |||
| active = getObj(ix, iy, [Plate1, Plate2][game.hueValue], [CanPutOver]) != null; | |||
| case Square2: | |||
| active = getObj(ix, iy, [Plate2, Plate1][game.hueValue], [CanPutOver]) != null; | |||
| case Square3: | |||
| if( game.hueValue == 0 ) | |||
| active = getObj(ix, iy, Plate3, [CanPutOver]) != null || getObj(ix, iy, Steal, [CanPutOver]) != null; | |||
| else | |||
| active = getObj(ix, iy, Plate4, [CanPutOver]) != null; | |||
| case Wings: | |||
| var obj = getObj(ix, iy, [CanPutOver]); | |||
| active = obj != null && obj.kind != Steal; | |||
| default: | |||
| } | |||
| if( wasCarried ) { | |||
| var tx = x * 32, ty = y * 32; | |||
| var d = hxd.Math.distance(tx - spr.x, ty - spr.y); | |||
| if( d > 1 ) { | |||
| spr.x = hxd.Math.lerp(spr.x, tx, 1 - Math.pow(0.7, dt)); | |||
| spr.y = hxd.Math.lerp(spr.y, ty, 1 - Math.pow(0.7, dt)); | |||
| return; | |||
| } | |||
| wasCarried = false; | |||
| } | |||
| super.update(dt); | |||
| } | |||
| } | |||