2
* This file is part of the dis-Emi-A HaXe Library. Copyright (c) edA-qa mort-ora-y
3
* For full copyright and license information please refer to doc/license.txt.
8
import flash.display.BitmapData;
9
import flash.display.Sprite;
14
import flashx.ObjectCollider;
17
* Contains all game related elements (abstract information and links
20
class Game extends gamex.BaseGameDriver<GameObject>
22
public var global : Global;
24
//referencable objects
25
public var corePanel : CorePanel;
26
public var cursor : PlayerCursor;
27
public var selector : GameSelector;
28
public var surface : Surface;
29
public var edgeTimer : EdgeTimer;
30
public var miniPuzzle : MiniPuzzle;
31
public var scoring : Scoring;
33
//game behaviour config
34
public var constrainSelectorToCursor : Bool; //constraint the selector to the cursor (requires useCursor == true)
35
public var lockCursorOnSelector : Bool;
36
public var innerMonsterOverlap : Bool; //can the inner monster overlap the borders?
37
public var useCursor : Bool; //will a cursor be used/displayed
38
public var useDemoIMS : Bool; //use a demo sprite for the inner monster
39
public var useCircleSelector : Bool; //flase=use trace selector
40
public var allowCursorJitter : Bool; //improves movement, but cursor then jitters
41
public var allowSelectorEscape : Bool; //can a selection be prematurely finished?
42
public var traceAllowCross : Bool; //allow lines to cross during trace selection
43
public var cursorStartOnEdge : Bool; //the cursor always starts on the nearest edge, otherwise it can float
44
public var enableMouseCursor : Bool; //use the mouse to control cursor
45
public var useStickyKeys : Bool; //use sticky cursor control
46
public var useMiniPuzzle : Bool; //should the minipuzzle be used
47
public var useInnerBonus : Bool; //should inner bonuses be created
50
public var cursorPhase : CursorPhase;
52
public var numLives : Int; //number of player remaining "lives"
53
public var gamePhase : GamePhase; //should we go to the next level
54
public var score : Int;
55
public var nextLifeScore : Int;
56
public var curLevel : Int; //level counter (starts at 0, to be displayed as 1)
58
//public to allow other GameObjects to use it...
59
public var goodCollider : ObjectCollider; //use when collision would benefit player (looser collision criteria)
60
public var badCollider : ObjectCollider; //use when collision harms player (tighter collision criteria)
61
public var neutralCollider : ObjectCollider; //use when outcome has no positive or negative impact, and checking should be balanced
63
public function new( difficulty : Int )
67
global = new Global( difficulty, 0 );
69
badCollider = new ObjectCollider(flash.Lib.current.stage, 0.95);
70
goodCollider = new ObjectCollider(flash.Lib.current.stage, 0.05);
71
neutralCollider = new ObjectCollider(flash.Lib.current.stage, 0.5);
72
scoring = new Scoring( this );
75
constrainSelectorToCursor = true;
76
lockCursorOnSelector = true;
77
innerMonsterOverlap = false;
80
useCircleSelector = false;
81
allowCursorJitter = false;
82
allowSelectorEscape = false;
83
traceAllowCross = false;
84
cursorStartOnEdge = false;
88
//non-behavioural options (loaded from global options)
89
enableMouseCursor = Options.enableMouseCursor; //if false, assume keyboard cursor, both combined has little sense...
90
useStickyKeys = Options.useStickyKeys; //something feels just wrong about this mode
94
cursorStartOnEdge = true;
95
global.numInnerMonsters = 0;
96
global.numEdgeMonsters = 0;
97
useMiniPuzzle = false;
100
Assert.isTrue( useCursor || !constrainSelectorToCursor );
101
Assert.isTrue( constrainSelectorToCursor || useCircleSelector );
102
Assert.isFalse( traceAllowCross ); //unless two ambigious trace conditions are resolved..
104
numLives = global.startingLives;
105
gamePhase = GamePhase.None;
107
nextLifeScore = global.extraLifePointDelta;
111
public function start()
113
gamePhase = GamePhase.LevelStart;
117
override function _stepTime( elapsed : Float )
119
//var start = flash.Lib.getTimer();
121
scoring.checkBonusLife();
123
//should any of these return false, it means to stop evaluating the next ones
124
//thus, the order here forms a priority
127
&& checkRestoreCursor()
128
&& checkSelectorCursorDie() //perhaps these should be
129
&& checkEdgeCursorDie(); //self-checking somehow, like PuzzlePiece...?
132
//var end = flash.Lib.getTimer();
133
//trace( (end - start ) );
136
function checkNewLevel() : Bool
138
if( gamePhase == GamePhase.LevelStart )
140
gamePhase = GamePhase.Action;
141
surface = new Surface( global.surfaceSize.x, global.surfaceSize.y ); //needs to come first, before others might look at it
143
//start on the edge phase (though perhaps the cursor itself decides this)
144
cursorPhase = CursorPhase.Edge;
146
//create the inner monster
147
for( i in 0...global.numInnerMonsters )
149
var ims : InnerMonsterSprite;
151
ims = new IMSSimple()
154
new InnerMonster( this, ims );
157
for( i in 0...global.numEdgeMonsters )
158
new EdgeMonster( this, i );
159
if( global.numEdgeMonsters > 0 )
160
new EdgeTimer( this );
163
new MiniPuzzle( this );
167
new InnerBonus( this, Point2.at( surface.width * 0.2, surface.height * 0.2 ) );
168
new InnerBonus( this, Point2.at( surface.width * 0.2, surface.height * 0.8 ) );
169
new InnerBonus( this, Point2.at( surface.width * 0.8, surface.height * 0.2 ) );
170
new InnerBonus( this, Point2.at( surface.width * 0.8, surface.height * 0.8 ) );
173
postEvent( new GameEvent( GameEvent.NewLevel ) );
174
new LevelStart( this );
182
//allows another object to indicate we should start the next level
183
public function startNewLevel()
185
/* Note that the PostLevelOver event is done synchronously to ensure that
186
* it is finished before the new level actually starts
188
if( gamePhase == GamePhase.LevelEnd )
190
dispatchEvent( new GameEvent( GameEvent.PostLevelOver ) );
191
//only do in this case since otherwise we may just be starting the first time
193
//recreate global params
194
global = new Global( global.difficulty, curLevel );
196
gamePhase = GamePhase.LevelStart;
199
public function startLevelEnd()
201
//there is a possible (and once realized) error where two level end events could
202
//trigger at the same time
203
if( gamePhase != GamePhase.Action )
205
gamePhase = GamePhase.LevelEnd;
206
postEvent( new GameEvent( GameEvent.LevelOver ) );
209
Options.ifSetLevelStatus( curLevel, Options.statusNormal );
212
public function endLevelEnd()
214
Assert.isTrue( gamePhase == GamePhase.LevelEnd );
215
new LevelOver( this );
218
function checkLevelOver() : Bool
220
if( gamePhase != GamePhase.Action )
223
//only if not already going to a newlevel...
224
if( surface.cleared >= global.levelClearAt )
234
function checkRestoreCursor() : Bool
236
if( gamePhase != GamePhase.Action )
240
if( cursor == null && useCursor )
250
new PlayerCursor( this );
257
//public so GameLayout can call (premature end)
258
public function endGame()
260
//post the level was over (so cleanup occurs)
261
postEvent( new GameEvent( GameEvent.LevelOver ) );
262
new GameOver( this );
263
postEvent( new GameEvent( GameEvent.GameOver ) );
264
gamePhase = GamePhase.GameOver;
267
function checkSelectorCursorDie() : Bool
269
if( gamePhase != GamePhase.Action )
272
if( selector == null )
275
for( go in gameObjects )
276
if( Std.is( go, InnerMonster )
277
&& go.getCorePanelCollisionObject() != null )
279
if( badCollider.doCollide(
280
go.getCorePanelCollisionObject(),
281
selector.getCorePanelCollisionObject()
284
postEvent( new GameEvent( GameEvent.CursorDie ) );
292
function checkEdgeCursorDie() : Bool
294
if( gamePhase != GamePhase.Action )
298
|| cursorPhase != CursorPhase.Edge
299
|| cursor.getCorePanelCollisionObject() == null )
302
for( go in gameObjects )
303
if( Std.is( go, EdgeMonster )
304
&& go.getCorePanelCollisionObject() != null )
306
//TODO: Check actual position on grid to prevent nearby death... (hmm, I like if the way it is)
307
if( badCollider.doCollide(
308
go.getCorePanelCollisionObject(),
309
cursor.getCorePanelCollisionObject()
312
postEvent( new GameEvent( GameEvent.CursorDie ) );
320
public function isCursorNearEdgeKiller() : Bool
325
for( go in gameObjects )
326
if( Std.is( go, EdgeMonster ) )
328
//TODO: genarlize locating objects...
329
var em = cast( go, EdgeMonster );
330
var dist = em.getSPos().distanceTo( cursor.getSPos() );
331
if( dist < global.cursorInvincibleDist )
338
/////////////////////////////////////////////////////////////////////////////////////////////////////////
340
public function buttonEnd()
342
if( selector != null )
343
selector.buttonEnd();
346
public function buttonStart()
348
//only does something in action mode
349
if( gamePhase != GamePhase.Action )
352
if( selector == null )
354
if( useCircleSelector )
355
new CircleSelector( this );
357
new TraceSelector( this );
361
///////////////////////////////////////////////////////////////////////////////////////////////////////
362
// Common game operations with no other home
365
* Determines if the indicated piece can be cleared from the surface.
367
* if numMonsters == 1
368
* allowed = dc does not intersect monster
370
* allowed = true (if there is no monster, and to allow monster killing on higher levels)
372
public function allowedToClear( dc : Sprite ) : Bool
374
//translate into local world (via intermediary as to not destroy Sprite)
375
var trans = new Sprite();
376
trans.addChild( dc );
377
var scale = corePanel.surfaceSizeToLocal( Point2.at( 1, 1 ) );
378
var tl = corePanel.surfaceToLocal( Point2.at( 0, 0 ) );
381
trans.scaleX = scale.x;
382
trans.scaleY = scale.y;
383
corePanel.addChild( trans );
387
for( go in gameObjects )
388
if( Std.is( go, InnerMonster )
389
&& go.getCorePanelCollisionObject() != null )
392
ret = ret && !neutralCollider.doCollide( go.getCorePanelCollisionObject(), trans );
398
trans.removeChild( dc );
399
corePanel.removeChild( trans );
400
return count != 1 || ret;
403
public function clearSurface( dc : Sprite ) : Void
405
var oldCleared = surface.cleared;
407
var diffCleared = surface.cleared - oldCleared;
408
var bounds = dc.getBounds( null );
409
postEvent( GameEvent.newSegmentCleared( diffCleared, Rect2.fromFlash( bounds ) ) );