Moving stuff around, nothing to see here

git-svn-id: https://aklabs.dyndns.org/svn/aklabs/trunk/games/wilysays@50 eb184899-6090-47d4-a65b-558f62f6ea1c
This commit is contained in:
andrew
2010-07-29 01:33:30 +00:00
commit c4ae376c8b
136 changed files with 6379 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
webapp/
this directory contains the PHP files that run the leaderboard.
Really simple stuff. Also contains the help files and such.
src/
Contains the actual source files that the game was made from.
*SHOULD* load right up and run in Flash CS3.

View File

@@ -0,0 +1,909 @@
/*
* MEGA MAN : "Wily Says"
* Demo for Zynga Games
* (C) Andrew Kesterson 2010 andrew@aklabs.net
*
*/
// - TODO : Implement proper layering! Quit this *!@# of adding/removing children in the right order.
package {
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.text.AntiAliasType;
import flash.filters.GlowFilter;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.utils.Dictionary;
import flash.media.SoundChannel;
import flash.net.*;
import net.aklabs.demo.simonsays.Preloader;
import net.aklabs.demo.simonsays.Pattern;
import net.aklabs.demo.simonsays.Mastermind;
import net.aklabs.demo.simonsays.LoadingObject;
import net.aklabs.demo.simonsays.Player;
import net.aklabs.demo.simonsays.Powerup;
import net.aklabs.demo.simonsays.PowerupEvent;
import net.aklabs.demo.simonsays.MastermindEvent;
/* Class : Game
*
* Main application class. Handles player input, logic, etc.
*/
public class Game extends MovieClip {
protected var preloader:Preloader; // preloader content manager
protected var gameTimer:Timer; // timer for the game logic
protected var bgMusicChannel:SoundChannel; // channel on which background music is playing - TODO: Allow bgmusic/sfx turned ON/OFF
protected var curLevel:Number; // the level of the current number, from 1-10
protected var player:Player; // Object representing the player
protected var curPattern:Pattern; // The currently active "Pattern" object being played out
protected var simon:Mastermind; // The "Simon Says" ("Mastermind")
protected var cutscenes:Dictionary; // A dictionary of instantiated and prepared SWF-cloned cutscenes
protected var difficulty:Number; // An integer from 0-n setting the difficulty of the game
public static var STATE_PLAYING:Number = 0; // STATE : Game is currently PLAYING (e.g., not in menu/cinematic/highscore/credits/etc)
public static var STATE_MENU:Number = 1; // STATE: Game is currently sitting at the main menu waiting for player to start the game
public static var STATE_HELP:Number = 2; // STATE : Game is currently on the HELP screen (currently unused) - TODO : Add "Help" screen beyond tutorial
public static var STATE_PASSWORD:Number = 3; /* STATE : Game is currently on the password input screen to resume a game (currently unused)
TODO : Get rid of this, password system was never implemented and doesn't make sense for this game */
public static var STATE_GAMEOVER:Number = 4; // STATE : Player has lost the game and is dead
public static var STATE_PLAYING_PLAYBACK:Number = 5; /* STATE : Substate of STATE_PLAYING. Used while the Mastermind is playing back the currently
exposed portions of the currently playing pattern */
public static var STATE_PLAYING_INPUT:Number = 6; // STATE : Substate of STATE_PLAYING. Used while the Mastermind is accepting input from the player.
public static var STATE_PLAYING_FLASHING:Number = 7; // STATE : Substate of STATE_PLAYING. Used while the Mastermind is flashing all its lights for a second.
public static var STATE_PLAYING_EXPLODING:Number = 8; // STATE : Substate of STATE_PLAYING. Used after the player loses, and while the screen is exploding.
public static var STATE_PLAYING_WAITING:Number = 9; /* STATE : Substate of STATE_PLAYING. When the explosion timer has fired, this substate is used while
waiting for the explosions to finish their animation before going to STATE_HIGHSCORE. */
public static var STATE_PLAYING_WINLEVEL:Number = 10; /* STATE : Substate of STATE_PLAYING. Used when the player has completed all iterations of the
current pattern. Implies that the level number is scrolling past, etc.*/
public static var STATE_WINGAME:Number = 11; // STATE : Used when the player has completed all patterns and has won the game.
public static var STATE_TUTORIAL = 12; // STATE : Game is currently running the tutorial/intro
public static var STATE_HIGHSCORE = 13; // STATE : Game is currently awaiting input on the high score screen
protected var primaryState:Number; // Stores the game's current primary state value
protected var secondaryState:Number; // Stores any applicable substate for the game, if any
protected var buttonSounds:Dictionary; // Stores references to the loaded sounds in the preloader for each of the Mastermind buttons
protected var timerLabel:TextField; // Text label for the timer display (upper right)
protected var scoreLabel:TextField; // Text label for the score display (upper left)
protected var levelLabel:TextField; // Text label for the "LEVEL" that scrolls across the screen after beating a pattern
protected var levelNumberLabel:TextField; // Text label for the level number (e.g., the "12" in "LEVEL 12") that scrolls after beating a pattern
protected var explosionTimer:Timer; // Timer that runs long enough to generate a bunch of sparse explosions when the player loses.
protected var explosions:Array; /* An array containing to references to all the currently running explosions on the screen
(used so that they can all be safely cleaned up & removed from the screen after Game Over and before moving to the High Score screen) */
protected var maxLevel:Number; // maximum level number achievable before winning the game
protected var levelClearTime:Number; // The time in which a given pattern/level was cleared; currently unused. TODO - Implement this and put it in the high scores
protected var labelPauseTimer:Timer; // the timer that lets the "Level X" label pause in the center of the screen briefly
public static var KEY_NUM1:Number = 97;
public static var KEY_NUM3:Number = 99;
public static var KEY_NUM7:Number = 103;
public static var KEY_NUM9:Number = 105;
public static var KEY_COMMA:Number = 188;
public static var KEY_BACKSLASH:Number = 191;
public static var KEY_K:Number = 75;
public static var KEY_APOSTROPHE = 222;
public static var KEY_0:Number = 48;
public static var KEY_1:Number = 49;
public static var KEY_2:Number = 50;
public static var KEY_3:Number = 51;
public static var KEY_4:Number = 52;
public static var KEY_5:Number = 53;
public static var KEY_6:Number = 54;
public static var KEY_7:Number = 55;
public static var KEY_8:Number = 56;
public static var KEY_9:Number = 57;
public static var KEY_SPACE:Number = 32;
/*
* Game()
*
* Default constructor for Game class
*
* arguments: none
*
* returns : Game
*/
public function Game()
{
// -- setup the preloader and start it downloading
var assets = new Array( new Array("sounds", "music_background", "sfx/BACKGROUND.mp3"),
new Array("sounds", "sfx_explosion", "sfx/EXPLOSION.mp3"),
new Array("sounds", "sfx_btn_blue", "sfx/BLUE.mp3"),
new Array("sounds", "sfx_btn_green", "sfx/GREEN.mp3"),
new Array("sounds", "sfx_btn_red", "sfx/RED.mp3"),
new Array("sounds", "sfx_btn_yellow", "sfx/YELLOW.mp3"),
new Array("sounds", "sfx_slowdown", "sfx/SLOWDOWN.mp3"),
new Array("sounds", "sfx_shortcircuit", "sfx/SHORTCIRCUIT.mp3"),
new Array("sounds", "sfx_pointdoubler", "sfx/POINTDOUBLER.mp3"),
new Array("sounds", "sfx_exclamation", "sfx/EXCLAMATION.mp3"),
new Array("sounds", "sfx_forgiveness", "sfx/FORGIVENESS.mp3"),
new Array("images", "gfx_btn_darkblue", "gfx/blue-dark.png"),
new Array("images", "gfx_btn_lightblue", "gfx/blue-light.png"),
new Array("images", "gfx_btn_darkgreen", "gfx/green-dark.png"),
new Array("images", "gfx_btn_lightgreen", "gfx/green-light.png"),
new Array("images", "gfx_btn_darkred", "gfx/red-dark.png"),
new Array("images", "gfx_btn_lightred", "gfx/red-light.png"),
new Array("images", "gfx_btn_darkyellow", "gfx/yellow-dark.png"),
new Array("images", "gfx_btn_lightyellow", "gfx/yellow-light.png"),
new Array("images", "gfx_mastermind", "gfx/whole.png"),
new Array("images", "gfx_background", "gfx/game_background.png"),
new Array("images", "gfx_circuitboard", "gfx/circuitboard.png"),
new Array("images", "gfx_pwup_exclamation", "gfx/EXCLAMATION.png"),
new Array("images", "gfx_pwup_forgiveness", "gfx/FORGIVENESS.png"),
new Array("images", "gfx_pwup_pointdoubler", "gfx/POINTDOUBLER.png"),
new Array("images", "gfx_pwup_shortcircuit", "gfx/SHORTCIRCUIT.png"),
new Array("images", "gfx_pwup_slowdown", "gfx/SLOWDOWN.png"),
new Array("images", "gfx_progress_red", "gfx/progress_red.png"),
new Array("images", "gfx_progress_green", "gfx/progress_green.png"),
new Array("images", "gfx_pwup_freelife", "gfx/LIFE.png"),
new Array("movies", "movie_endscreen", "gfx/cutscenes/endscreen.swf", ""),
new Array("movies", "movie_intro_menu", "gfx/cutscenes/intro-menu.swf", ""),
new Array("movies", "movie_tutorial", "gfx/cutscenes/tutorial.swf", ""),
new Array("movies", "movie_highscore", "gfx/cutscenes/highscore.swf", ""),
new Array("movies", "movie_difficultychooser", "gfx/cutscenes/difficultychooser.swf", ""),
new Array("movies", "movie_explosion", "gfx/explosion.swf", "SmallExplosion") );
this.preloader = new Preloader(assets);
this.preloader.x = 200;
this.preloader.y = 140;
this.addChild(this.preloader);
this.preloader.addEventListener(Event.COMPLETE, this.onPreloaderComplete);
this.preloader.loadAssets();
this.buttonSounds = new Dictionary();
this.buttonSounds[0] = "sfx_btn_blue";
this.buttonSounds[1] = "sfx_btn_green";
this.buttonSounds[2] = "sfx_btn_red";
this.buttonSounds[3] = "sfx_btn_yellow";
// -- set up all the timers
this.gameTimer = new Timer(25);
this.gameTimer.start();
this.explosionTimer = new Timer(5000);
stage.addEventListener(KeyboardEvent.KEY_UP, this.onKeyUp);
this.labelPauseTimer = new Timer(2000);
// -- miscellanious stuff
this.player = new Player();
this.cutscenes = new Dictionary();
this.explosions = new Array();
this.curLevel = 1;
this.curPattern = null;
this.difficulty = 3;
}
/*
* onNonLoopEnterFrame(evt)
*
* This function serves as a trigger on sprites which should not loop their animations. There may be
* a simpler way to do this, but being pressed for time I knew this would stop it.
*
* arguments:
* @evt : Event , event that triggered this function
*
* Returns: none
*/
public function onNonLoopEnterFrame(evt:Event)
{
if ( evt.target.currentFrame == evt.target.totalFrames ) {
evt.target.stop();
}
}
/*
* onKeyUp(evt)
*
* This function grabs the player's keyboard input and passes it off to the Player, Pattern objects, etc
*
* arguments:
* @evt: Event, event that triggered this function
*
* Returns : none
*/
public function onKeyUp(evt:KeyboardEvent)
{
var pwup:Powerup = null;
if ( this.primaryState == Game.STATE_PLAYING_INPUT ) {
var colorPressed:Number = -1;
if ( (( evt.keyCode == Game.KEY_NUM1) || (evt.keyCode == Game.KEY_COMMA)) ) {
colorPressed = Pattern.COLOR_YELLOW;
} else if ( (( evt.keyCode == Game.KEY_NUM3) || (evt.keyCode == Game.KEY_BACKSLASH)) ) {
colorPressed = Pattern.COLOR_BLUE;
} else if ( (( evt.keyCode == Game.KEY_NUM7) || (evt.keyCode == Game.KEY_K)) ) {
colorPressed = Pattern.COLOR_GREEN;
} else if ( (( evt.keyCode == Game.KEY_NUM9) || (evt.keyCode == Game.KEY_APOSTROPHE)) ) {
colorPressed = Pattern.COLOR_RED;
} else if ( ( evt.keyCode >= Game.KEY_0 && evt.keyCode <= Game.KEY_9) ) {
if ( evt.keyCode == Game.KEY_0 )
evt.keyCode = Game.KEY_0 + 10; // trust me it makes sense (Key 0 is the player's last inventory slot to the right
// but it comes first in the keyCode sequence before 1, which is the far left, so we add 10 to it
// because we're passing an index from 0 - 9 for the player's inventory)
this.player.usePowerupAt(evt.keyCode - 49);
}
if ( colorPressed != -1 )
this.checkColorHit(colorPressed);
} else if ( this.primaryState == Game.STATE_MENU ) {
if ( evt.keyCode == Game.KEY_SPACE ) {
this.addChild(cutscenes["difficultychooser"]);
}
} else if ( this.primaryState == Game.STATE_TUTORIAL ) {
if ( evt.keyCode == Game.KEY_SPACE ) {
this.newGame();
}
} else if ( this.primaryState == Game.STATE_WINGAME ) {
if ( evt.keyCode == Game.KEY_SPACE ) {
this.primaryState = Game.STATE_HIGHSCORE;
this.secondaryState = Game.STATE_HIGHSCORE;
this.removeChild(this.cutscenes["endscreen"]);
this.addChild(this.cutscenes["highscores"]);
this.cutscenes["highscores"].play();
}
}
}
/*
* onPreloaderComplete(evt)
*
* This function is fired whenever the Preloader fires an event signifying that all items
* in the asset list have been successfully loaded.
*
* arguments:
* @evt : Event, the event firing this function
*
* Returns: none
*/
public function onPreloaderComplete(evt:Event)
{
if ( evt.target == this.preloader ){
this.removeChild(this.preloader);
// -- setup the cutscenes so they're ready to use
this.cutscenes["intro_menu"] = this.preloader.getObject("movie_intro_menu");
this.cutscenes["intro_menu"].x = 0;
this.cutscenes["intro_menu"].y = 0;
this.cutscenes["intro_menu"].addEventListener(Event.ENTER_FRAME, this.onNonLoopEnterFrame);
this.cutscenes["tutorial"] = this.preloader.getObject("movie_tutorial");
this.cutscenes["tutorial"].x = 0;
this.cutscenes["tutorial"].y = 0;
this.cutscenes["tutorial"].addEventListener(Event.ENTER_FRAME, this.onNonLoopEnterFrame);
this.cutscenes["highscores"] = this.preloader.getObject("movie_highscore");
this.cutscenes["highscores"].x = 0;
this.cutscenes["highscores"].y = 0;
this.cutscenes["highscores"].addEventListener(Event.ENTER_FRAME, this.onNonLoopEnterFrame);
this.cutscenes["highscores"].highScorePostBtn.addEventListener(MouseEvent.CLICK, this.onHighScoreEntry);
this.cutscenes["highscores"].highScoreCancelBtn.addEventListener(MouseEvent.CLICK, this.onHighScoreEntry);
this.cutscenes["highscores"].viewScoreBtn.addEventListener(MouseEvent.CLICK, this.onHighScoreEntry);
this.cutscenes["difficultychooser"] = this.preloader.getObject("movie_difficultychooser");
this.cutscenes["difficultychooser"].x = 300;
this.cutscenes["difficultychooser"].y = 200;
this.cutscenes["difficultychooser"].easyBtn.addEventListener(MouseEvent.CLICK, this.onDifficultySelected);
this.cutscenes["difficultychooser"].normalBtn.addEventListener(MouseEvent.CLICK, this.onDifficultySelected);
this.cutscenes["difficultychooser"].hardBtn.addEventListener(MouseEvent.CLICK, this.onDifficultySelected);
this.cutscenes["difficultychooser"].wilyBtn.addEventListener(MouseEvent.CLICK, this.onDifficultySelected);
this.cutscenes["endscreen"] = this.preloader.getObject("movie_endscreen");
this.cutscenes["endscreen"].x = 0;
this.cutscenes["endscreen"].y = 0;
this.addChild(this.cutscenes["intro_menu"]);
this.gameTimer.removeEventListener(TimerEvent.TIMER, this.onPreloaderComplete);
this.gameTimer.addEventListener(TimerEvent.TIMER, this.onGameTimer);
this.simon = new Mastermind();
this.simon.x = (640-(this.simon.width))/2;
this.simon.y = 20;
this.simon.addEventListener(MastermindEvent.BTN_CLICKED, this.onMastermindClicked);
this.timerLabel = new TextField();
this.timerLabel.background = false;
this.timerLabel.autoSize = TextFieldAutoSize.LEFT;
var timerLabelFormat = new TextFormat();
timerLabelFormat.font = "Courier New";
timerLabelFormat.bold = false;
timerLabelFormat.color = 0xF12B2B;
timerLabelFormat.size = 36;
this.timerLabel.defaultTextFormat = timerLabelFormat;
this.timerLabel.text = "00000";
this.timerLabel.x = 504;
this.timerLabel.y = 34;
this.scoreLabel = new TextField();
this.scoreLabel.background = false;
this.scoreLabel.autoSize = TextFieldAutoSize.LEFT;
this.scoreLabel.defaultTextFormat = timerLabelFormat;
this.scoreLabel.text = "000000";
this.scoreLabel.x = 12;
this.scoreLabel.y = 34;
this.levelLabel = new TextField();
this.levelLabel.background = false;
this.levelLabel.autoSize = TextFieldAutoSize.LEFT;
this.levelNumberLabel = new TextField();
this.levelNumberLabel.background = false;
this.levelNumberLabel.autoSize = TextFieldAutoSize.LEFT;
var levelLabelFormat = new TextFormat();
levelLabelFormat.font = "Helvetica";
levelLabelFormat.bold = true;
levelLabelFormat.color = 0xF12B2B;
levelLabelFormat.size = 72;
this.levelLabel.defaultTextFormat = levelLabelFormat;
this.levelNumberLabel.defaultTextFormat = levelLabelFormat;
this.levelLabel.antiAliasType = AntiAliasType.ADVANCED;
this.levelNumberLabel.antiAliasType = AntiAliasType.ADVANCED;
this.levelLabel.filters = [new GlowFilter(0x000000, 1.0, 4, 4, 300)];
this.levelNumberLabel.filters = [new GlowFilter(0x000000, 1.0, 4, 4, 300)];
this.levelLabel.x = 150;
this.levelLabel.y = 500;
this.levelNumberLabel.x = 400;
this.levelNumberLabel.y = -150;
this.levelLabel.text = "LEVEL";
this.player.addEventListener(PowerupEvent.USED_POWERUP, this.onUsedPowerup);
this.playBackgroundMusic();
this.primaryState = Game.STATE_MENU;
this.secondaryState = Game.STATE_MENU;
return;
}
}
/*
* onBackgroundMusicFinished(evt)
*
* This function just makes sure that the background music loops forever
*
* arguments:
* @evt: Event, event firing this function
*
* Returns: none
*/
public function onBackgroundMusicFinished(evt:Event)
{
this.playBackgroundMusic();
}
/*
* playBackgroundMusic()
*
* This function starts the background music playing
*
* arguments: none
*
* Returns : none
*/
public function playBackgroundMusic()
{
if ( this.bgMusicChannel )
this.bgMusicChannel.stop();
var bgmusic = this.preloader.getObject("music_background");
if ( !bgmusic ) {
return;
}
this.bgMusicChannel = bgmusic.play();
this.bgMusicChannel.addEventListener(Event.SOUND_COMPLETE, this.onBackgroundMusicFinished);
}
/*
* onGetPowerup(evt)
*
* This function is fired whenever the Pattern is signifying that the player has gotten a powerup from the pattern
*
* arguments:
* @evt : Event, event firing this function
*
* Returns: none
*/
public function onGetPowerup(evt:PowerupEvent)
{
if ( evt.pwup != null ) {
var pwup = evt.pwup;
pwup.addChild(this.preloader.getBitmap(pwup.imgHandle));
this.player.addPowerup(pwup);
}
}
/*
* onGameTimer(evt)
*
* Fires once every 25 ms to run the core game logic
*
* arguments:
* @evt : Event, the event firing this function
*
* Returns : none
*/
public function onGameTimer(evt:TimerEvent)
{
var i:Number = 0;
/* This state machine got just a little bit too complex, and I think alot of it could be probably get
done away with in favor of more events driving the show. However for right now, it works. The IF chains
check the primary state first, then go in and check secondary states and ancillary conditions. */
if ( (this.primaryState == Game.STATE_PLAYING) && (this.curPattern.state == Pattern.STATE_STOPPED) ) {
if ( this.secondaryState == Game.STATE_PLAYING_FLASHING && (!this.simon.isLit) ) {
// we've flashed the Mastermind once, now let's play back the currently exposed portions of the pattern
this.curPattern.play(true);
this.primaryState = Game.STATE_PLAYING_PLAYBACK;
this.secondaryState = Game.STATE_PLAYING_PLAYBACK;
} else if ( this.secondaryState == Game.STATE_PLAYING_EXPLODING ) {
// the player has died and we're still in the explosion timeframe, so blow some *!$% up
if ( Math.random() < 0.25 ) {
var explosion = this.preloader.getMovieClip("movie_explosion");
explosion.addEventListener(Event.ENTER_FRAME, this.onNonLoopEnterFrame);
explosion.x = Math.random()*640;
explosion.y = Math.random()*480;
explosion.play();
this.preloader.playSound("sfx_explosion");
this.addChild(explosion);
this.explosions.push(explosion);
}
} else if ( this.secondaryState == Game.STATE_PLAYING_WINLEVEL ) {
// player just beat the pattern; scroll "LEVEL" down from the top, and the level number up from the bottom
this.levelNumberLabel.text = "" + this.curLevel;
if ( this.levelLabel.y == 175 && (!this.labelPauseTimer.running)) {
this.labelPauseTimer.addEventListener(TimerEvent.TIMER, this.onLabelPauseTimer);
this.labelPauseTimer.reset();
this.labelPauseTimer.start();
} else if ( this.labelPauseTimer.running ) {
// do nothing if the label pause timer is running
} else if ( this.levelLabel.y <= -120 ) {
this.secondaryState = Game.STATE_PLAYING;
this.levelLabel.y = 500;
this.levelNumberLabel.y = -150;
} else {
this.levelLabel.y -= 5;
this.levelNumberLabel.y += 5;
}
} else if ( this.secondaryState == Game.STATE_PLAYING ){
// flash the Mastermind once before playing back the portions currently exposed, so we have the player's
// attention
this.simon.flashAll(500);
this.secondaryState = Game.STATE_PLAYING_FLASHING;
}
} else if ( (this.primaryState == Game.STATE_PLAYING_PLAYBACK) ) {
if ( (this.secondaryState == Game.STATE_PLAYING_FLASHING ) && (!this.simon.isLit) ) {
// okay we're done flashing around, let the player give input and start the timers
this.curPattern.play(false);
this.primaryState = Game.STATE_PLAYING_INPUT;
this.secondaryState = Game.STATE_PLAYING;
} else if ( this.secondaryState == Game.STATE_PLAYING_PLAYBACK && this.curPattern.state == Pattern.STATE_STOPPED ) {
// flash the Mastermind a 2nd time to let the player know we're done running the pattern, and they need to start hitting buttons
this.simon.flashAll(500);
this.secondaryState = Game.STATE_PLAYING_FLASHING;
}
} else if ( (this.primaryState == Game.STATE_PLAYING_INPUT) && (this.curPattern.state != Pattern.STATE_RUNNING ) ) {
if ( this.curPattern.state == Pattern.STATE_CORRECT ) {
// player has repeated the pattern correctly
this.player.score += this.curPattern.score;
this.curPattern.complexify();
if ( this.curPattern.patternLength() > this.player.maxPattern )
this.player.maxPattern = this.curPattern.patternLength();
// check the state again after complexifying it. If the player has reached the end of the pattern, we won't know
// until we've ran .complexify() on it.
if ( this.curPattern.state == Pattern.STATE_COMPLETE ) {
this.nextLevel();
if ( this.curLevel >= this.maxLevel ) {
this.wonGame();
return;
}
return;
}
} else if ( this.curPattern.state == Pattern.STATE_FAILED ){
// Player irrevocably missed the pattern; deduct a life and either start a new pattern, or game over.
this.player.die();
if ( this.player.lives <= 0 ) {
this.curPattern.stop()
this.primaryState = Game.STATE_PLAYING;
this.secondaryState = Game.STATE_PLAYING_EXPLODING;
this.explosionTimer.addEventListener(TimerEvent.TIMER, this.onExplosionTimer);
this.explosionTimer.start();
this.curPattern.forceState(Pattern.STATE_STOPPED);
return;
} else {
this.newPattern();
}
}
// if we haven't returned out from a previous condition, it's safe to reset the primary/secondary state
// to STATE_PLAYING so we'll flash and run the pattern normally
this.primaryState = Game.STATE_PLAYING;
this.secondaryState = Game.STATE_PLAYING;
this.timerLabel.text = "00000";
} else if ( this.primaryState == Game.STATE_PLAYING_INPUT ) {
// Player is running input, just update the timer text
this.timerLabel.text = "" + this.curPattern.clearTime;
}
this.scoreLabel.text = "" + int(player.score);
return;
}
/*
* onLabelPauseTimer(evt)
*
* This function is called when the label pause timer is up, so the Level labels will start moving again
*
* arguments:
* @evt:TimerEvent, the event firing this function
*
* Returns: none
*/
public function onLabelPauseTimer(evt:TimerEvent)
{
this.labelPauseTimer.removeEventListener(TimerEvent.TIMER, this.onLabelPauseTimer);
this.labelPauseTimer.stop();
// this bumps it past the pixel mark so we don't duplicate the onLabelPauseTimer call and it sits there forever
this.levelLabel.y -= 5;
this.levelNumberLabel.y == 5.
}
/*
* onDifficultySelected(evt)
*
* This function is called whenever the player selects a difficulty level from the main screen starting a new game
*
* arguments:
* @evt : Event, the event firing this function
*
* Returns : none
*/
public function onDifficultySelected(evt:MouseEvent)
{
var mapping:Dictionary = new Dictionary;
// -- this just saves me a long block of if () { ... } , and the use of one-line X ? Y : Z ...
mapping[this.cutscenes["difficultychooser"].easyBtn] = 0;
mapping[this.cutscenes["difficultychooser"].normalBtn] = 1;
mapping[this.cutscenes["difficultychooser"].hardBtn] = 2;
mapping[this.cutscenes["difficultychooser"].wilyBtn] = 3;
this.difficulty = mapping[evt.target];
this.removeChild(this.cutscenes["difficultychooser"]);
this.removeChild(this.cutscenes["intro_menu"]);
this.primaryState = Game.STATE_TUTORIAL;
this.secondaryState = Game.STATE_TUTORIAL;
this.addChild(this.cutscenes["tutorial"]);
this.cutscenes["tutorial"].play();
}
/*
* onHighScoreEntry(evt)
*
* This function fires whenever the user clicks any of the buttons on the High Score screen
*
* arguments:
* @evt : Event, the event firing this function
*
* Returns: none
*/
public function onHighScoreEntry(evt:MouseEvent)
{
if ( evt.target == this.cutscenes["highscores"].highScorePostBtn ) {
// post up the user's high score and spin off a new browser window to the high score area
var request:URLRequest = new URLRequest("http://atlanta.aklabs.net/~akesterson/wilysays/index.php");
request.method = URLRequestMethod.POST;
var variables:URLVariables = new URLVariables();
variables.op = "store";
variables.name = this.cutscenes["highscores"].highScoreName.text;
variables.score = this.player.score;
variables.maxpattern = this.player.maxPattern;
request.data = variables;
sendToURL(request);
var request:URLRequest = new URLRequest("http://atlanta.aklabs.net/~akesterson/wilysays/index.php");
navigateToURL(request, "_blank");
} else if ( evt.target == this.cutscenes["highscores"].viewScoreBtn) {
// just send the user to the high scores and return, don't disable any of the buttons or change state
var request:URLRequest = new URLRequest("http://atlanta.aklabs.net/~akesterson/wilysays/index.php");
navigateToURL(request, "_blank");
return;
}
// go back to the main menu
this.removeChild(this.cutscenes["highscores"]);
this.addChild(this.cutscenes["intro_menu"]);
this.primaryState = Game.STATE_MENU;
this.primaryState = Game.STATE_MENU;
this.cutscenes["intro_menu"].gotoAndPlay(0);
}
/*
* clearExplosions()
*
* This function is ran when the explosion timer is done, and right before the high score screen
* is fixing to come up, to make sure that all the explosions are gone from the screen.
*
* arguments: none
*
* Returns: none
*/
public function clearExplosions()
{
var i:Number;
for ( i = 0; i < this.explosions.length ; i++ ) {
this.removeChild(this.explosions[i]);
this.explosions[i].stop();
this.explosions.splice(i, 1);
}
}
/*
* clearGameScreen()
*
* This function clears the game screen of all play elements (inventory, lives, Mastermind, etc)
*
* arguments : none
*
* returns: none
*/
public function clearGameScreen()
{
this.removeChild(this.preloader.getObject("gfx_circuitboard"));
this.removeChild(this.preloader.getObject("gfx_background"));
this.removeChild(this.simon);
this.removeChild(this.timerLabel);
this.removeChild(this.scoreLabel);
this.removeChild(this.levelLabel);
this.removeChild(this.levelNumberLabel);
if ( this.curPattern )
this.removeChild(this.curPattern);
this.removeChild(this.player);
this.removeChild(this.player.lifeDisplay);
this.player.clearInventory();
this.explosionTimer.reset();
this.explosionTimer.delay = 5000;
this.explosionTimer.stop();
}
/*
* wonGame()
*
* This function is called when the player has beaten all 10 levels and therefore won the game
*
* arguments: None
*
* Returns: None
*
*/
public function wonGame()
{
this.clearGameScreen();
this.primaryState = Game.STATE_WINGAME;
this.secondaryState = Game.STATE_WINGAME;
this.addChild(this.cutscenes["endscreen"]);
this.cutscenes["endscreen"].play();
}
/* gameOver()
*
* This function is called whenever the player has lost all of their lives, and achieved Game Over
*
* arguments : None
*
* Returns : none
*/
public function gameOver()
{
this.clearGameScreen();
this.primaryState = Game.STATE_HIGHSCORE;
this.secondaryState = Game.STATE_HIGHSCORE;
this.addChild(this.cutscenes["highscores"]);
this.cutscenes["highscores"].play();
}
/*
* nextLevel()
*
* This function runs to setup the next level above the previous one
*
* arguments : none
*
* Returns : none
*/
public function nextLevel()
{
this.curLevel += 1;
this.levelLabel.y = 500;
this.levelNumberLabel.y = -150;
this.levelNumberLabel.text = "" + this.curLevel;
this.primaryState = Game.STATE_PLAYING;
this.secondaryState = Game.STATE_PLAYING_WINLEVEL;
this.player.score += this.curPattern.score;
this.timerLabel.text = "00000";
this.scoreLabel.text = "" + int(player.score);
this.newPattern();
}
/*
* newGame()
*
* This function sets up a new game when the player starts a game from the main menu
*
* arguments : none
*
* Returns: none
*/
public function newGame()
{
// difficulty just really changes how long the patterns are and how many levels you play
if ( this.difficulty > 1 ) {
this.curLevel = 3*this.difficulty;
} else
this.curLevel = 0;
this.maxLevel = this.curLevel + (6+this.difficulty);
this.player.score = 0;
this.player.lives = 3;
this.cutscenes["tutorial"].stop();
this.cutscenes["highscores"].stop();
this.cutscenes["intro_menu"].stop();
try {
this.removeChild(this.cutscenes["tutorial"]);
} catch (error:Error) {
// do nothing, it wasn't a child for some reason.. (I ran into this a couple times but not sure why)
}
this.addChild(this.preloader.getObject("gfx_circuitboard"));
this.addChild(this.preloader.getObject("gfx_background"));
this.addChild(this.simon);
this.addChild(this.timerLabel);
this.addChild(this.scoreLabel);
this.addChild(player);
this.addChild(player.lifeDisplay);
this.addChild(this.levelLabel);
this.addChild(this.levelNumberLabel);
this.player.x = 0;
this.player.y = 480-64;
player.lifeDisplay.x = 400;
player.lifeDisplay.y = 480-64;
this.player.resetLifePositions();
this.primaryState = Game.STATE_PLAYING;
this.secondaryState = Game.STATE_PLAYING;
this.newPattern();
this.nextLevel();
}
/*
* onExplosionTimer(evt)
*
* This function fires when the explosion timeframe is up
*
* arguments :
* @evt : Event, the event firing this function
*
* Returns : none
*/
public function onExplosionTimer(evt:TimerEvent)
{
this.primaryState = Game.STATE_PLAYING;
this.secondaryState = Game.STATE_PLAYING_WAITING;
for ( var i:Number = 0; i < this.explosions.length; i++ ) {
if ( this.explosions[i].currentFrame != this.explosions[i].totalFrames ) {
// some of the explosions aren't done yet, let them finish
this.explosionTimer.delay = 1000;
this.explosionTimer.start();
return;
}
}
this.clearExplosions();
this.gameOver();
}
/*
* onMastermindClicked(evt)
*
* This function fires whenever the player clicks the mouse on one of the mastermind buttons
*
* arguments:
* @evt : Event, the event firing this function
*
* Returns : none
*/
public function onMastermindClicked(evt:MastermindEvent)
{
this.checkColorHit(evt.colorClicked);
}
/*
* autoForgiveness()
*
* This function checkes to see if the player has a Forgiveness powerup in his inventory,
* and if it does, it uses it to stop the pattern from blowing out one of the players' lives
*
* arguments : none
*
* Returns : none
*/
public function autoForgiveness()
{
var pwup:Powerup = null;
for ( var i:Number = 0; i < this.player.inventory.length ; i++ ) {
pwup = this.player.inventory[i];
if ( pwup.pType == Powerup.PTYPE_FORGIVENESS ) {
this.curPattern.forceState(Pattern.STATE_STOPPED);
this.player.usePowerupAt(i);
break;
}
}
}
/*
* checkColorHit(colorPressed)
*
* arguments:
* @colorPressed : Number, an integer (e.g. Pattern.COLOR_XXXX) specifying which color the player hit
*
* Returns: none
*/
public function checkColorHit(colorPressed:Number)
{
if ( this.curPattern.colorActive(colorPressed) == true ) {
this.simon.lightButton(colorPressed, 100);
this.preloader.playSound(this.buttonSounds[colorPressed]);
} else {
this.autoForgiveness();
this.curPattern.stop();
return;
}
}
/*
* onUsedPowerup()
*
* Fired whenever the player uses a powerup
*
* arguments:
* @evt : Event, the event firing this function
*
* Returns: none
*/
public function onUsedPowerup(evt:PowerupEvent)
{
// the only time we get a powerupevent for used powerups
// is when it's the player dispatching one; we have to
// then re-dispatch it so that the pattern will see it,
// since it's in the opposite direction for bubbling (things bubble up,
// never down). We never actually process them, all powerup handling is
// handled between the player & pattern. We just dispatch.
this.curPattern.onUsedPowerup(evt);
}
/*
* newPattern()
*
* Creates a new pattern object to challenge the player.
*
* arguments: none
*
* Returns: none
*/
public function newPattern()
{
try {
this.removeChild(this.curPattern);
} catch (error:Error) {
// do nothing, it wasn't in our child list yet
}
this.curPattern = new Pattern(this.curLevel, this.simon, this.difficulty);
this.curPattern.addEventListener(PowerupEvent.GOT_POWERUP, this.onGetPowerup);
this.curPattern.stop();
this.curPattern.forceState(Pattern.STATE_STOPPED);
this.curPattern.x = 602;
this.curPattern.y = 138;
this.addChild(this.curPattern);
trace("Finished newPattern()");
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,34 @@
package net.aklabs.demo.simonsays {
/*
* Class LoadingObject
*
* This class is used to represent a content asset while it is going through the process of being loaded
* by the Preloader class.
*/
public class LoadingObject {
public static var STATE_READY:Number = 0; // Object has been loaded and is ready
public static var STATE_LOADING:Number = 1; // Object is currently loading, not ready yet
public static var STATE_NOTFOUND:Number = 2; // Object wasn't found in the cache
public var handle:String; // Text handle for this object
public var state:Number; // State value
public var bytesRead:Number; // the amount of bytes currently read in to this object over the net
public var bytesTotal:Number; // the total byte size of this object
/*
* LoadingObject()
*
* Default constructor
*
* arguments : none
*
* Returns : LoadingObject
*/
public function LoadingObject() {
this.handle = "";
this.state = LoadingObject.STATE_NOTFOUND;
this.bytesRead = 0;
this.bytesTotal = 0;
}
}
}

View File

@@ -0,0 +1,176 @@
package net.aklabs.demo.simonsays
{
import flash.utils.Timer;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.display.Sprite;
import net.aklabs.demo.simonsays.Preloader;
import net.aklabs.demo.simonsays.SimonButton;
import net.aklabs.demo.simonsays.MastermindEvent;
/*
* Class: Mastermind
*
* This class defines our "Simon Says", "Wily Lok", "Mastermind", whatever you want to call it.
* (I called it 3 or 4 different things during the course of development.)
*
*/
public class Mastermind extends Sprite
{
protected var lightOutTimer:Timer; // timer that fires when it's time to turn off the lights
protected var lightButtons:Array; // array of custom SimonButtons that exists in Pattern.COLOR_XXX order
public var isLit:Boolean; // is the device currently lit?
public function Mastermind()
{
var preloader = Preloader.getInstance();
var lightPositions = new Array();
// this array holds pairs of (x,y) coordinates at which to place the dark/light colored
// Simon Says buttons, since they're meant to cover the existing buttons on the original graphic.
// These are hard-coded; in a better implementation, they would come from an XML or would be
// individual frames of an SWF which could be fired individually, etc. But this works.
// array idx 0: Blue, 1: Green, 2: Red, 3: Yellow
lightPositions.push( new Array(183, 187)); // blue
lightPositions.push( new Array(18, 17)); // green
lightPositions.push( new Array(185, 17)); // red
lightPositions.push( new Array(18, 186)); // yellow
// this array holds the button objects for the visible simon says buttons ...
this.lightButtons = new Array();
// just a temporary array for which images to fetch for creating the down/up button images
var fetchArray = new Array( new Array("gfx_btn_darkblue", "gfx_btn_lightblue"),
new Array("gfx_btn_darkgreen", "gfx_btn_lightgreen"),
new Array("gfx_btn_darkred", "gfx_btn_lightred"),
new Array("gfx_btn_darkyellow", "gfx_btn_lightyellow") );
// Simon Says body
var whole = preloader.getObject("gfx_mastermind");
this.addChild(whole);
for ( var i = 0; i < fetchArray.length ; i++ ) {
var btn:SimonButton = new SimonButton(preloader.getObject(fetchArray[i][1]), preloader.getObject(fetchArray[i][0]));
btn.x = lightPositions[i][0];
btn.y = lightPositions[i][1];
this.lightButtons.push(btn);
this.addChild(btn);
btn.addEventListener(MouseEvent.CLICK, this.onMouseClick); // for some reason, MouseEvent.CLICK never actually does anything?
//btn.addEventListener(MouseEvent.MOUSE_UP, this.onMouseClick);
}
this.lightOutTimer = new Timer(0);
}
/*
* flashAll(length)
*
* This function lights all the lights on the Mastermind for the given length of time
*
* arguments:
* @length:Number, the time in milliseconds for which the Mastermind should stay lit
*
* Returns : none
*/
public function flashAll(length:Number)
{
this.lightOutTimer.delay = length;
this.lightOutTimer.addEventListener(TimerEvent.TIMER, this.onTimer);
this.lightOutTimer.reset();
this.lightOutTimer.start();
for (var i = 0 ; i < 4 ; i++) {
// fake mouse event to light it up
this.lightButtons[i].onMouseDown(null);
}
this.isLit = true;
}
/*
* lightButton(btn, activeTime)
*
* This function lights up a given button on the Mastermind. Mostly used by the Pattern when it's replaying itself.
*
* arguments:
* @btn:Number, the Pattern.COLOR_XXX button that should light
* @activeTime:Number, the amount of milliseconds for which the button should stay lit
*
* Returns : none
*/
public function lightButton(btn:Number, activeTime:Number = 0 )
{
if ( btn < 4 ) {
this.lightButtons[btn].onMouseDown(null);
this.isLit = true;
}
if ( activeTime != 0 ) {
this.lightOutTimer.delay = activeTime;
this.lightOutTimer.addEventListener(TimerEvent.TIMER, this.onTimer);
this.lightOutTimer.reset();
this.lightOutTimer.start();
}
}
/*
* blackout()
*
* This function makes sure that all lights on the Mastermind are extinguished
*
* arguments : none
*
* Returns : none
*/
public function blackout()
{
if ( this.lightButtons.length <= 0 ) {
return;
}
for ( var i = 0 ; i < this.lightButtons.length ; i++ ){
this.lightButtons[i].onMouseUp(null);
}
this.isLit = false;
}
/*
* onTimer(evt)
*
* This function fires whenever the lightOutTimer fires, telling the lights to shut off
*
* arguments :
* @evt:Event, the event that's firing this function
*
* Returns : none
*/
public function onTimer(evt:TimerEvent)
{
if ( evt.target != this.lightOutTimer )
return;
this.lightOutTimer.removeEventListener(TimerEvent.TIMER, this.onTimer);
this.lightOutTimer.stop();
this.lightOutTimer.reset();
this.blackout();
}
/*
* onMouseClick()
*
* This function is fired whenever the user clicks one of the Mastermind's buttons
*
* arguments:
* @evt:Event, the event firing this function
*
* Returns : none
*/
public function onMouseClick(evt:MouseEvent)
{
// we don't do any processing here, as the SimonButton has already checked for
// per-pixel accuracy w/ the click on our abnormally shaped buttons. We just propagate
// out a new MastermindEvent for the game to catch.
for ( var i:Number = 0; i < this.lightButtons.length ; i++ ) {
if ( evt.target == this.lightButtons[i] ) {
var newEvt:MastermindEvent = new MastermindEvent(MastermindEvent.BTN_CLICKED);
newEvt.colorClicked = i;
this.dispatchEvent(newEvt);
}
}
}
}
}

View File

@@ -0,0 +1,22 @@
package net.aklabs.demo.simonsays
{
import flash.events.Event;
/*
* Class : MastermindEvent
*
* This class basically just defines a custom event that will let the mastermind send up
* a clicked event w/ a color.
*/
public class MastermindEvent extends Event
{
public static var BTN_CLICKED:String = "MASTERMIND_BUTTON_CLICKED";
public var colorClicked:Number;
public function MastermindEvent(evtType:String)
{
super(evtType);
}
}
}

View File

@@ -0,0 +1,393 @@
package net.aklabs.demo.simonsays
{
import flash.utils.Timer;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.events.EventDispatcher;
import flash.display.Sprite;
import flash.display.Bitmap;
import net.aklabs.demo.simonsays.Mastermind;
import net.aklabs.demo.simonsays.Powerup;
import net.aklabs.demo.simonsays.PowerupEvent;
import net.aklabs.demo.simonsays.Preloader;
/*
* Class Pattern
*
* This class defines a "pattern", which is where most of the game challenge exists.
* It just defines the pattern currently being traced out on the Simon Says/Mastermind/etc
*
* In addition to doing processing, this class also does some graphical representation,
* in the way of a series of red/green lights to show how far along the player is inside the
* pattern. The image is 16 pixels wide, and (16*maxSize) pixels tall.
*
*/
public class Pattern extends Sprite
{
public static var COLOR_BLUE:Number = 0;
public static var COLOR_GREEN:Number = 1;
public static var COLOR_RED:Number = 2;
public static var COLOR_YELLOW:Number = 3;
protected var patternTimer:Timer; // timer that fires to check pattern logic independently of game timer
protected var curIndex:Number; // amount of the pattern currently finished
protected var pattern:Array; // the array of colors that make up the actual pattern
protected var simon:Mastermind; // A link back up to the parent Mastermind (put here because I didn't want to assume that this.parent would always be correct)
protected var delay:Number; // The number of milliseconds that should pass before the logic timer fires
protected var playCount:Number; // The number of times this pattern has been played through (via Forgiveness). Not currently used for anything.
public var clearTime:Number; // the amount of time the player has (in milliseconds) to finish the pattern
public var state:Number; // state of the pattern at current
public static var STATE_RUNNING = 0; // STATE : pattern is currently "running" - e.g., waiting for input from the player and checking logic
public static var STATE_DEMO = 1; // STATE : pattern is currently "demoing", e.g., flashing the lights up to this.curIndex of the pattern
public static var STATE_FAILED = 2; // STATE : pattern is stopped and the player screwed up
public static var STATE_CORRECT = 3; // STATE : pattern is stopped and the player got the last iteration correct
public static var STATE_STOPPED = 4; // STATE : pattern is just stopped w/ no further info
public static var STATE_COMPLETE = 5; // STATE : pattern is stopped because the player has finished all iterations of this pattern
public var score:Number; // Score currently built up in this pattern
protected var maxSize:Number; // Maximum length of the pattern
public var patternPowerups:Array; // array of powerups assigned to any given button on this pattern
protected var scoreMultiplier:Number; // Set by powerup, the multiplier for current score (default x1)
protected var clearDecrement:Number; // Set by powerup, defines how quickly the pattern's timer runs
protected var progressLights:Array; // An array of bitmaps equal in length to the pattern; all the lights up to this.curIndex will be green, the rest are red
protected var level:Number; // The level of pattern which this is (mainly used for calculating pattern length, could probly be scrapped)
protected var difficulty:Number; // The difficulty of the pattern (used in calculating timer speed)
/*
* Pattern()
*
* Default constructor
*
* arguments:
* @levelNumber:Number, the level number for which this pattern is being made
* @simon:Mastermind, the Mastermind object to which this pattern is to be applied (default null)
* @difficulty:Number, the difficulty level for this pattern (default 1)
*
* Returns: Pattern
*/
public function Pattern(levelNumber:Number, simon:Mastermind = null, difficulty:Number = 1)
{
this.state = 0;
this.simon = simon;
this.level = levelNumber;
this.difficulty = difficulty;
this.curIndex = -1;
this.maxSize = 2+levelNumber; // smallest pattern will never be less than 3 lights total
this.pattern = new Array();
this.patternPowerups = new Array();
this.progressLights = new Array();
this.patternTimer = null;
this.delay = 1000;
this.playCount = 0;
this.clearTime = 0;
this.score = 0;
this.scoreMultiplier = 1;
this.clearDecrement = 0;
this.patternTimer = new Timer(0);
this.addEventListener(PowerupEvent.USED_POWERUP, this.onUsedPowerup);
var preloader:Preloader = Preloader.getInstance();
var newLight:Bitmap;
// populate all the red lights for this pattern that will turn green as the player goes on
for ( var i:Number = 0; i < this.maxSize ; i++ ) {
newLight = preloader.getBitmap("gfx_progress_red");
newLight.x = 0;
newLight.y = i*16;
if ( i > 15 ) {
newLight.x += 20;
newLight.y = (i-15)*16;
}
this.progressLights.push(newLight);
this.addChild(newLight);
}
this.complexify();
}
/*
* patternLength()
*
* Just a getter for the length of the pattern
*
* arguments : none
*
* Returns : Number
*/
public function patternLength():Number
{
return this.pattern.length;
}
/*
* forceState()
*
* Forces a given state onto the pattern
*
* arguments: none
*
* Returns : none
*/
public function forceState(state:Number)
{
this.state = state;
}
/*
* complexify()
*
* This function adds another element to the pattern, so that it becomes a longer pattern, up until the maximum length of the pattern
*
* arguments: none
*
* Returns : none
*/
public function complexify()
{
// we're complete if we're beyond the maximum size
if ( this.pattern.length >= this.maxSize ) {
this.stop();
this.state = Pattern.STATE_COMPLETE;
return null;
}
// reset the score multiplier and such 'cause complexify only gets called at the end of a round
this.scoreMultiplier = 1;
this.state = Pattern.STATE_STOPPED;
this.stop(); // -- wtf why did I call stop on myself? ...
var newcolor = (Math.round(int(Math.random()*4)));
this.pattern.push(newcolor);
// create a new powerup ~20% of the time that complexify is ran
if ( Math.random() < 0.20 ) {
var powerup = new Powerup();
powerup.pType = (Math.round(int(Math.random()*Powerup.PTYPE_MAXVALUE)));
powerup.imgHandle = Powerup.POWERUP_IMAGES[powerup.pType];
powerup.sndHandle = Powerup.POWERUP_SOUNDS[powerup.pType];
this.patternPowerups.push(powerup);
} else {
this.patternPowerups.push(null);
}
this.clearTime = 2000 * ( this.pattern.length );
}
/*
* play(lightSimon)
*
* This function tells the pattern to start playback in one of two modes; demo, or running. Demo mode
* just has the pattern playing itself back via the lights on the Mastermind. The running mode doesn't
* do any playback, it just checks logic.
*
* arguments:
* @lightSimon:Boolean, set this to True to run in Demo mode (default false)
*
* Returns : none
*/
public function play(lightSimon:Boolean = false)
{
if ( this.patternTimer ) {
this.patternTimer.reset()
} else {
this.patternTimer = new Timer( this.delay );
}
if ( lightSimon ){
this.state = Pattern.STATE_DEMO;
this.patternTimer.delay = 1000;
this.patternTimer.addEventListener(TimerEvent.TIMER, this.onDemoTimer);
} else {
this.state = Pattern.STATE_RUNNING;
this.patternTimer.delay = 25;
this.clearDecrement = this.patternTimer.delay + (this.level*(this.difficulty));
this.patternTimer.addEventListener(TimerEvent.TIMER, this.onRunningTimer);
}
this.patternTimer.start();
this.playCount += 1;
this.curIndex = 0;
}
/*
* stop()
*
* Stop all logic/running status on the pattern
*
* arguments: none
*
* Returns : none
*/
public function stop()
{
if ( this.patternTimer ) {
this.patternTimer.removeEventListener(TimerEvent.TIMER, this.onDemoTimer);
this.patternTimer.removeEventListener(TimerEvent.TIMER, this.onRunningTimer);
}
this.curIndex = -1;
}
/*
* getIndex()
*
* Gets the current value is curIndex
*
* arguments: none
*
* Returns : none
*/
public function getIndex()
{
return this.curIndex;
}
/*
* getActive()
*
* OBSOLETE - gets the currecntly active color. This isn't as useful since the input checking method changed around v0.12.
*
* arguments: none
* Returns : Number, -1 on failure, >= 0 on success
*/
public function getActive()
{
if ( (this.curIndex < this.pattern.length) && (this.curIndex >= 0) ) {
return this.pattern[this.curIndex];
}
return -1;
}
/*
* resetLights()
*
* This function makes sure the ratio of red:green lights in the progress lights is correct
* according to the value of curIndex
*
* arguments: none
*
* Returns: none
*/
public function resetLights()
{
var preloader:Preloader = Preloader.getInstance();
var newLight:Bitmap;
for ( var i:Number = 0; i <= this.curIndex ; i++ ) {
// remove any existing red lights and replace them with green lights
// if they're at an index < curIndex
this.removeChild(this.progressLights[i]);
newLight = preloader.getBitmap("gfx_progress_green");
newLight.x = this.progressLights[i].x;
newLight.y = this.progressLights[i].y;
this.progressLights[i] = newLight;
this.addChild(this.progressLights[i]);
}
}
/*
* colorActive(color)
*
* Checks to see if the given color is the one currently active on the pattern.
* Also updates the current index, modifies state, etc, depending on the result.
*
* arguments:
* @color:Number, the Pattern.COLOR_XXX color you want checked
*
* Returns: Boolean (Always returns false on a stopped pattern)
*/
public function colorActive(color:Number):Boolean
{
if ( this.curIndex == -1 ) {
return false;
}
if ( (this.curIndex < this.pattern.length) && (this.pattern[this.curIndex] == color) ) {
// dispatch a PowerupEvent if there is a powerup in this spot at the pattern
if ( this.patternPowerups[this.curIndex] != null ) {
this.dispatchEvent(new PowerupEvent(PowerupEvent.GOT_POWERUP, this.patternPowerups[this.curIndex]));
this.patternPowerups[this.curIndex] = null;
}
this.resetLights();
this.curIndex += 1;
this.score += 5;
if ( this.curIndex >= this.pattern.length ) {
this.curIndex = -1;
this.state = Pattern.STATE_CORRECT;
this.stop();
}
return true;
}
this.state = Pattern.STATE_FAILED;
this.stop();
return false;
}
/*
* onRunningTimer(evt)
*
* Fires along w/ the runningTimer to check pattern logic
*
* arguments:
* @evt:Event, event firing this function
*
* Returns : none
*/
public function onRunningTimer(evt:TimerEvent)
{
if ( (!evt) || (evt.target != this.patternTimer) )
return;
this.clearTime -= this.clearDecrement;
if ( this.clearTime < 0 ) {
this.clearTime = 0;
this.state = Pattern.STATE_FAILED;
this.stop();
}
}
/*
* onDemoTimer(evt)
*
* Runs every time the Demo timer fires, lighting the buttons in sequence at the right times
*
* arguments:
* @evt:Event, the event firing this function
*
* Returns : none
*/
public function onDemoTimer(evt:TimerEvent)
{
if ( (!evt) || (evt.target != this.patternTimer) || (!this.simon) )
return;
if ( this.curIndex >= this.pattern.length ) {
this.state = Pattern.STATE_STOPPED;
this.stop();
return;
}
this.simon.lightButton(this.pattern[curIndex], this.patternTimer.delay/2);
this.curIndex += 1;
}
/*
* onUsedPowerup(evt)
*
* This function fires whenever a PowerupEvent filters down from the Mastermind, which originally
* filtered up from the Player. It processes and applies the effects of any powerups used by the player.
*
* arguments:
* @evt:PowerupEvent, the event firing this function
*
* Returns: none
*/
public function onUsedPowerup(evt:PowerupEvent)
{
var pwup:Powerup = evt.pwup;
if ( pwup.pType == Powerup.PTYPE_FORGIVENESS ) {
// we don't actually have to *do* anything with a forgiveness ...
return;
} else if ( pwup.pType == Powerup.PTYPE_SLOWDOWN ) {
this.clearDecrement = 1;
} else if ( pwup.pType == Powerup.PTYPE_SKIP ) {
this.state = Pattern.STATE_CORRECT;
this.stop();
this.resetLights();
} else if ( pwup.pType == Powerup.PTYPE_DOUBLE ) {
this.scoreMultiplier = 2;
}
return;
}
}
}

View File

@@ -0,0 +1,228 @@
package net.aklabs.demo.simonsays
{
import net.aklabs.demo.simonsays.PowerupEvent;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import net.aklabs.demo.simonsays.Preloader;
import flash.display.Bitmap;
/*
* Class Player
*
* This class represents the player in the game.
*
* The class has two displayable objects in it: the Player object itself,
* and Player.lifeDisplay. The Player object displays the inventory (64 pixels high, up to (64*5) pixels wide)
* The Player.lifeDisplay object displays the remaining number of lives (64 pixels high, up to 64*3 pixels wide)
*
*/
public class Player extends Sprite {
public var score:Number; // the player's current score
public var lives:Number; // the number of lives the player currently has
public var maxPattern:Number; // the largest pattern the player has completed
public var inventory:Array; // the player's inventory
public var lifeDisplay:Sprite; /* the parent sprite to which all the player life sprites are attached (number of remaining lives) ..
we have this parenting the rest of the images, so the Game class can just add this single child object, rather than tracking
and removing all the images in the individual lifeImages array */
protected var lifeImages:Array; // an array of images holding all the images showing up in the player's life array
protected var headExplosion;
/*
* Player()
*
* Default constructor
*
* arguments : none
*
* Returns : none
*/
public function Player()
{
this.score = 0;
this.lives = 3;
this.maxPattern = 0;
this.inventory = new Array();
this.lifeDisplay = new Sprite();
this.lifeImages = new Array();
}
/*
* addPowerup(pwup)
*
* Adds a new powerup to the player's inventory
*
* arguments:
* @pwup:Powerup, the powerup to be added
*
* Returns: none
*/
public function addPowerup(pwup:Powerup)
{
if ( this.inventory.length >= 5 ) {
return;
}
this.inventory.push(pwup);
this.resetPowerupPositions();
this.addChild(pwup);
pwup.addEventListener(MouseEvent.MOUSE_UP, this.onPowerupClicked);
}
/*
* resetPowerupPositions()
*
* This function goes through the player's inventory and makes sure the positions line up (mostly) with the background graphic for their slot
*
* arguments: none
*
* Returns: none
*/
protected function resetPowerupPositions()
{
for ( var i = 0; i < this.inventory.length ; i++ ) {
var pwup:Powerup = this.inventory[i];
pwup.x = 2+(70*i);
pwup.y = 0;
}
}
/*
* die()
*
* This function is called whenever the player should die - lose a life
*
* arguments: none
*
* Returns: none
*/
public function die()
{
// lose a life, and do it in style
var preloader:Preloader = Preloader.getInstance();
this.headExplosion = preloader.getMovieClip("movie_explosion");
this.headExplosion.addEventListener(Event.ENTER_FRAME, this.stopExplosion);
this.headExplosion.x = (this.lives * 64)-32;
this.headExplosion.y = 32;
this.lifeDisplay.addChild(this.headExplosion);
this.headExplosion.play();
preloader.playSound("sfx_explosion");
this.lives -= 1;
this.resetLifePositions();
}
/*
* stopExplosion(evt)
*
* This stops the head explosion animation from looping (much like Game.onNonLoopEnterFrame)
*
* arguments:
* @evt:Event, the event firing this function
*
* Returns: none
*/
public function stopExplosion(evt:Event)
{
if ( evt.target.currentFrame == evt.target.totalFrames ) {
this.headExplosion.stop();
this.lifeDisplay.removeChild(this.headExplosion);
this.headExplosion.removeEventListener(Event.ENTER_FRAME, this.stopExplosion);
this.headExplosion = null;
}
}
/*
* resetLifePositions()
*
* This function arranges the images representing the number of remaining lives the player has
*
* arguments: none
*
* returns : none
*/
public function resetLifePositions()
{
var i:Number = 0;
var preloader:Preloader = Preloader.getInstance();
if ( this.lifeImages.length < this.lives ) {
for ( i = this.lifeImages.length; i < this.lives; i++ ) {
var img:Bitmap = preloader.getBitmap("gfx_pwup_freelife");
img.x = 64*i;
img.y = 0;
this.lifeImages.push(img);
this.lifeDisplay.addChild(img);
}
} else {
for ( var i = 0; i < this.lifeImages.length ; i++ ) {
if ( i >= this.lives ) {
this.lifeDisplay.removeChild(this.lifeImages[i]);
this.lifeImages.splice(i, 1);
}
}
}
for ( var i = 0; i < this.lifeImages.length ; i++ ) {
this.lifeImages[i].x = 64*i;
this.lifeImages[i].y = 0;
}
}
/*
* usePowerupAt(index)
*
* See if there is a powerup at index 'index' in the inventory, use it, fire off any sounds associated with it,
* and dispatch a new PowerupEvent for it
*
* arguments:
* @index:Number, the index in inventory from which the powerup should be drawn
*
* returns: none
*/
public function usePowerupAt(index:Number)
{
if ( index < this.inventory.length ) {
this.removeChild(this.inventory[index]);
var preloader:Preloader = Preloader.getInstance();
preloader.playSound(this.inventory[index].sndHandle);
this.resetPowerupPositions();
this.dispatchEvent(new PowerupEvent(PowerupEvent.USED_POWERUP, this.inventory[index]));
this.inventory[index].removeEventListener(MouseEvent.MOUSE_UP, this.onPowerupClicked);
this.inventory.splice(index, 1);
}
}
/*
* onPowerupClicked(evt)
*
* This function is fired whenever the player clicks the mouse on a powerup owned by the player
*
* arguments:
* @evt:MouseEvent, the event firing this function
*
* Returns: none
*/
public function onPowerupClicked(evt:MouseEvent)
{
for ( var i:Number = 0 ; i < this.inventory.length ; i++ ) {
if ( this.inventory[i] == evt.target ) {
this.usePowerupAt(i);
}
}
}
/*
* clearInventory()
*
* Fairly obvious, this function just clears out the inventory
*
* arguments: none
*
* returns: none
*/
public function clearInventory()
{
for ( var i:Number = 0; i < this.inventory.length ; i++ ) {
this.removeChild(this.inventory[i]);
this.inventory.splice(i, 1);
}
}
}
}

View File

@@ -0,0 +1,29 @@
package net.aklabs.demo.simonsays {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import net.aklabs.demo.simonsays.PowerupEvent;
/*
* Class Powerup
*
* This class just represents a powerup in the game.
* This is more a data structure than a class, but I don't think
* AS 3.0 has just bare structures. Silly ECMA language...
*/
public class Powerup extends Sprite
{
public static var PTYPE_SLOWDOWN:Number = 0; /* SLOWDOWN - Slows the pattern timer to a much lower rate */
public static var PTYPE_FORGIVENESS:Number = 1; /* FORGIVENESS - If you have FORGIVENESSS in your inventory and you miss a pattern, it doesn't stop you */
public static var PTYPE_SKIP:Number = 2; /* SKIP - Lets you "skip" a given pattern iteration, and you still get all the score for it. */
public static var PTYPE_DOUBLE:Number = 3; /* DOUBLE - Score double points for the pattern on which you use this powerup. */
public static var PTYPE_MAXVALUE:Number = 4;
// POWERUP_IMAGES - these are the image handles (stored in an array where idx => PTYPE_XXX) for each of the powerup types
public static var POWERUP_IMAGES = new Array("gfx_pwup_slowdown", "gfx_pwup_forgiveness", "gfx_pwup_exclamation", "gfx_pwup_pointdoubler");
// POWERUP_SOUNDS - these are the sound handles (stored in an array where idx => PTYPE_XXX) for each of the powerup types
public static var POWERUP_SOUNDS = new Array("sfx_slowdown", "sfx_forgiveness", "sfx_exclamation", "sfx_pointdoubler");
public var imgHandle:String; // the handle for the image of this specific powerup
public var sndHandle:String; // the handle for the sound of this specific powerup
public var pType:Number; // the PTYPE_XXX of this powerup
}
}

View File

@@ -0,0 +1,32 @@
package net.aklabs.demo.simonsays {
import flash.events.Event;
import net.aklabs.demo.simonsays.Powerup;
/*
* Class PowerupEvent
*
* An event specifically made for actions taken regarding powerups
*/
public class PowerupEvent extends Event {
public static var GOT_POWERUP:String = "SIMONSAYS_GOT_POWERUP"; // Type for events when a powerup was received
public static var USED_POWERUP:String = "SIMONSAYS_USED_POWERUP"; // Type for events when a powerup was used
public var pwup:Powerup; // the powerup (rather than the target) of this event
/*
* PowerupEvent()
*
* Default Constructor
*
* arguments:
* @evtType:String, the type of this event (GOT_POWERUP or USED_POWERUP)
* @tgt:Powerup, the Powerup object that's being affected by this event
*
* returns: none
*/
public function PowerupEvent(evtType:String, tgt:Powerup = null)
{
super(evtType);
this.pwup = tgt;
}
}
}

View File

@@ -0,0 +1,529 @@
package net.aklabs.demo.simonsays {
import net.aklabs.demo.simonsays.LoadingObject;
import flash.utils.Dictionary;
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.media.Sound;
import flash.display.MovieClip;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.events.ProgressEvent;
import flash.events.Event;
/*
* Class Preloader
*
* This class is what loads and manages the cache of media assets for the game
* This class is a singleton, which was annoyingly difficulty to implement in
* Actionscript 3 because it doesn't support private constructors.
*
* Be careful subclassing this, because of the way the singleton mechanism was implemented,
* it may break.
*
* This class can be added as a child asset, and it will display a pair of progress
* bars as it loads all the assets. The top bar is the progress on the current file,
* the bottom bar is the progress on the total set of assets. You don't have to display the
* preloader, but if you do, make sure to load via the assets array, rather than calling loadImage()
* and such manually, as the progress bars will act funky.
*
* When the preloader has loaded all of the assets, it will dispatch a COMPLETE event that should be handled
* by whatever higher game class, as a signal that all assets are ready and cached.
*/
public class Preloader extends Sprite {
protected var objects:Dictionary; // this contains all loaded objects, keyed by their handle
protected var loading_by_instance:Dictionary; // this contains the [handle, bytes read, bytes total] of all objects that are currently loading, keyed by their instance
protected var loading_by_handle:Dictionary; // this contains the [instance, bytes read, bytes total] of all objects that are currently loading, keyed by their handle
protected static var instance:Preloader = null; // the singleton instance
protected var curAsset:Number; // the index of the asset (in the assets array) currently being loaded
protected var assets:Array; // the array of all the assets to be loaded
/* format of the 'assets' array:
[ ASSET_ARRAY, ASSET_ARRAY ...]
each ASSET_ARRAY is...
["images"|"sounds"|"movies", "TEXT HANDLE", "URI", "CLASS NAME"]
... The "images"|"sounds"|"movies" serves an obvious purpose; it says what kind of asset we're loading,
as the mechanism for loading images/sounds/movies are different.
The TEXT HANDLE is a text handle that can be used when referencing this asset in the preloader
The URI is just that, the URI where this object can be found. Usual security restrictions apply.
The CLASS NAME is only important for exported SWF movies, and must equal whatever the class name is
that you set for that SWF when telling Flash to export it for Actionscript. If this is wrong, or you
don't export your SWFs for actionscript, you won't be able to instantiate new MovieClip/Sprites of them.
*/
protected var loadingLabel:TextField; // just a text label that says "Please wait; loading"
protected var progressSpinner:Array = new Array("-", "\\", "|", "/"); // an array of characters that creates a spinner for the loading label
protected var progSpin:Number = 0; // the current index in the progressSpinner array
protected var classDefs:Dictionary; // classDefs holds the class definitions for each of the given objects (if supplied), keyed by text handle
protected var classNames:Dictionary; // classNames holds the name of the classes for each of the given objects (if supplied), keyed by text handle
/*
* getInstance()
*
* Returns the instance of the singleton
*
* arguments: none
*
* Returns: Preloader
*/
public static function getInstance():Preloader
{
if ( Preloader.instance == null )
Preloader.instance = new Preloader();
return Preloader.instance;
}
/*
* Preloader(assets)
*
* Default constructor for Preloader
*
* arguments:
* @assets:Array, the asset array to be loaded (default null)
*
* Returns: none
*/
public function Preloader(assets:Array = null)
{
if ( Preloader.instance != null )
throw("Don't use (new Preloader()) directly, use Preloader.getInstance() to prevent duplication of this singleton class.");
this.objects = new Dictionary();
this.loading_by_instance = new Dictionary();
this.loading_by_handle = new Dictionary();
Preloader.instance = this;
this.curAsset = 0;
if ( assets != null)
this.assets = assets;
var labelFormat = new TextFormat();
labelFormat.font = "Courier New";
labelFormat.bold = false;
labelFormat.color = 0xFFFFFF;
labelFormat.size = 12;;
this.loadingLabel = new TextField();
this.loadingLabel.background = false;
this.loadingLabel.autoSize = TextFieldAutoSize.LEFT;
this.loadingLabel.defaultTextFormat = labelFormat;
this.loadingLabel.text = "Please wait; loading |"
this.loadingLabel.x = 0;
this.loadingLabel.y = 0;
this.addChild(loadingLabel);
this.classDefs = new Dictionary();
this.classNames = new Dictionary();
}
/*
* setAssets(assets)
*
* Set the asset array for the preloader
*
* arguments:
* @assets:Array, the array of assets
*
* returns: none
*/
public function setAssets(assets:Array)
{
this.assets = assets;
}
/*
* loadAssets()
*
* Start loading all the assets
*
* arguments: none
*
* returns: none
*/
public function loadAssets()
{
this.onLoadComplete(null);
}
/*
* getObject(handle)
*
* Get a generic Object referenced by the given handle
*
* argument:
* @handle:String, the text handle of the object you want
*
* returns: object you want, or null
*/
public function getObject(handle:String)
{
if ( this.objects[handle] )
return this.objects[handle];
return null;
}
/*
* getBitmap(handle:String)
*
* This function returns a CLONE of a Bitmap object in the preloader. Use this when
* you want a bitmap that you can use in more than one place, e.g., more like a sprite.
* All instances will reference the same bitmap data, however, so any modification to
* the core bitmap data will show up in all instances.
*
* arguments:
* @handle:String, the text handle reference for the bitmap you want
*
* returns Bitmap on success, null on failure
*/
public function getBitmap(handle:String)
{
var obj = this.getObject(handle);
if ( (obj) && (obj is Bitmap) ) {
var bm = new Bitmap(obj.bitmapData);
return bm;
}
return obj;
}
/*
* getBitmap(handle:String)
*
* This function returns a CLONE of a MovieClip object in the preloader. Use this when
* you want a MovieClip that you can use in more than one place, e.g., more like a sprite.
* All instances will reference the same frame data, however, so any modification to
* the core frame data will show up in all instances.
*
* arguments:
* @handle:String, the text handle reference for the bitmap you want
*
* returns MovieClip on success, null on failure
*/
public function getMovieClip(handle:String):MovieClip
{
var obj = this.getObject(handle);
try {
var clip:Class = this.classDefs[handle];
if ( clip ) {
return new clip();
}
} catch (error:Error) {
trace(error);
return null;
}
return null;
}
/*
* startObject(obj, handle)
*
* Start loading the given object with the given handle. Sets up event handling for notifications on the event while it loads.
*
* arguments:
* @obj:Loader|Sound, either a Loader or a Sound object, referencing the object which has already had its URI set and begun loading
* @handle:String, the text string by which this object should be referenced
*
* returns: none
*/
protected function startObject(obj, handle:String)
{
var toadd = obj;
if ( obj is Loader ) {
toadd = obj.contentLoaderInfo;
}
toadd.addEventListener(Event.COMPLETE, this.onLoadComplete);
toadd.addEventListener(ProgressEvent.PROGRESS, this.onProgressUpdate);
toadd.addEventListener(IOErrorEvent.IO_ERROR, this.onIOError);
toadd.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurityError);
this.loading_by_instance[toadd] = new Array(handle, 0, 0);
this.loading_by_handle[handle] = new Array(obj, 0, 0);
}
/*
* stopObject(obj)
*
* Stops loading on a given object, unhooks all the event listeners, etc
*
* arguments:
* @obj:Loader|Sound, the object on which loading should stop
*
* returns: none
*/
protected function stopObject(obj)
{
var obj_info = this.loading_by_instance[obj];
obj.removeEventListener(Event.COMPLETE, this.onLoadComplete);
obj.removeEventListener(ProgressEvent.PROGRESS, this.onProgressUpdate);
obj.removeEventListener(IOErrorEvent.IO_ERROR, this.onIOError);
obj.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.onSecurityError);
delete this.loading_by_handle[this.loading_by_instance[obj][0]];
delete this.loading_by_instance[obj];
}
/*
* getObjectStatus(handle)
*
* Returns a LoadingObject object that describes the current loading status of the object you're inquiring about
*
* arguments:
* @handle:String, the handle of the object you want to know about
*
* returns : LoadingObject
*/
public function getObjectStatus(handle:String):LoadingObject
{
var objStats = new LoadingObject();
objStats.handle = handle;
if ( this.objects[handle] ) {
objStats.state = LoadingObject.STATE_READY;
} else if ( this.loading_by_handle[handle] ) {
objStats.state = LoadingObject.STATE_LOADING;
objStats.bytesRead = this.loading_by_handle[handle][1];
objStats.bytesTotal = this.loading_by_handle[handle][2];
}
return objStats;
}
/*
* loadImage(uri, handle)
*
* Start loading the image at the given URI with the given handle
*
* arguments:
* @uri:String, the URI where the file lives
* @handle:String, the handle for the object
*
* returns: none
*/
public function loadImage(uri:String, handle:String)
{
var request:URLRequest = new URLRequest(uri);
var img = new Loader();
img.load(request);
this.startObject(img, handle);
}
/*
* loadMovie(uri, handle, className)
*
* Loads an external SWF object from URI and stores it as 'handle' and stores the class definition from it where the class name is className
*
* arguments:
* @uri:String, the URI where the file lives
* @handle:String, the handle for this object
* @className:String, the name of the SWF class when exported for Actionscript
*
* returns: none
*/
public function loadMovie(uri:String, handle:String, className:String)
{
var request:URLRequest = new URLRequest(uri);
var movie = new Loader();
movie.load(request);
this.startObject(movie, handle);
this.classNames[handle] = className;
trace(this.classNames[handle]);
}
/*
* loadSound(uri, handle)
*
* Loads the given sound
*
* arguments:
* @uri:String, the URI from which to load the sound
* @handle:String, the handle to store the sound as
*
* returns: none
*/
public function loadSound(uri:String, handle:String)
{
var request:URLRequest = new URLRequest(uri);
var snd = new Sound();
snd.load(request);
this.startObject(snd, handle);
}
/*
* playSound(handle)
*
* Locates the sound associated with the given handle, and plays it
*
* arguments:
* @handle:String, the text handle for the sound you want
*
* returns: Boolean (true on success, false on error)
*/
public function playSound(handle:String):Boolean
{
var snd = this.getObject(handle);
if ( !snd )
return false;
snd.play(); // we don't care about the channel it returns
return true;
}
/*
* onIOError(evt)
*
* This function fires whenever there's an IO Error that prevents the object from finishing loading
*
* arguments:
* @evt:IOErrorEvent, the event firing this function
*
* returns: none
*/
protected function onIOError(evt:IOErrorEvent)
{
var obj = evt.target;
var obj_info = this.loading_by_instance[obj];
var handle = obj_info[0];
var read = obj_info[1];
var total = obj_info[2];
this.stopObject(obj);
}
/*
* onSecurityError(evt)
*
* This function fires whenever there's a security error that prevents the object from finishing loading
*
* arguments:
* @evt:SecurityErrorEvent, the event firing this function
*
* returns: none
*/
protected function onSecurityError(evt:SecurityErrorEvent)
{
var obj = evt.target;
var obj_info = this.loading_by_instance[obj];
var handle = obj_info[0];
var read = obj_info[1];
var total = obj_info[2];
this.stopObject(obj);
}
/*
* onProgressUpdate(evt)
*
* This function fires whenever there's a progress update on the object currently loading
*
* arguments:
* @evt:ProgressEvent, the event firing this function
*
* returns: none
*/
protected function onProgressUpdate(evt:ProgressEvent)
{
var obj = evt.target;
var handle = this.loading_by_instance[obj][0];
this.loading_by_instance[obj][1] = this.loading_by_handle[handle][1] = evt.bytesLoaded;
this.loading_by_instance[obj][2] = this.loading_by_handle[handle][2] = evt.bytesTotal;
this.drawProgressMeters(evt);
this.progSpin += 1;
if ( this.progSpin >= this.progressSpinner.length ) {
this.progSpin = 0;
}
this.loadingLabel.text = "Please wait; loading ... " + this.progressSpinner[this.progSpin];
}
/*
* onLoadComplete(evt)
*
* This function fires whenever a file finishes loading. You can call this, after setting the assets array, with a null event.
* In such a case, the loading process will simply be started.
*
* arguments:
* @evt:Event, the event firing this function (default null)
*
* returns: none
*/
protected function onLoadComplete(evt:Event = null)
{
if ( evt != null ) {
var obj = evt.target;
var handle = this.loading_by_instance[obj][0];
if ( obj is LoaderInfo ) {
this.objects[handle] = obj.content;
trace(this.classNames[handle]);
if ( (this.classNames[handle]) && (this.classNames[handle] != "") )
this.classDefs[handle] = obj.applicationDomain.getDefinition(this.classNames[handle]);
else
this.classDefs[handle] = null;
} else
this.objects[handle] = obj
this.stopObject(obj);
this.curAsset += 1;
}
if ( this.curAsset < this.assets.length ) {
var asset = this.assets[this.curAsset];
var asset_stat = this.getObjectStatus(asset[1]);
if ( asset_stat.state == LoadingObject.STATE_NOTFOUND ) {
if ( asset[0] == "sounds" ){
this.loadSound(asset[2], asset[1]);
} else if ( asset[0] == "images" ) {
this.loadImage(asset[2], asset[1]);
} else if ( asset[0] == "movies" ) {
this.loadMovie(asset[2], asset[1], asset[3]);
}
}
} else if ( this.curAsset >= this.assets.length ) {
var evt = new Event(Event.COMPLETE);
this.dispatchEvent(evt);
}
}
/*
* drawProgressMeters(evt)
*
* This function redraws the visible progress meters; it is generally called from inside of onProgressUpdate.
* It isn't fired by a timer, but it does need to have the event passed in to it so it can access the bytes read, etc.
*
* arguments:
* @evt:ProgressEvent, the event firing this function (default null)
*
* returns: none
*/
protected function drawProgressMeters(evt:ProgressEvent)
{
this.graphics.clear();
// draw the file progress meter
// white box
this.graphics.lineStyle(1,0xFFFFFF);
this.graphics.beginFill(0xFFFFFF);
this.graphics.drawRoundRect(60, 30, 200, 15, 5);
this.graphics.endFill();
// blue bar
this.graphics.lineStyle(1,0x6E6BF4);
this.graphics.beginFill(0x6E6BF4);
this.graphics.drawRoundRect(60, 30, 200*(evt.bytesLoaded/evt.bytesTotal), 15, 5);
this.graphics.endFill();
// red box
this.graphics.lineStyle(3, 0xAC2626);
this.graphics.drawRoundRect(60, 30, 200, 15, 5);
// draw the total progress meter
// white box
this.graphics.lineStyle(1,0xFFFFFF);
this.graphics.beginFill(0xFFFFFF);
this.graphics.drawRoundRect(60, 60, 200, 15, 5);
this.graphics.endFill();
// blue bar
this.graphics.lineStyle(1,0x6E6BF4);
this.graphics.beginFill(0x6E6BF4);
this.graphics.drawRoundRect(60, 60, 200*(this.curAsset/this.assets.length), 15, 5);
this.graphics.endFill();
// red box
this.graphics.lineStyle(3, 0xAC2626);
this.graphics.drawRoundRect(60, 60, 200, 15, 5);
}
}
}

View File

@@ -0,0 +1,123 @@
package net.aklabs.demo.simonsays {
import flash.events.MouseEvent;
import flash.display.Bitmap;
import flash.display.Sprite;
/*
* class SimonButton
*
* This is just a custom button class that is pixel-accurate, because the Mastermin/Simon Says
* buttons are an extremely odd shape, so I needed something that could detect mouse hits in/
* outside of the alpha color areas.
*
* Most of this class is really self explanatory, so I'm not going to bother documenting all of it. Only the parts that don't make immediate sense.
*/
public class SimonButton extends Sprite
{
protected var imgDown:Bitmap; // bitmap for when the button is pressed
protected var imgUp:Bitmap; // bitmap for when the button is released
protected var curImg:Bitmap; // the bitmap currently being displayed on the button
protected var magicColor:Number; // the magic color (e.g. "magic pink"), if any (otherwise alpha is used for hit detection)
public function SimonButton(imgDown:Bitmap = null, imgUp:Bitmap = null, magicColor = 0x00000000)
{
super();
this.imgDown = imgDown;
this.imgUp = imgUp;
this.curImg = null;
this.magicColor = magicColor;
this.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseDown);
this.addEventListener(MouseEvent.MOUSE_UP, this.onMouseUp);
this.addEventListener(MouseEvent.CLICK, this.onMouseClick);
}
public function setMagicColor(color:Number)
{
this.magicColor = color;
}
public function setBtnDown(obj:Bitmap)
{
if ( obj ) {
this.imgDown = obj;
}
}
public function setBtnUp(obj:Bitmap)
{
if ( obj ) {
this.imgUp = obj;
}
}
public function onMouseDown(obj:MouseEvent)
{
if ( (obj) && (! this.hitTestPoint(obj.localX, obj.localY)) ) {
obj.stopImmediatePropagation();
return;
}
if ( this.curImg ) {
this.removeChild(this.curImg);
}
if ( this.imgDown ) {
this.addChild(this.imgDown);
this.curImg = this.imgDown;
}
}
public function onMouseUp(obj:MouseEvent)
{
if ( (obj) && (!this.hitTestPoint(obj.localX, obj.localY)) ) {
obj.stopImmediatePropagation();
return;
}
if ( this.curImg ) {
this.removeChild(this.curImg);
}
if ( this.imgUp ) {
this.addChild(this.imgUp);
this.curImg = this.imgUp;
}
}
public function onMouseClick(obj:MouseEvent)
{
if ( ! this.hitTestPoint(obj.localX, obj.localY) ) {
obj.stopImmediatePropagation();
}
}
/*
* hitTestPoint(x, y, shapeFlag)
*
* An overriden version of hitTestPoint that is pixel-accurate. If the value at (x, y) is either A: of the value
* in the "magic color", or B: containing an alpha value of zero, then the hit is POSITIVE. Otherwise it is false.
*
* arguments:
* @x:Number, the X location of the hit relative to the origin of the object
* @y:Number, the Y location of the hit relative to the origin of the object
* @shapeFlag:Boolean, not used, just here for compatibility
*
* returns: Boolean (true if the hit is positive, false if it's negative)
*/
public override function hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean
{
var color:uint;
var rgb:uint;
var a:uint;
if ( this.curImg && this.curImg.bitmapData ) {
color = this.curImg.bitmapData.getPixel32(x, y);
a = ((color >> 24) & 0xFF);
rgb = (color & 0xFFFFFF00);
//trace("Alpha : " + a + " RGB " + rgb + " magic color " + this.magicColor);
if ( this.magicColor == rgb || a == 0 ) {
return false;
}
return true;
}
return false;
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,292 @@
//v1.7
// Flash Player Version Detection
// Detect Client Browser type
// Copyright 2005-2007 Adobe Systems Incorporated. All rights reserved.
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
function ControlVersion()
{
var version;
var axo;
var e;
// NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry
try {
// version will be set for 7.X or greater players
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
version = axo.GetVariable("$version");
} catch (e) {
}
if (!version)
{
try {
// version will be set for 6.X players only
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
// installed player is some revision of 6.0
// GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
// so we have to be careful.
// default to the first public version
version = "WIN 6,0,21,0";
// throws if AllowScripAccess does not exist (introduced in 6.0r47)
axo.AllowScriptAccess = "always";
// safe to call for 6.0r47 or greater
version = axo.GetVariable("$version");
} catch (e) {
}
}
if (!version)
{
try {
// version will be set for 4.X or 5.X player
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
version = axo.GetVariable("$version");
} catch (e) {
}
}
if (!version)
{
try {
// version will be set for 3.X player
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
version = "WIN 3,0,18,0";
} catch (e) {
}
}
if (!version)
{
try {
// version will be set for 2.X player
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
version = "WIN 2,0,0,11";
} catch (e) {
version = -1;
}
}
return version;
}
// JavaScript helper required to detect Flash Player PlugIn version information
function GetSwfVer(){
// NS/Opera version >= 3 check for Flash plugin in plugin array
var flashVer = -1;
if (navigator.plugins != null && navigator.plugins.length > 0) {
if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
var descArray = flashDescription.split(" ");
var tempArrayMajor = descArray[2].split(".");
var versionMajor = tempArrayMajor[0];
var versionMinor = tempArrayMajor[1];
var versionRevision = descArray[3];
if (versionRevision == "") {
versionRevision = descArray[4];
}
if (versionRevision[0] == "d") {
versionRevision = versionRevision.substring(1);
} else if (versionRevision[0] == "r") {
versionRevision = versionRevision.substring(1);
if (versionRevision.indexOf("d") > 0) {
versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
}
}
var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
}
}
// MSN/WebTV 2.6 supports Flash 4
else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
// WebTV 2.5 supports Flash 3
else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
// older WebTV supports Flash 2
else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
else if ( isIE && isWin && !isOpera ) {
flashVer = ControlVersion();
}
return flashVer;
}
// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision)
{
versionStr = GetSwfVer();
if (versionStr == -1 ) {
return false;
} else if (versionStr != 0) {
if(isIE && isWin && !isOpera) {
// Given "WIN 2,0,0,11"
tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"]
tempString = tempArray[1]; // "2,0,0,11"
versionArray = tempString.split(","); // ['2', '0', '0', '11']
} else {
versionArray = versionStr.split(".");
}
var versionMajor = versionArray[0];
var versionMinor = versionArray[1];
var versionRevision = versionArray[2];
// is the major.revision >= requested major.revision AND the minor version >= requested minor
if (versionMajor > parseFloat(reqMajorVer)) {
return true;
} else if (versionMajor == parseFloat(reqMajorVer)) {
if (versionMinor > parseFloat(reqMinorVer))
return true;
else if (versionMinor == parseFloat(reqMinorVer)) {
if (versionRevision >= parseFloat(reqRevision))
return true;
}
}
return false;
}
}
function AC_AddExtension(src, ext)
{
if (src.indexOf('?') != -1)
return src.replace(/\?/, ext+'?');
else
return src + ext;
}
function AC_Generateobj(objAttrs, params, embedAttrs)
{
var str = '';
if (isIE && isWin && !isOpera)
{
str += '<object ';
for (var i in objAttrs)
{
str += i + '="' + objAttrs[i] + '" ';
}
str += '>';
for (var i in params)
{
str += '<param name="' + i + '" value="' + params[i] + '" /> ';
}
str += '</object>';
}
else
{
str += '<embed ';
for (var i in embedAttrs)
{
str += i + '="' + embedAttrs[i] + '" ';
}
str += '> </embed>';
}
document.write(str);
}
function AC_FL_RunContent(){
var ret =
AC_GetArgs
( arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
, "application/x-shockwave-flash"
);
AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}
function AC_SW_RunContent(){
var ret =
AC_GetArgs
( arguments, ".dcr", "src", "clsid:166B1BCA-3F9C-11CF-8075-444553540000"
, null
);
AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}
function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
var ret = new Object();
ret.embedAttrs = new Object();
ret.params = new Object();
ret.objAttrs = new Object();
for (var i=0; i < args.length; i=i+2){
var currArg = args[i].toLowerCase();
switch (currArg){
case "classid":
break;
case "pluginspage":
ret.embedAttrs[args[i]] = args[i+1];
break;
case "src":
case "movie":
args[i+1] = AC_AddExtension(args[i+1], ext);
ret.embedAttrs["src"] = args[i+1];
ret.params[srcParamName] = args[i+1];
break;
case "onafterupdate":
case "onbeforeupdate":
case "onblur":
case "oncellchange":
case "onclick":
case "ondblclick":
case "ondrag":
case "ondragend":
case "ondragenter":
case "ondragleave":
case "ondragover":
case "ondrop":
case "onfinish":
case "onfocus":
case "onhelp":
case "onmousedown":
case "onmouseup":
case "onmouseover":
case "onmousemove":
case "onmouseout":
case "onkeypress":
case "onkeydown":
case "onkeyup":
case "onload":
case "onlosecapture":
case "onpropertychange":
case "onreadystatechange":
case "onrowsdelete":
case "onrowenter":
case "onrowexit":
case "onrowsinserted":
case "onstart":
case "onscroll":
case "onbeforeeditfocus":
case "onactivate":
case "onbeforedeactivate":
case "ondeactivate":
case "type":
case "codebase":
case "id":
ret.objAttrs[args[i]] = args[i+1];
break;
case "width":
case "height":
case "align":
case "vspace":
case "hspace":
case "class":
case "title":
case "accesskey":
case "name":
case "tabindex":
ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
break;
default:
ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
}
}
ret.objAttrs["classid"] = classid;
if (mimeType) ret.embedAttrs["type"] = mimeType;
return ret;
}

View File

@@ -0,0 +1,52 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>simon says</title>
<script language="javascript">AC_FL_RunContent = 0;</script>
<script src="AC_RunActiveContent.js" language="javascript"></script>
</head>
<body bgcolor="#000000" text="white">
<!--url's used in the movie-->
<!--text used in the movie-->
<!-- saved from url=(0013)about:internet -->
<center><h2>CLICK <a href="http://www.aklabs.net/~akesterson/wilysays/help.html">HERE</a> FOR HELP!</h2></center>
<br/><br/>
<script language="javascript">
if (AC_FL_RunContent == 0) {
alert("This page requires AC_RunActiveContent.js.");
} else {
AC_FL_RunContent(
'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0',
'width', '640',
'height', '480',
'src', 'simon says',
'quality', 'high',
'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
'align', 'middle',
'play', 'true',
'loop', 'true',
'scale', 'showall',
'wmode', 'window',
'devicefont', 'false',
'id', 'simon says',
'bgcolor', '#000000',
'name', 'simon says',
'menu', 'true',
'allowFullScreen', 'false',
'allowScriptAccess','sameDomain',
'movie', 'simon says',
'salign', ''
); //end AC code
}
</script>
<noscript>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="640" height="480" id="simon says" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="false" />
<param name="movie" value="simon says.swf" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /> <embed src="simon says.swf" quality="high" bgcolor="#000000" width="640" height="480" name="simon says" align="middle" allowScriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>
</noscript>
</body>
</html>

View File

@@ -0,0 +1,145 @@
<html>
<body bgcolor="black" text="white">
<center><h1>MEGA MAN: Wily Says!</h1>
<h2>HELP!</h2>
</center>
This is the help information for Mega Man: Wily Says!, the smash-megahit
game currently sweeping teh intarnets. Here's how to play the game.
<br/>
<center><img src="help1.png"></center>
<br/>
Once the game loads up, click inside the game window with your mouse to
make sure it has focus. Then hit your SPACE BAR. Click on one of the
difficulty setting buttons, to choose the difficulty. This determines
how many levels you play, and how long the patterns you're challenged with,
will be. Once you've done that, watch the intro; it'll give you a little
bit of background story, and a little bit of information on how to play
the game.
<center><h1>The interface</h1></center>
<br/>
<center><img src="help2.png"></center>
<br/>
<ul>
<li>The "SCORE" in the upper left corner of the window displays your current
total score. Higher scores mean you're more awesome, therefore higher scores
are better. You increase your score by completing more patterns.</li>
<li>The "TIMER" in the upper right corner of the window displays the amount of
time you have left to repeat the pattern. The timer may run faster or slower
depending on what difficulty setting you chose, as well as any powerups
you may or may not be using right then.</li>
<li>The numbered slots on the bottom left are your powerup slots. Hidden
inside the patterns are powerups; when you complete a pattern that has a
powerup associated with it, you get the powerup, and it shows up in one
of these numbered slots. To use one of the powerups, you can either click
on the powerup, or press the number key on your keyboard (non-numeric keypad)
above that powerup. Here are the powerups and what they do:
<br/><br/>
<table cols=3 cellspacing = 5>
<tr>
<td><b>Powerup Icon</b></td>
<td><b>Powerup Name</b></td>
<td><b>Powerup Effect</b></td>
</tr>
<tr>
<td><img src="gfx/EXCLAMATION.png"></td>
<td valign=bottom>SKIP</td>
<td valign=bottom>Skips the current pattern iteration you're on, and gives you all the score points for it</td>
</tr>
<tr>
<td><img src="gfx/FORGIVENESS.png"></td>
<td valign=bottom>FORGIVENESS</td>
<td valign=bottom>If you have a FORGIVENESS in your inventory, and you mess up a pattern, then you don't have to start over on a new pattern; it's as if the mistake never happened.</td>
</tr>
<tr>
<td><img src="gfx/POINTDOUBLER.png"></td>
<td valign=bottom>POINT DOUBLER</td>
<td valign=bottom>When this powerup is used, the current pattern iteration will give you double the number of points it normally would have.</td>
</tr>
<tr>
<td><img src="gfx/SLOWDOWN.png"></td>
<td valign=bottom>SLOW DOWN</td>
<td valign=bottom>When this powerup is used, the timer runs at an incredibly slow speed, virtually stopping.</td>
</tr>
</table>
</li>
<li> The "ATTEMPTS REMAINING" at the bottom right will show many lives
you have left. Every time you miss a light on a pattern, you will
lose one life. When you reach 0 lives, the lock will self-detonate,
and you will experience the crushing failure that is Game Over.</li>
<li>The red lights on the right side of the screen indicate the total
number of lights in this pattern; for example, if there are 3
red lights, then this pattern has 3 lights to its combination.
Therefore you will have one iteration with one light, one
iteration with 2 lights, and one iteration with 3 lights.
We all remember how a Simon Says works, right?
As you complete iterations, those iterations will turn lights
from red to green, showing how far away you are from completing
the lock/pattern and progressing to the next level.</li>
<li>The thing that looks like a Simon Says in the middle of the screen
isn't actually a simon says. Yeah, I know - I know, it looks
like one, but it's *not*. It's called the WilyLok, "an ingenious
pattern-based locking mechanism" designed to keep Mega Man
out of Dr Wily's laboratory while he destroys the world.
This is where most of the gameplay happens. All you have to do
is press the lighted buttons in the same pattern that they
flash. All 4 lights will flash once, and then the lights you
need to press will light individually. Then all 4 lights
will flash again, and the timer will start ticking.
Now you have to click on the lights in the same pattern that
you just watched. Failure to do so will explode your skull
and you'll lose a life - and what's worse, you'll have to
start over.</li>
</ul>
Simple, right?
<center><h2>Credits</h2></center>
<pre>
Pre-formatting this because I'm lazy.
Most of this was assembled ad-hoc from various places around the internet
for a game demo to accompany a resume, so it was never really intended for
public consumption. But before the whole thing was over, it just became
so ridiculous I couldn't possibly keep it to myself.
The theme music is a MIDI version of Depeche Mode's "Master and Servant". That's
where the name "Mastermind" for the Simon Says came from.
The graphics were mostly stolen from mega man fansites around the internet.
The explosion graphic was lifted from someone. I forget who. It's the same
one I used in my "HOLY *@#%! ALIENS!" space shooter demo.
The sound effects, again, were lifted from various free sites around the
net. I honestly didn't keep track of them. I know they were all straight off
Google links.
I'm solely responsible for this atrocity; if you want to send me hate mail,
you're a megaman purist and you want to tear off my head, you think this was
the most ridiculous idea for a game demo ever, or if you want to send me
big buckets of money because I'm just so <i>goddamned AWESOME</i>, send mail
to andrew@aklabs.net, or follow me on twitter (@akesterson). Thanks.
The entire demo was coded in ActionScript 3 on Adobe Flash CS3, graphics
were chopped up with The GIMP, sounds composed/trimmed in Audacity. I think
I spent about a total of 48 hours on this project, and that includes learning
ActionScript 3. I'll release the source in a few days after an employer
is done looking at it.
</pre>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

View File

@@ -0,0 +1,134 @@
<?php
$db = mysql_connect("localhost", "akesterson", "fadmin");
if ( !$db ) {
die("Unable to connect to mysql database");
}
mysql_select_db("akesterson", $db);
if ( isset($_REQUEST["op"]) ) {
if ( strcmp($_REQUEST["op"], "store") == 0 ) {
$query = ("INSERT INTO wilysays_highscores (score, name, maxpattern, dtime) VALUES (" .
(int)$_REQUEST["score"] . ", \"" . mysql_real_escape_string($_REQUEST["name"]) . "\", " . (int)$_REQUEST["maxpattern"] . ", NOW() );");
//printf($query);
$res = mysql_query($query, $db);
if ( !$res )
die("Unable to insert into the database - WTF?. " . mysql_error($db));
printf("<html><body>\n<center>Groovy</center>\n</body></html>");
}
die();
}
?>
<html>
<body bgcolor="black" text="white">
<center>
<h1>MEGA MAN: Wily Says!</h1>
<h3>Leaderboards</h3>
<h4>Click <a href="http://www.aklabs.net/~akesterson/wilysays/game.html">HERE</a> to play the mega-hit game!</h4>
<h4>Click <a href="http://www.aklabs.net/~akesterson/wilysays/help.html">HERE</a> for instructions on HOW to play the mega-hit game!</h4>
</center>
<table cols=3 align="center" >
<tr>
<td valign="top" width="171" ><img src="megaman.png"/></td>
<td valign="top" >
<?php
$totalRows = 0;
$curPage = 0;
$rowsPerPage = 5;
$sortOrder = 1;
if ( isset($_REQUEST["perpage"]) ) {
$rowsPerPage = (int)$_REQUEST["perpage"];
}
if ( isset($_REQUEST["start"]) ) {
$curPage = ((int)$_REQUEST["start"])/$rowsPerPage;
}
if ( isset($_REQUEST["sort"]) ) {
$sortOrder = (int)$_REQUEST["sort"];
}
$totalPages = $totalRows/$rowsPerPage;
$query = "SELECT COUNT(*) AS count FROM wilysays_highscores;";
$res = mysql_query($query, $db);
if ( $res ) {
$row = mysql_fetch_array($res);
$totalRows = $row["count"];
}
$query = "SELECT * FROM wilysays_highscores";
if ( $sortOrder == 0 ) {
$query .= " ORDER BY name ASC";
} else if ( $sortOrder == 1 ) {
$query .= " ORDER BY score DESC ";
} else if ( $sortOrder == 2 ) {
$query .= " ORDER BY maxpattern DESC ";
} else if ( $sortOrder == 3 ) {
$query .= " ORDER BY dtime DESC ";
}
$query .= " LIMIT " . $rowsPerPage . " OFFSET " . ($curPage*$rowsPerPage) . ";";
///printf($query);
$res = mysql_query($query, $db);
if ( $res ) {
printf("\t\t\t<table align=center cols=4 width=440 border=1>\n");
printf("<tr>\n");
if ( $curPage > 0 )
printf(" <td colspan=2 align=left><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?perpage=%d&start=%d\">&lt;&lt; PREVIOUS</td>\n", $rowsPerPage, (($curPage*$rowsPerPage)-$rowsPerPage));
else
printf(" <td colspan=2></td>\n");
if ( $totalRows > ($curPage * $rowsPerPage) )
printf(" <td colspan=2 align=right><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?perpage=%d&start=%d\">NEXT &gt;&gt;</a></td>\n", $rowsPerPage, (($curPage*$rowsPerPage)+$rowsPerPage));
else
printf(" <td colspan=2></td>\n");
printf("</tr>\n");
printf("\t\t\t\t<tr><td><b><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?start=%d&sort=0\">Player<br/>Name</a></b></td><td><b><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?start=%d&sort=1\">Total<br/>Score</a></b></td><td><b><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?start=%d&sort=2\">Longest<br/>Pattern</a></b></td><td><b><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?start=%d&sort=3\">When<br/>Recorded</a></b></td></tr>\n",
($curPage*$rowsPerPage), ($curPage*$rowsPerPage), ($curPage*$rowsPerPage), ($curPage*$rowsPerPage));
while ( $row = mysql_fetch_array($res) ) {
printf("\t\t\t\t<tr>\n");
printf("\t\t\t\t\t<td>" . $row["name"] . "</td>\n");
printf("\t\t\t\t\t<td>" . $row["score"] . "</td>\n");
printf("\t\t\t\t\t<td>" . $row["maxpattern"] . "</td>\n");
printf("\t\t\t\t\t<td>" . $row["dtime"] . "</td>\n");
printf("\t\t\t\t</tr>\n");
}
printf("<tr>\n");
if ( $curPage > 0 )
printf(" <td colspan=2 align=left><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?perpage=%d&start=%d\">&lt;&lt; PREVIOUS</td>\n", $rowsPerPage, (($curPage*$rowsPerPage)-$rowsPerPage));
else
printf(" <td colspan=2></td>\n");
if ( $totalRows > ($curPage * $rowsPerPage) )
printf(" <td colspan=2 align=right><a href=\"http://www.aklabs.net/~akesterson/wilysays/index.php?perpage=%d&start=%d\">NEXT &gt;&gt;</a></td>\n", $rowsPerPage, (($curPage*$rowsPerPage)+$rowsPerPage));
else
printf(" <td colspan=2></td>\n");
printf("</tr>\n");
printf("\t\t\t</table>\n");
}
?>
</td>
<td valign="top" ><img src="wily.png"/></td>
</tr>
</table>
<center>
<br/><br/><i>"A fabulous tour de force..." -- Game Misinformer Bragazine</i>
<br/><br/><i>"Quite possibly the most important thing to happen to
<br/>video games since Shigeru Miyamoto." -- Protendo Trading Cards</i>
<br/><br/><i>"I believe we made the most beautiful thing in the world. Nobody
<br/>would criticize a renowned architect's blueprint that the position
<br/>of a gate is wrong. It's the same as that." --Ken Kutaragi</i>
</center>
</body>
</html>