/*
#=======================#
#== AS3 Sprite Parser ==#
#== Made by zhade ==#
#=======================#
*/
package parser.ragnarok {
import flash.utils.ByteArray;
import flash.utils.Timer;
import flash.utils.*;
import flash.display.*;
import flash.errors.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
public class SpriteParser {
private var SPRBA:ByteArray = new ByteArray(); // The .spr file from which we gonna parse the information
private var ACTBA:ByteArray = new ByteArray(); // .act, same as above
private var spriteData:Array = new Array(); // This will only store the .spr version, ident and number of frames (PAL & RGB)
private var actData:Array = new Array(); // In this array will store almost the entire act data, including each actions, its frames and the subframes information
private var frameData:Array = new Array(); // This saves the sprites width, height, data length and offset of the images in the .spr file
private var paletteData:Array = new Array(); // Pretty much self-explanory right? Structure is paletteData[index(hex)] = RR:GG:BB
private var soundData:Array = new Array(); // Contains the path to sound files in grf, saved as strings
private var bitmapArray:Array = new Array(); // Contains the from .spr to Flash Bitmap converted images
private var dimArray:Array = new Array();
private var animCache:Array = new Array();
private var childArray:Array = new Array();
private var curAct:int; // Which action are we currently viewing? Needed for the UI
private var curFrame:int; // Which frame, also needed for UI
private var frameIdx:int; // An index used for a loop
private var xDimMin:*, xDimMax:*, yDimMin:*, yDimMax:* = null;
public var mcFrame:MovieClip = new MovieClip(); // The movieclip that will hold the frames patterns
public var mcCapture:MovieClip = new MovieClip();
private var fileName:String; // Name of the input string without extension
private var SPRLoader:URLLoader = new URLLoader(); // Load .spr file
private var ACTLoader:URLLoader = new URLLoader(); // Load .act file
private var runTimer:Timer = new Timer( 0 ); // Every 2/1000 sec a frame is converted from .spr to Bitmap. Is needed to prevent the application freeze
private var playTimer:Timer = new Timer( 1000 ); // Timer for the playback, needed for UI. ( Value is changed later in code )
private var useCallback:Boolean = false; // Is set to true if user sets a function for callback
private var callback:Function; // the function the user has set
private var startPoint:Point = new Point( 0, 0 ); // default position, where the sprite is being placed
private var useFixedFrames:Boolean = false; // This determines whether the frameLoading process is loading all Frames or just specifics.
private var fixedFrames:Array = new Array();
private var hasParent:Boolean = false;
private var hasChilds:Boolean = false;
private var parentSpr:SpriteParser = null;
public var isEquipment:Boolean = false;
private var finished:Boolean = false; // After the parsing process this is set to true
private var partialFinish:int;
private var FrameTimer:Number;
// Constructor of the class, either input a string for spr or do it later with the parse() function
public function SpriteParser( SPRFilename:String = null ):void {
if( SPRFilename != null) parse( SPRFilename );
} // End function
// o=====================================================o
// o=====================================================o
// o== ==o
// o== Sprite Parsing ==o
// o== ==o
// o=====================================================o
// o=====================================================o
// Load the file, and call the actual parsing function. If it has been parsed before, show error
public function parse( SPRFilename:String, useFixed:Boolean=false ):void {
useFixedFrames = useFixed;
try {
if( finished ) throw new Error( "Attempting to parse file twice. If you want to parse another sprite please create a new instance." );
fileName = SPRFilename;
if( SPRFilename.lastIndexOf( "." ) != -1 ) fileName = SPRFilename.slice( 0, SPRFilename.lastIndexOf( "." ) );
SPRLoader.dataFormat = URLLoaderDataFormat.BINARY;
var SPRRequest:URLRequest = new URLRequest( fileName + ".spr" );
SPRLoader.addEventListener( Event.COMPLETE, sprLoaded );
SPRLoader.load( SPRRequest );
SPRRequest = null;
} catch( err:Error ) {
trace( err );
}
} // End function
// Parse the sprite file. There isn't much I can say, without explaining the .spr file format.
// Read the arrays string indexes, it should give you an idea what its reading at that point.
private function sprLoaded( ev:Event ):void {
trace( "Starting Sprite Parsing (SPR)" );
var TIME:Number=getTimer();
SPRLoader.removeEventListener( Event.COMPLETE, sprLoaded );
SPRBA = SPRLoader.data;
SPRBA.endian = Endian.LITTLE_ENDIAN;
spriteData['ident'] = SPRBA.readUTFBytes( 2 );
spriteData['version'] = SPRBA.readUnsignedShort().toString( 16 );
spriteData['num_pal'] = SPRBA.readUnsignedShort();
spriteData['num_rgba'] = SPRBA.readUnsignedShort();
var i:int;
for( i = 0; i < spriteData['num_pal']; i++ ) {
frameData[i] = {
width: SPRBA.readUnsignedShort(),
height: SPRBA.readUnsignedShort(),
data_len: SPRBA.readUnsignedShort(),
type: 0,
offset: SPRBA.position
};
SPRBA.position += frameData[i]['data_len'];
//trace( i + ": " + frameData[i]['width'] + " / " + frameData[i]['height'] );
} // End for-loop
for( i = 0; i < spriteData['num_rgba']; i++ ) {
var idx = spriteData['num_pal'] + i;
var Width:uint = SPRBA.readUnsignedShort();
var Height:uint = SPRBA.readUnsignedShort();
frameData[idx] = {
width: Width,
height: Height,
data_len: Width * Height * 4,
type: 1,
offset: SPRBA.position
};
SPRBA.position += frameData[idx]['data_len'];
//trace( idx + ": " + frameData[idx]['width'] + " / " + frameData[idx]['height'] );
} // End for-loop
// After the frames are done, we are almost at the end of the file.
// The only thing thats left is the color palette. (Note that even if its a sprite with only RGBA
// images, it will still have a palette, or so I hope =P
// The palette is, fortunately, always 1024 bytes long.
// There are 256 colors, saved in RRGGBBAA structure. 256 * 4 = 1024.
spriteData['PAL'] = SPRBA.position;
var a:int;
var b:int;
var SColor:String;
var IdxColor;
for( var p = 0; p < 256; p++ ) {
paletteData[p.toString( 16 )] = decToCol( SPRBA.readUnsignedByte() << 16 |
SPRBA.readUnsignedByte() << 8 |
SPRBA.readUnsignedByte() );
SPRBA.position += 0x01;
} // End for-loop
/* while( SPRBA.position < SPRBA.length && paletteData.length <= 256 ) {
IdxColor = SPRBA.readUnsignedByte().toString( 16 );
if( b < 256 ) {
if( IdxColor.length < 2 ) IdxColor = "0" + IdxColor;
SColor = SColor + IdxColor + ":";
} // End if
a++;
if( a >= 4 ) {
paletteData[b.toString( 16 )] = SColor.slice( 0, SColor.length - 1 );
SColor = "";
b++;
a = 0;
} // End if
} // End while-loop
*/ trace( "Time: " + (getTimer() - TIME) );
parseAct();
} // End function
private function loadFrames():void {
trace( "Starting Frame Conversion" );
FrameTimer=getTimer();
runTimer.addEventListener( TimerEvent.TIMER, frameLoading );
runTimer.start();
} // End function
private function frameLoading( ev:TimerEvent ):void {
if(useFixedFrames) frameIdx = fixedFrames[0];
if( frameIdx < ( spriteData['num_pal'] + spriteData['num_rgba'] ) ) {
if( !bitmapArray[frameIdx] ) {
var SPRBitmapData:BitmapData = new BitmapData( frameData[frameIdx]['width'], frameData[frameIdx]['height'], true);
var SPRBitmap:Bitmap = new Bitmap( SPRBitmapData );
SPRBA.position = frameData[frameIdx]['offset'];
// Is PAL image (Data Structure: [Palette Index, [Length:Optional]])
// The length is only defined for the first index in the palette, meaning 00
if( frameData[frameIdx]['type'] == 0 ) {
var bgx = 0;
var bgy = 0;
var tmpColor;
var fColor;
var tmpLength;
var trans = "ff";
var cidx = 0;
var pixels:Vector.<uint> = new Vector.<uint>(frameData[frameIdx]['width']*frameData[frameIdx]['height'], true);
//for( var i = 0; i < frameData[frameIdx]['data_len']; i++ ) {
while( SPRBA.position < ( frameData[frameIdx]['offset'] + frameData[frameIdx]['data_len'] ) ) {
tmpColor = SPRBA.readUnsignedByte().toString( 16 );
if( tmpColor == 00 ) {
trans = "00";
tmpLength = SPRBA.readUnsignedByte();
} else {
tmpLength = 1;
trans = "ff";
} // End if
for( var c = 0; c < tmpLength; c++ ) {
// fColor = paletteData[tmpColor].split( ":" );
// fColor = int( "0x" + trans + fColor[0] + fColor[1] + fColor[2] );
fColor = "0x" + trans + paletteData[tmpColor];
//--SPRBitmapData.setPixel32( bgx, bgy, fColor );
pixels[cidx] = fColor;
cidx++;
bgx++;
if( bgx >= frameData[frameIdx]['width'] ) {
bgx = 0;
bgy++;
} // End if
} // End for-loop
} // End while-loop
SPRBitmapData.setVector( SPRBitmapData.rect, pixels );
// Is RGBA image (Data Structure: [AABBGGRR], It also goes from top to bottom unlike the PAL image.)
} else if( frameData[frameIdx]['type'] == 1 ) {
var bgx2 = 0;
var bgy2 = frameData[frameIdx]['height'] - 1;
//var rColor:Array = new Array();
var rColor;
while( SPRBA.position < ( frameData[frameIdx]['offset'] + frameData[frameIdx]['data_len'] ) ) {
rColor = "0x" + toRGB( SPRBA.readUnsignedByte() << 24 |
SPRBA.readUnsignedByte() |
SPRBA.readUnsignedByte() << 8 |
SPRBA.readUnsignedByte() << 16 );
/* rColor = [
SPRBA.readUnsignedByte().toString( 16 ),
SPRBA.readUnsignedByte().toString( 16 ),
SPRBA.readUnsignedByte().toString( 16 ),
SPRBA.readUnsignedByte().toString( 16 )
];
if( rColor[0].length < 2 ) rColor[0] = "0" + rColor[0];
if( rColor[1].length < 2 ) rColor[1] = "0" + rColor[1];
if( rColor[2].length < 2 ) rColor[2] = "0" + rColor[2];
if( rColor[3].length < 2 ) rColor[3] = "0" + rColor[3];
SPRBitmapData.setPixel32( bgx2, bgy2, int( "0x" + rColor[0] + rColor[3] + rColor[2] + rColor[1] ) );
*/
SPRBitmapData.setPixel32( bgx2, bgy2, rColor );
bgx2++;
if( bgx2 >= frameData[frameIdx]['width'] ) {
bgx2 = 0;
bgy2--;
} // End if
} // End while-loop
} // End if
bitmapArray[frameIdx] = SPRBitmap;
} // End if
} else {
if(!useFixedFrames) {
runTimer.stop();
runTimer.removeEventListener( TimerEvent.TIMER, frameLoading );
// parseAct();
parseComplete();
}
} // End if
if(!useFixedFrames) frameIdx++;
else {
fixedFrames.splice(0,0); // Remove first entry that has been loaded
fixedFrames = reOrderArray(fixedFrames); // Makes all entries move one down, so that the first entry is set again
frameIdx = fixedFrames[0];
if(fixedFrames.length <= 0) {
runTimer.stop();
runTimer.removeEventListener( TimerEvent.TIMER, frameLoading );
// parseAct();
parseComplete();
}
} // End if
} // End function
// o=====================================================o
// o=====================================================o
// o== ==o
// o== Act Parsing ==o
// o== ==o
// o=====================================================o
// o=====================================================o
private function parseAct():void {
try {
ACTLoader.dataFormat = URLLoaderDataFormat.BINARY;
var ACTRequest:URLRequest = new URLRequest( fileName + ".act" );
ACTLoader.addEventListener( Event.COMPLETE, actLoaded );
ACTLoader.load( ACTRequest );
ACTRequest = null;
} catch( err:Error ) {
trace( err );
}
} // End function
private function actLoaded( ev:Event ):void {
trace( "Starting Sprite Parsing (ACT)" );
var TIME:Number=getTimer();
ACTLoader.removeEventListener( Event.COMPLETE, actLoaded );
ACTBA = ACTLoader.data;
ACTBA.endian = Endian.LITTLE_ENDIAN;
var anim:int;
var nf:int;
var pat:int;
actData['ident'] = ACTBA.readUTFBytes( 2 );
actData['version'] = ACTBA.readUnsignedShort().toString( 16 );
actData['num_frames'] = ACTBA.readUnsignedShort();
actData['num_actions'] = Math.floor( actData['num_frames'] / 8 );
ACTBA.position += 0xA; // Those are useless/unused/unknown bytes that we skip
// Loop through the actions
for( anim = 0; anim < actData['num_frames']; anim++ ) {
actData[anim] = new Array();
actData[anim]['num_frames'] = ACTBA.readInt();
// Loop through the actions frames
for( nf = 0; nf < actData[anim]['num_frames']; nf++ ) {
ACTBA.position += 0x20; // Skipped bytes again
actData[anim][nf] = new Array();
actData[anim][nf]['num_subframes'] = ACTBA.readInt();
// Loop through the frames patterns
for( pat = 0; pat < actData[anim][nf]['num_subframes']; pat++ ) {
actData[anim][nf][pat] = new Array();
actData[anim][nf][pat] = {
xOffset: ACTBA.readInt(),
yOffset: ACTBA.readInt(),
sprNo: ACTBA.readInt(),
mirror: ACTBA.readInt(),
red: ACTBA.readUnsignedByte(),
green: ACTBA.readUnsignedByte(),
blue: ACTBA.readUnsignedByte(),
alpha: ACTBA.readUnsignedByte(),
offset: ACTBA.position
};
// There are differences depending on the version
if( actData['version'] >= 200 && actData['version'] <= 203 ) actData[anim][nf][pat]['xyScale'] = ACTBA.readFloat();
if( actData['version'] >= 204 ) {
actData[anim][nf][pat]['xScale'] = ACTBA.readFloat();
actData[anim][nf][pat]['yScale'] = ACTBA.readFloat();
} // End if
actData[anim][nf][pat]['rotation'] = ACTBA.readInt();
actData[anim][nf][pat]['sprType'] = ACTBA.readInt();
if( actData['version'] >= 205 ) {
actData[anim][nf][pat]['sprWidth'] = ACTBA.readInt();
actData[anim][nf][pat]['sprHeight'] = ACTBA.readInt();
} // End if
} // End for-loop
// After the patterns follows the sounds, those are pointers to the sounddata at the end of the actfile.
actData[anim][nf]['soundNo'] = ACTBA.readInt();
var extrainfo = ACTBA.readInt(); // if this is actually 1 in an act, it will give us the info for reference (eg. head/body/headgear)
if( extrainfo == 1 ) {
ACTBA.position += 0x04;
actData[anim][nf]['refX'] = ACTBA.readInt();
actData[anim][nf]['refY'] = ACTBA.readInt();
ACTBA.position += 0x04;
} // End if
} // End for-loop
} // End for-loop
// At the end of the act file we find the sound and interval list
// the sounds are frames specific
soundData['num_sounds'] = ACTBA.readInt();
if( soundData['num_sounds'] > 0 ) {
for( var sn = 0; sn < soundData['num_sounds']; sn++ ) {
soundData[sn] = ACTBA.readUTFBytes(40);
} // End for-loop
} // End if
// the intervals are actions specific
for( var intv = 0; intv < actData['num_frames']; intv++ ) {
actData[intv]['interval'] = ACTBA.readFloat();
} // End if
trace( "Time: " + (getTimer() - TIME) );
// parseComplete();
if(useFixedFrames) displayFirstFrame();
else loadFrames();
} // End function
// Clean up to reduce memory usage?
private function parseComplete():void {
SPRLoader.close();
ACTLoader.close();
SPRLoader = null;
ACTLoader = null;
SPRBA = null;
ACTBA = null;
runTimer = null;
mcCapture.graphics.beginFill(0xFFFFFF,0.15);
mcCapture.graphics.drawRect( -1, -1, mcCapture.width+1, mcCapture.height+1 );
mcCapture.graphics.endFill();
trace( "Time: " + (getTimer() - FrameTimer) );
finished = true;
if( hasParent ) parentSpr.partFinish();
else partFinish();
/*if( useFixedFrames ) displayAction(0, 0);
if( useCallback ) callback(this);*/
} // End function
// o=====================================================o
// o=====================================================o
// o== ==o
// o== Functions ==o
// o== ==o
// o=====================================================o
// o=====================================================o
// Eh ya, put our info from the actData together and display it on stage I guess...
// We loop through each pattern of the specific frame and do some magic to it and then display it.
public function displayAction( action:int = 0, frame:int = 0 ):void {
if( hasChilds ) {
for( var i = 0; i < childArray.length; i++ ) {
childArray[i].displayAction( action, frame );
} // End for-loop
}
try {
if( !finished ) throw new Error( "Cannot display action when sprite is not fully parsed" );
if( action != curAct ) {
xDimMin = null;
xDimMax = null;
yDimMin = null;
yDimMax = null;
} // End if
curAct = action;
curFrame = frame;
var numPattern:int = actData[action][frame]['num_subframes'];
while ( mcFrame.numChildren > 0 ) {
delete( mcFrame.getChildAt( 0 ) );
mcFrame.removeChildAt( 0 );
} // End while-loop
if( !animCache[curAct] ) animCache[curAct] = new Array();
for( var pat = 0; pat < numPattern; pat++ ) {
var patData = actData[action][frame][pat];
if( patData['sprNo'] >= 0 ) {
var frameNumPadding = ( patData['sprType'] == 1 ) ? spriteData['num_pal'] : 0;
var tempBitmapData:BitmapData = bitmapArray[patData['sprNo'] + frameNumPadding].bitmapData.clone();
var tempBitmap:Bitmap = new Bitmap( tempBitmapData );
var patLayer:MovieClip = new MovieClip();
patLayer.ID = pat;
patLayer.addChild( tempBitmap );
mcFrame.addChild( patLayer );
var Alpha:Number = patData['alpha'] / 255;
var Red:Number = patData['red'] / 255;
var Green:Number = patData['green'] / 255;
var Blue:Number = patData['blue'] / 255;
var cTrans:ColorTransform = patLayer.transform.colorTransform;
cTrans.alphaMultiplier = Alpha;
cTrans.redMultiplier = Red;
cTrans.greenMultiplier = Green;
cTrans.blueMultiplier = Blue;
patLayer.transform.colorTransform = cTrans;
var Mirror = 1;
if( patData['mirror'] == 1 ) Mirror = -1;
var xScale = 1;
var yScale = 1;
if( actData['version'] >= 200 && actData['version'] <= 203 ) {
xScale = patData['xyScale'];
yScale = patData['xyScale'];
} else {
xScale = patData['xScale'];
yScale = patData['yScale'];
} // End if
patLayer.scaleX *= xScale * Mirror;
patLayer.scaleY *= yScale;
if( hasParent ) {
var newOffsetX = null;
var newOffsetY = null;
// if( !isEquipment ) {
var refOffset:Array = parentSpr.getRefOffset( curAct, curFrame );
newOffsetX = patData['xOffset'] + refOffset[0] - actData[curAct][curFrame]['refX'];
newOffsetY = patData['yOffset'] + refOffset[1] - actData[curAct][curFrame]['refY'];
// } else {
// newOffsetX = patData['xOffset'] - actData[curAct][curFrame]['refX'];
// newOffsetY = patData['yOffset'] - actData[curAct][curFrame]['refY'];
// } // End if
patLayer.x = Math.floor( ( startPoint.x - patLayer.width / 2 * Mirror ) ) + Math.floor( newOffsetX );
patLayer.y = Math.floor( ( startPoint.y - patLayer.height / 2 ) ) + Math.floor( newOffsetY );
} else {
patLayer.x = Math.floor( ( startPoint.x - patLayer.width / 2 * Mirror ) ) + Math.floor( patData['xOffset'] );
patLayer.y = Math.floor( ( startPoint.y - patLayer.height / 2 ) ) + Math.floor( patData['yOffset'] );
} // End if
if( Math.round( patData['rotation'] ) != 0 ) {
var ptRotationPoint:Point = new Point( Math.floor( patLayer.x + patLayer.width / 2 * Mirror ), Math.floor( patLayer.y + patLayer.height / 2 ) );
rotateAroundCenter( patLayer, patData['rotation'], ptRotationPoint);
} // End if
} else {
mcFrame.addChild( new MovieClip() ); // useless
} // End if
} // End for-loop
if( count( animCache[curAct] ) < actData[curAct]['num_frames'] ) {
if( mcFrame.numChildren > 0 ) {
if( xDimMin == null ) xDimMin = mcFrame.getBounds( mcFrame ).x;
if( xDimMax == null ) xDimMax = mcFrame.getBounds( mcFrame ).x + mcFrame.width;
if( yDimMin == null ) yDimMin = mcFrame.getBounds( mcFrame ).y;
if( yDimMax == null ) yDimMax = mcFrame.getBounds( mcFrame ).y + mcFrame.height;
if( xDimMin > mcFrame.getBounds( mcFrame ).x ) xDimMin = mcFrame.getBounds( mcFrame ).x;
if( xDimMax < mcFrame.getBounds( mcFrame ).x + mcFrame.width ) xDimMax = mcFrame.getBounds( mcFrame ).x + mcFrame.width;
if( yDimMin > mcFrame.getBounds( mcFrame ).y ) yDimMin = mcFrame.getBounds( mcFrame ).y;
if( yDimMax < mcFrame.getBounds( mcFrame ).y + mcFrame.height ) yDimMax = mcFrame.getBounds( mcFrame ).y + mcFrame.height;
} // End if
animCache[curAct][curFrame] = 1;
} else {
if( !dimArray[curAct] ) dimArray[curAct] = new Matrix( xDimMin, yDimMin, ( xDimMax - xDimMin ), ( yDimMax - yDimMin ) );
mcCapture.width = dimArray[curAct].c;
mcCapture.height = dimArray[curAct].d;
mcCapture.x = dimArray[curAct].a + mcCapture.width;
mcCapture.y = dimArray[curAct].b + mcCapture.height;
} // End if
// var tmpMatrix:Matrix = new Matrix();
// tmpMatrix.translate( -mcFrame.getBounds(mcFrame).x, -mcFrame.getBounds(mcFrame).y );
// var cacheBitmapData:BitmapData = new BitmapData( mcFrame.width, mcFrame.height, true, 0x00000000 );
// var cacheBitmap:Bitmap = new Bitmap( cacheBitmapData );
// cacheBitmapData.draw( mcFrame, tmpMatrix );
// animCache[curAct][curFrame] = cacheBitmap;
// } // End if
} catch( err:Error ) {
trace( err );
}
} // End function
private function rotateAroundCenter( ob:*, angleDegrees:Number, ptRotationPoint:Point ):void {
var m:Matrix = ob.transform.matrix;
m.tx -= ptRotationPoint.x;
m.ty -= ptRotationPoint.y;
m.rotate( angleDegrees * ( Math.PI / 180 ) );
m.tx += ptRotationPoint.x;
m.ty += ptRotationPoint.y;
ob.transform.matrix = m;
}
private function startAnimation( ev:TimerEvent ):void {
curFrame++;
if( curFrame >= actData[curAct]['num_frames'] ) curFrame = 0;
gotoFrame( curFrame );
if( hasChilds ) {
for( var i = 0; i < childArray.length; i++ ) {
childArray[i].gotoFrame( curFrame );
} // End for-loop
} // End if
} // End function
private function decToCol( dec:uint ):String {
var red, green, blue;
blue = ( dec & 255 ).toString( 16 );
green = ( ( dec & 65280 ) / 256 ).toString( 16 );
red = ( ( dec & 16711680) / 65536 ).toString( 16 );
red = ( red.length < 2 ) ? "0" + red : red;
green = ( green.length < 2 ) ? "0" + green : green;
blue = ( blue.length < 2 ) ? "0" + blue : blue;
return ( red + green + blue );
} // End function
private function toRGB( dec:uint ):String {
return dec.toString( 16 );
} // End function
private function count( arr:Array ):int {
var count:int = 0;
for( var i = 0; i < arr.length; i++ ) {
if( arr[i] != null ) count++;
}
return count;
} // End function
private function getRefOffset( action:int, frame:int ):Array {
return new Array( actData[action][frame]['refX'], actData[action][frame]['refY'] );
} // End function
private function setChild( sprite:SpriteParser ):void {
hasChilds = true;
childArray.push( sprite );
} // End function
private function reOrderArray( arr:Array ):Array {
var newArr:Array = new Array();
for( var i=0; i<arr.length; i++ ) {
if( (i+1) <= arr.length && arr[i+1] != null) {
newArr[i] = arr[i+1];
}
} // End for-loop
return newArr;
} // End function
private function displayFirstFrame():void {
fixedFrames = new Array();
// Get required frames from patterns
var PatCount = actData[0][0]['num_subframes'];
for( var i = 0; i < PatCount; i++ ) {
//trace("Pat: "+i+" SprNo: "+actData[0][0][i]['sprNo']);
if(actData[0][0][i]['type'] == 1) fixedFrames.push(actData[0][0][i]['sprNo']+spriteData['num_pal']);
else fixedFrames.push(actData[0][0][i]['sprNo']);
} // End for-loop
loadFrames();
} // End function
public function partFinish():void {
partialFinish++;
if( hasChilds || hasParent ) {
if( partialFinish >= ( count( childArray ) + 1 ) ) {
mcFrame.visible = true;
if( useFixedFrames ) displayAction(0, 0);
if( useCallback ) callback(this);
} // End if
} else {
mcFrame.visible = true;
if( useFixedFrames ) displayAction(0, 0);
if( useCallback ) callback(this);
} // End if
} // End function
// o=====================================================o
// o=====================================================o
// o== ==o
// o== Public Functions ==o
// o== ==o
// o=====================================================o
// o=====================================================o
public function isLoaded( func:Function ):void {
useCallback = true;
callback = func;
} // End function
public function setPosition( xPos:int, yPos:int ):void {
startPoint.x = xPos;
startPoint.y = yPos;
if( mcFrame.numChildren > 0 && finished ) {
for( var pat = 0; pat < mcFrame.numChildren; pat++ ) {
var patLayer = mcFrame.getChildAt( pat );
var patData = actData[curAct][curFrame][patLayer.ID];
var Mirror = 1;
if( patData['mirror'] == 1 ) Mirror = -1;
patLayer.x = Math.floor( ( startPoint.x - patLayer.width / 2 * Mirror ) ) + Math.floor( patData['xOffset'] );
patLayer.y = Math.floor( ( startPoint.y - patLayer.height / 2 ) ) + Math.floor( patData['yOffset'] );
} // End for-loop
} // End if
} // End function
public function setFrame( mc:MovieClip ):void {
mcFrame = mc;
} // End function
public function gotoFrame( frame:int = 0 ):void {
if( frame >= 0 && frame < actData[curAct]['num_frames'] ) {
displayAction( curAct, frame );
} // End if
} // End function
public function nextFrame():void {
if( ( curFrame + 1 ) < actData[curAct]['num_frames'] ) displayAction( curAct, ( curFrame + 1 ) );
else displayAction( curAct, 0 );
} // End function
public function prevFrame():void {
if( ( curFrame - 1 ) >= 0 ) displayAction( curAct, ( curFrame - 1 ) );
else displayAction( curAct, ( actData[curAct]['num_frames'] - 1 ) );
} // End function
public function playStopAnimation():void {
if( !hasParent ) {
if( !playTimer.running ) {
playTimer.stop();
playTimer.delay = 22 * actData[curAct]['interval'];
playTimer.addEventListener( TimerEvent.TIMER, startAnimation );
playTimer.start();
} else {
playTimer.stop();
} // End if
} // End if
} // End function
public function nextAct():void {
if( ( curAct + 1 ) < actData['num_frames'] ) displayAction( ( curAct + 1 ), 0 );
else displayAction( 0, 0 );
} // End function
public function prevAct():void {
if( ( curAct - 1 ) >= 0 ) displayAction( ( curAct - 1 ), 0 );
else displayAction( ( actData['num_frames'] - 1 ), 0 )
} // End function
public function generatePalette():Bitmap {
try {
if( !finished ) throw new Error("Cannot generate palette when sprite is not fully parsed");
var paletteBitmapData:BitmapData = new BitmapData( 256, 256, false, 0xffffff );
var paletteBitmap:Bitmap = new Bitmap( paletteBitmapData );
var pColor = 0;
var X=0;
var Y=0;
for( var i = 0; i < 256; i++ ) {
pColor = "0x" + paletteData[i.toString( 16 )];
paletteBitmapData.fillRect( new Rectangle( X * 16, Y * 16, 16, 16 ), pColor );
X++;
if( X >= 16 ) {
X = 0;
Y++;
}
}
} catch( err:Error ) {
trace( err );
}
return paletteBitmap;
} // End function
public function setParent( sprite:SpriteParser ):void {
hasParent = true;
parentSpr = sprite;
sprite.setChild( this );
} // End function
public function getCurFrame():int {
return curFrame;
} // End function
public function getFrameCount():int {
return actData[curAct]['num_frames'];
} // End function
public function getCurAct():int {
return curAct;
} // End function
public function getActCount():int {
return actData['num_frames'];
} // End function
} // End class
} // End package