1 // ---
  2 // Copyright (c) 2010 Francesco Cottone, http://www.kesiev.com/
  3 // ---
  4 
  5 /**
  6  * @namespace
  7  * Gamecycle contains your basic game loop: intro, menus, 
  8  * crossfading between stages/lifes, gameover and ending. 
  9  */
 10 var gamecycle={
 11 
 12 	/**
 13 	 * Gamecycle constructor - initializes a new game object
 14 	 * 
 15 	 * @param	id		unique id of object
 16 	 * @param	group		name of group to store the object in
 17 	 */
 18 	createMaingame:function(id,group) {
 19 	return gbox.addObject({
 20 		id:id,
 21 		group:group,
 22 		counter:0,
 23 		difficulty:0,
 24 		
 25 		// state transition
 26 		state:50,  
 27 		stateFirstIteration:true, 
 28 		
 29 		hud:{},
 30 		
 31 		/**
 32 		 * This method is called whenever you load a new map. It's meant to be
 33 		 * overridden when you create your game.
 34 		 */
 35 		changeLevel:function() { },
 36 		
 37 		/**
 38 		 * This method is called every time a player is "reborn". This method is 
 39 		 * meant to be overridden since you have to do garbage collection. 
 40 		 */
 41 		newLife:function() { },
 42 
 43 		// game disclaimer animation (if needed)
 44 		gameDisclaimerAnimation:function(reset) {
 45 			return true;
 46 		 },
 47 		
 48 		// game intro animation
 49 		gameIntroAnimation:function(reset) {
 50 			if (reset) {
 51 				gbox.stopChannel("bgmusic");
 52 				toys.resetToy(this,"default-blinker");
 53 			} else {
 54 				gbox.blitFade(gbox.getBufferContext(),{alpha:1});
 55 				return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"LETS BEGIN!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:6});
 56 			}
 57 		 },
 58 		 
 59 		// level intro animation
 60 		levelIntroAnimation:function(reset) {
 61 			if (reset) {
 62 				gbox.stopChannel("bgmusic");
 63 				toys.resetToy(this,"default-blinker");
 64 			} else {
 65 				gbox.blitFade(gbox.getBufferContext(),{alpha:1});
 66 				return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"GET READY!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:6});
 67 			}
 68 		 },
 69 	  
 70 		 // Life intro animation
 71 		 newlifeIntroAnimation:function(reset) {
 72 			 if (reset) {
 73 				gbox.stopChannel("bgmusic");
 74 				toys.resetToy(this,"default-blinker");
 75 			} else {
 76 				gbox.blitFade(gbox.getBufferContext(),{alpha:1});
 77 				return toys.text.fixed(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"GET READY!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),time:30});
 78 			}
 79 		},
 80 		
 81 		// gameover animation
 82 		gameoverIntroAnimation:function(reset) {
 83 			 if (reset) {
 84 				gbox.stopChannel("bgmusic");
 85 				toys.resetToy(this,"default-blinker");
 86 			} else {
 87 				gbox.blitFade(gbox.getBufferContext(),{alpha:1});
 88 				return toys.text.fixed(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"GAME OVER",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),time:50});
 89 			}
 90 		},
 91 		
 92 		// game title animation
 93 		gameTitleIntroAnimation:function(reset) {
 94 			if (reset)
 95 				gbox.stopChannel("bgmusic");
 96 			else {
 97 				gbox.blitFade(gbox.getBufferContext(),{alpha:1});
 98 				gbox.blitText(gbox.getBufferContext(),{font:"small",text:"GAME TITLE",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH()-100});
 99 			}
100 		},
101 		
102 		// End level animation
103 		endlevelIntroAnimation:function(reset) {
104 			 if (reset) {
105 				 toys.resetToy(this,"default-blinker");
106 			} else {
107 				return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"WELL DONE!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:10});
108 			}
109 		},
110 		
111 		// Game ending
112 		gameEndingIntroAnimation:function(reset) {
113 			if (reset) {
114 				toys.resetToy(this,"default-blinker");
115 			} else {
116 				gbox.blitFade(gbox.getBufferContext(),{alpha:1});
117 				return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"CONGRATULATIONS!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:10});
118 			}		  	
119 		},
120 		
121 		// PRESS START
122 		pressStartIntroAnimation:function(reset) {
123 			if (reset) {
124 				toys.resetToy(this,"default-blinker");
125 			} else {
126 				toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"PRESS A TO START",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:Math.floor(gbox.getScreenH()/3),dw:gbox.getScreenW(),dh:Math.floor(gbox.getScreenH()/3)*2,blinkspeed:10});
127 				return gbox.keyIsHit("a");
128 			}
129 		},
130 		
131 		/**
132 		 * This method is called when the player dies.
133 		 */
134 		gameIsOver:function() { return true; },
135 		
136 		/** 
137 		 * Actions done during the game (i.e. stage is clear or other ending conditions)
138 		 */
139 		gameEvents:function() {
140 		
141 		},
142 		
143 		gameMenu:function(reset) {
144 			if (reset) {
145 				toys.resetToy(this,"difficulty");
146 			} else {
147 				gbox.blitFade(gbox.getBufferContext(),{alpha:0.5});
148 				if (toys.ui.menu(this,"difficulty",{audiooption:"default-menu-option",audioconfirm:"default-menu-confirm",font:"small",keys:{up:"up",down:"down",ok:"a",cancel:"b"},selector:">",items:["EASY","NORMAL","HARD"],x:10,y:10})) {
149 					if (toys.getToyValue(this,"difficulty","ok") == -1) return -1;
150 					else {
151 						this.difficulty=toys.getToyValue(this,"difficulty","selected");
152 						return true;
153 					}
154 				}
155 				return false;
156 			}
157 		},
158 	  
159 		// CHECK
160 		
161 		gameIsHold:function() { // Use this clause to check collision and kill player: if true the level is changing
162 			return (this.state==400)||(this.state==401);
163 		},
164 		
165 		isCompleted:function() {
166 			return (this.state==800);
167 		},
168 		
169 		// GAME CYCLE
170 		
171 		getNextLevel:function() {
172 			return this._nextlevel;
173 		},
174 		
175 		gotoLevel:function(level) {
176 			this._nextlevel=level;
177 			this.setState(400);
178 		},
179 		
180 		playerDied:function(data) {
181 			this._loselife=data;
182 			this.setState(500);
183 		},
184 		
185 		gameIsCompleted:function() {
186 			this.setState(800);
187 		},
188 		
189 		// private methods
190 		
191 		/**
192 		 * Changes the current game state
193 		 * 
194 		 * @param	st	state number
195 		 */
196 		setState:function(st) {
197 			this.state=st;
198 			this.stateFirstIteration=true;
199 		},
200 	
201 		/*
202 		 * Removes all objects in each group except the game 
203 		 * cycle group. Used for garbage collection when resetting the game.
204 		 */	
205 		_resetGroups:function() {
206 			var g=gbox.getGroups();
207 			for (var i=0;i<g.length;i++)
208 				if (g[i]!=this.group) gbox.clearGroup(g[i]);
209 			gbox.soloGroup(this.group);
210 		},
211 
212 		stateIsReady:function() { this.stateFirstIteration=false; },
213 
214 		blit:function() {
215 			switch (this.state) {
216 
217 				// Disclaimer
218 				case 50: {
219 					if (this.stateFirstIteration) {
220 						this._resetGroups();
221 						this.gameDisclaimerAnimation(true);
222 						this.stateIsReady();
223 					}
224 					if (this.gameDisclaimerAnimation(false)) 
225 						this.setState(100);
226 					break;
227 				}
228 				// main menu
229 				case 100: 
230 				case 101:
231 				case 102: { // Press Start / Menu
232 					if (this.stateFirstIteration && (this.state == 100)) {
233 						this._resetGroups();
234 						this.gameTitleIntroAnimation(true);
235 					}
236 					this.gameTitleIntroAnimation(false);
237 					switch (this.state) {
238 						case 100: { // Press to start
239 							if (this.stateFirstIteration) {
240 								gbox.resetChannel("bgmusic");
241 								this.pressStartIntroAnimation(true);
242 								this.stateIsReady();
243 							}
244 							if (this.pressStartIntroAnimation(false)) this.setState(101);
245 							break;
246 						}
247 						case 101: { // Game menu
248 							if (this.stateFirstIteration) {
249 								gbox.setChannelVolume("bgmusic",0.5);
250 								this.gameMenu(true);
251 								this.stateIsReady();
252 							}
253 							
254 							var menu=this.gameMenu(false);
255 							if (menu)
256 								if (menu == -1) this.setState(100); else this.setState(102);
257 							break;
258 						}
259 						case 102: { // Fader
260 							if (this.stateFirstIteration) {
261 								this._resetGroups();
262 								toys.resetToy(this,"fadeout");
263 								this.stateIsReady();
264 							}
265 							if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"}))
266 								this.setState(200);
267 							break;
268 						}
269 						break;
270 					}
271 					break;
272 				}
273 				case 200:// Game intro animation
274 				
275 				case 300:// Start game
276 				case 301:// Game is going
277 				
278 				case 400:// Fade out to change level
279 				case 401:// Level animation (levelIntroAnimation)
280 				case 402:// Fade in to next level
281 				
282 				case 500:// Wait after dead
283 				case 501:// Dead fadeout
284 				
285 				case 600:// Next life intro
286 				case 601:// New life fadein
287 				
288 				case 700:// Gameover animation
289 
290 				case 800:// Fade out game ending
291 				case 801:// Game ending
292 
293 				{ // Game playing
294 					if (this.stateFirstIteration) {
295 						switch (this.state) {
296 							case 200: { // Game intro
297 								toys.resetToy(this,"fadein");
298 								this.level=null;
299 								this._nextlevel=null;
300 								this.hud=toys.ui.hud("maingamehud");
301 								
302 								this.initializeGame();
303 								this.gameIntroAnimation(true);
304 								
305 								break;
306 							}
307 							case 300: {
308 								// Game start
309 								this.level=this._nextlevel;
310 								gbox.playAllGroups();
311 								this.changeLevel(this._nextlevel);
312 							}
313 							case 800:
314 							case 400:{
315 								this.endlevelIntroAnimation(true);
316 								toys.resetToy(this,"fadeout");
317 								break;
318 							}
319 							case 501: {
320 								toys.resetToy(this,"fadeout");
321 								break;
322 							}
323 							case 401: {
324 								gbox.soloGroup(this.group);
325 								this.levelIntroAnimation(true);
326 								break;
327 							}
328 							case 402: {
329 								toys.resetToy(this,"fadein");
330 								this.level=this._nextlevel;
331 								gbox.playAllGroups();
332 								this.changeLevel(this._nextlevel);
333 								break;
334 							}
335 							case 600: {
336 								gbox.soloGroup(this.group);
337 								this.newlifeIntroAnimation(true);
338 								break;
339 							}
340 							case 500: {
341 								this._loselife.counter=0;
342 								break;
343 							}
344 							case 601: {
345 								toys.resetToy(this,"fadein");
346 								this.newLife();
347 								gbox.playAllGroups();
348 								break;
349 							}
350 							case 700: {
351 								gbox.resetChannel("bgmusic");
352 								gbox.soloGroup(this.group);
353 								this.gameoverIntroAnimation(true);
354 								break;
355 							}
356 							case 801: {
357 								gbox.resetChannel("bgmusic");
358 								gbox.soloGroup(this.group);
359 								this.gameEndingIntroAnimation(true);
360 								break;
361 							}
362 						}
363 						this.stateIsReady();
364 					}
365 					
366 					switch (this.state) {
367 						case 200: { // Game intro
368 							if (this.gameIntroAnimation(false)) this.setState(300);
369 							break;
370 						}
371 						case 601: // Fade in with new life
372 						case 402: // Fade in after level change
373 						case 300: { // Fade in at the beginning of the game
374 							if (toys.fullscreen.fadein(this,"fadein",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) this.setState(301);
375 							break;
376 						}
377 						case 301: { // Ingame stuff
378 							this.gameEvents();
379 							break;
380 						}
381 						case 400: { // Fade out before changing the level
382 							if (this.endlevelIntroAnimation(false))
383 								if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) this.setState(401);
384 							break;
385 						}
386 						case 800: { // Fade out before game ending
387 							if (this.endlevelIntroAnimation(false))
388 								if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) this.setState(801);
389 							break;
390 						}
391 						case 501: { // Fade out after dead
392 							if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) 
393 								if (this.gameIsOver())
394 									this.setState(700); // GAME OVER
395 								else
396 									this.setState(600);
397 							break;
398 						}
399 						case 401:{ // Level intro animation
400 							if (this.levelIntroAnimation(false)) this.setState(402);
401 							break;
402 						}
403 						case 500: { // Wait after dead
404 							this._loselife.counter++;
405 							if (this._loselife.counter==this._loselife.wait) this.setState(501);
406 							break;
407 						}
408 						case 600:{ // New life intro
409 							if (this.newlifeIntroAnimation(false)) this.setState(601);
410 							break;
411 						}
412 						case 700:{ // gameover
413 							if (this.gameoverIntroAnimation(false)) this.setState(100); // Restart game
414 							break;
415 						}
416 						case 801:{ // Game ending
417 							if (this.gameEndingIntroAnimation(false)) {
418 								this._loselife={ending:true};
419 								this.setState(700); // Game over
420 							}
421 							break;
422 						}
423 					}
424 					this.hud.blit();
425 					break;
426 				}
427 			}
428 		}
429 	});
430 	}
431 }
432