How to use Thing method in chai

Best JavaScript code snippet using chai

FullScreenMario.js

Source:FullScreenMario.js Github

copy

Full Screen

...170            FSM.GroupHolder.clearArrays();171            FSM.ItemsHolder.hideContainer();172            FSM.TimeHandler.cancelAllEvents();173            FSM.PixelDrawer.setBackground("black");174            FSM.addThing(text, FSM.MapScreener.width / 2, FSM.MapScreener.height / 2);175            texts = text.children;176            textWidth = -(texts[texts.length - 1].right - texts[0].left) / 2;177            for (i = 0; i < texts.length; i += 1) {178                FSM.shiftHoriz(texts[i], textWidth);179            }180            FSM.TimeHandler.addEvent(function () {181                FSM.gameStart();182                FSM.ItemsHolder.displayContainer();183            }, 420);184            FSM.ModAttacher.fireEvent("onGameOver");185        };186        /**187         * Slight addition to the GameStartr thingProcess Function. The Thing's hit188         * check type is cached immediately.189         *190         * @param thing   The Thing being processed.191         * @param title   What type Thing this is (the name of the class).192         * @param settings   Additional settings to be given to the Thing.193         * @param defaults   The default settings for the Thing's class.194         * @remarks This is generally called as the onMake call in an ObjectMakr.195         */196        FullScreenMario.prototype.thingProcess = function (thing, title, settings, defaults) {197            // Infinite height refers to objects that reach exactly to the bottom198            if (thing.height === "Infinity" || thing.height === Infinity) {199                thing.height = thing.FSM.getAbsoluteHeight(thing.y) / thing.FSM.unitsize;200            }201            _super.prototype.thingProcess.call(this, thing, title, settings, defaults);202            thing.FSM.ThingHitter.cacheChecksForType(thing.title, thing.groupType);203        };204        /**205         * Generates a key for a Thing based off the current area and the Thing's206         * basic attributes. This should be used for PixelRender.get calls, to207         * cache the Thing's sprite.208         *209         * @param thing210         * @returns A key that to identify the Thing's sprite.211         */212        FullScreenMario.prototype.generateThingKey = function (thing) {213            return thing.GameStarter.AreaSpawner.getArea().setting214                + " " + thing.groupType + " "215                + thing.title + " " + thing.className;216        };217        /**218         * Adds a Thing via addPreThing based on the specifications in a PreThing.219         * This is done relative to MapScreener.left and MapScreener.floor.220         *221         * @param prething   A PreThing whose Thing is to be added to the game.222         */223        FullScreenMario.prototype.addPreThing = function (prething) {224            var thing = prething.thing, position = prething.position || thing.position;225            thing.FSM.addThing(thing, prething.left * thing.FSM.unitsize - thing.FSM.MapScreener.left, (thing.FSM.MapScreener.floor - prething.top) * thing.FSM.unitsize);226            // Either the prething or thing, in that order, may request to be in the227            // front or back of its container using the "position" attribute228            if (position) {229                thing.FSM.TimeHandler.addEvent(function () {230                    switch (position) {231                        case "beginning":232                            thing.FSM.arrayToBeginning(thing, thing.FSM.GroupHolder.getGroup(thing.groupType));233                            break;234                        case "end":235                            thing.FSM.arrayToEnd(thing, thing.FSM.GroupHolder.getGroup(thing.groupType));236                            break;237                        default:238                            break;239                    }240                });241            }242            thing.FSM.ModAttacher.fireEvent("onAddPreThing", prething);243        };244        /**245         * Adds a new Player Thing to the game and sets it as EightBitter.play. Any246         * required additional settings (namely keys, power/size, and swimming) are247         * applied here.248         *249         * @param left   A left edge to place the Thing at (by default, unitsize * 16).250         * @param bottom   A bottom to place the Thing upon (by default, unitsize * 16).251         * @returns A newly created Player in the game.252         */253        FullScreenMario.prototype.addPlayer = function (left, bottom) {254            if (left === void 0) { left = this.unitsize * 16; }255            if (bottom === void 0) { bottom = this.unitsize * 16; }256            var FSM = FullScreenMario.prototype.ensureCorrectCaller(this), player;257            player = FSM.player = FSM.ObjectMaker.make("Player", {258                "power": FSM.ItemsHolder.getItem("power")259            });260            player.keys = player.getKeys();261            if (FSM.MapScreener.underwater) {262                player.swimming = true;263                FSM.TimeHandler.addClassCycle(player, [264                    "swim1", "swim2"265                ], "swimming", 5);266                FSM.TimeHandler.addEventInterval(player.FSM.animatePlayerBubbling, 96, Infinity, player);267            }268            FSM.setPlayerSizeSmall(player);269            if (player.power >= 2) {270                FSM.playerGetsBig(player, true);271                if (player.power === 3) {272                    FSM.playerGetsFire(player);273                }274            }275            FSM.addThing(player, left, bottom - player.height * FSM.unitsize);276            FSM.ModAttacher.fireEvent("onAddPlayer", player);277            return player;278        };279        /**280         * Shortcut to call scrollThing on a Player.281         *282         * @param dx   How far to scroll horizontally.283         * @param dy   How far to scroll vertically.284         */285        FullScreenMario.prototype.scrollPlayer = function (dx, dy) {286            var FSM = FullScreenMario.prototype.ensureCorrectCaller(this);287            FSM.scrollThing(FSM.player, dx, dy);288            FSM.ModAttacher.fireEvent("onScrollPlayer", dx, dy);289        };290        /**291         * Triggered Function for when the game is paused. Music stops, the pause292         * bleep is played, and the mod event is fired.293         *294         * @param FSM295         */296        FullScreenMario.prototype.onGamePause = function (FSM) {297            FSM.AudioPlayer.pauseAll();298            FSM.AudioPlayer.play("Pause");299            FSM.ModAttacher.fireEvent("onGamePause");300        };301        /**302         * Triggered Function for when the game is played or unpause. Music resumes303         * and the mod event is fired.304         *305         * @param FSM306         */307        FullScreenMario.prototype.onGamePlay = function (FSM) {308            FSM.AudioPlayer.resumeAll();309            FSM.ModAttacher.fireEvent("onGamePlay");310        };311        /* Input312        */313        /**314         * Reacts to the left key being pressed. keys.run and leftDown are marked315         * and the mod event is fired.316         *317         * @param FSM318         * @param event   The original user-caused Event.319         */320        FullScreenMario.prototype.keyDownLeft = function (FSM, event) {321            if (FSM.GamesRunner.getPaused()) {322                return;323            }324            var player = FSM.player;325            player.keys.run = -1;326            player.keys.leftDown = true; // independent of changes to keys.run327            player.FSM.ModAttacher.fireEvent("onKeyDownLeft");328        };329        /**330         * Reacts to the right key being pressed. keys.run and keys.rightDown are331         * marked and the mod event is fired.332         *333         * @param FSM334         * @param event   The original user-caused Event.335         */336        FullScreenMario.prototype.keyDownRight = function (FSM, event) {337            if (FSM.GamesRunner.getPaused()) {338                return;339            }340            var player = FSM.player;341            player.keys.run = 1;342            player.keys.rightDown = true; // independent of changes to keys.run343            player.FSM.ModAttacher.fireEvent("onKeyDownRight");344            if (event && event.preventDefault !== undefined) {345                event.preventDefault();346            }347        };348        /**349         * Reacts to the up key being pressed. If a Player can jump, it does, and350         * underwater paddling is checked. The mod event is fired.351         *352         * @param FSM353         * @param event   The original user-caused Event.354         */355        FullScreenMario.prototype.keyDownUp = function (FSM, event) {356            if (FSM.GamesRunner.getPaused()) {357                return;358            }359            var player = FSM.player;360            player.keys.up = true;361            if (player.canjump && (player.resting || FSM.MapScreener.underwater)) {362                player.keys.jump = true;363                player.canjump = false;364                player.keys.jumplev = 0;365                if (player.power > 1) {366                    FSM.AudioPlayer.play("Jump Super");367                }368                else {369                    FSM.AudioPlayer.play("Jump Small");370                }371                if (FSM.MapScreener.underwater) {372                    FSM.TimeHandler.addEvent(function () {373                        player.jumping = player.keys.jump = false;374                    }, 14);375                }376            }377            FSM.ModAttacher.fireEvent("onKeyDownUp");378            if (event && event.preventDefault !== undefined) {379                event.preventDefault();380            }381        };382        /**383         * Reacts to the down key being pressed. A player's keys.crouch is marked384         * and the mod event is fired.385         *386         * @param FSM387         * @param event   The original user-caused Event.388         */389        FullScreenMario.prototype.keyDownDown = function (FSM, event) {390            if (FSM.GamesRunner.getPaused()) {391                return;392            }393            var player = FSM.player;394            player.keys.crouch = true;395            FSM.ModAttacher.fireEvent("onKeyDownDown");396            if (event && event.preventDefault !== undefined) {397                event.preventDefault();398            }399        };400        /**401         * Reacts to the sprint key being pressed. Firing happens if a Player is402         * able, keys.spring is marked, and the mod event is fired.403         *404         * @param FSM405         * @param event   The original user-caused Event.406         */407        FullScreenMario.prototype.keyDownSprint = function (FSM, event) {408            if (FSM.GamesRunner.getPaused()) {409                return;410            }411            var player = FSM.player;412            if (player.power === 3 && player.keys.sprint === false && !player.crouching) {413                player.fire(player);414            }415            player.keys.sprint = true;416            player.FSM.ModAttacher.fireEvent("onKeyDownSprint");417            if (event && event.preventDefault !== undefined) {418                event.preventDefault();419            }420        };421        /**422         * Reacts to the pause key being pressed. The game is either paused or unpaused,423         * and the mod event is fired.424         *425         * @param FSM426         * @param event   The original user-caused Event.427         */428        FullScreenMario.prototype.keyDownPause = function (FSM, event) {429            if (FSM.GamesRunner.getPaused()) {430                FSM.GamesRunner.play();431            }432            else {433                FSM.GamesRunner.pause();434            }435            FSM.ModAttacher.fireEvent("onKeyDownPause");436            if (event && event.preventDefault !== undefined) {437                event.preventDefault();438            }439        };440        /**441         * Reacts to the mute key being lifted. Muting is toggled and the mod event442         * is fired.443         *444         * @param FSM445         * @param event   The original user-caused Event.446         */447        FullScreenMario.prototype.keyDownMute = function (FSM, event) {448            if (FSM.GamesRunner.getPaused()) {449                return;450            }451            FSM.AudioPlayer.toggleMuted();452            FSM.ModAttacher.fireEvent("onKeyDownMute");453            if (event && event.preventDefault !== undefined) {454                event.preventDefault();455            }456        };457        /**458         * Reacts to the left key being lifted. keys.run and keys.leftDown are459         * marked and the mod event is fired.460         *461         * @param FSM462         * @param event   The original user-caused Event.463         */464        FullScreenMario.prototype.keyUpLeft = function (FSM, event) {465            var player = FSM.player;466            player.keys.run = 0;467            player.keys.leftDown = false;468            FSM.ModAttacher.fireEvent("onKeyUpLeft");469            if (event && event.preventDefault !== undefined) {470                event.preventDefault();471            }472        };473        /**474         * Reacts to the right key being lifted. keys.run and keys.rightDown are475         * marked and the mod event is fired.476         *477         * @param FSM478         * @param event   The original user-caused Event.479         */480        FullScreenMario.prototype.keyUpRight = function (FSM, event) {481            var player = FSM.player;482            player.keys.run = 0;483            player.keys.rightDown = false;484            FSM.ModAttacher.fireEvent("onKeyUpRight");485            if (event && event.preventDefault !== undefined) {486                event.preventDefault();487            }488        };489        /**490         * Reacts to the up key being lifted. Jumping stops and the mod event is491         * fired.492         *493         * @param FSM494         * @param event   The original user-caused Event.495         */496        FullScreenMario.prototype.keyUpUp = function (FSM, event) {497            var player = FSM.player;498            if (!FSM.MapScreener.underwater) {499                player.keys.jump = player.keys.up = false;500            }501            player.canjump = true;502            FSM.ModAttacher.fireEvent("onKeyUpUp");503            if (event && event.preventDefault !== undefined) {504                event.preventDefault();505            }506        };507        /**508         * Reacts to the down key being lifted. keys.crouch is marked, crouch509         * removal happens if necessary, and the mod event is fired.510         *511         * @param FSM512         * @param event   The original user-caused Event.513         */514        FullScreenMario.prototype.keyUpDown = function (FSM, event) {515            var player = FSM.player;516            player.keys.crouch = false;517            if (!player.piping) {518                FSM.animatePlayerRemoveCrouch(player);519            }520            FSM.ModAttacher.fireEvent("onKeyUpDown");521            if (event && event.preventDefault !== undefined) {522                event.preventDefault();523            }524        };525        /**526         * Reacts to the spring key being lifted. keys.sprint is marked and the mod527         * event is fired.528         *529         * @param FSM530         * @param event   The original user-caused Event.531         */532        FullScreenMario.prototype.keyUpSprint = function (FSM, event) {533            var player = FSM.player;534            player.keys.sprint = false;535            FSM.ModAttacher.fireEvent("onKeyUpSprint");536            if (event && event.preventDefault !== undefined) {537                event.preventDefault();538            }539        };540        /**541         * Reacts to the pause key being lifted. The mod event is fired.542         *543         * @param FSM544         * @param event   The original user-caused Event.545         */546        FullScreenMario.prototype.keyUpPause = function (FSM, event) {547            FSM.ModAttacher.fireEvent("onKeyUpPause");548            if (event && event.preventDefault !== undefined) {549                event.preventDefault();550            }551        };552        /**553         * Reacts to a right click being pressed. Pausing is toggled and the mod554         * event is fired.555         *556         * @param FSM557         * @param event   The original user-caused Event.558         */559        FullScreenMario.prototype.mouseDownRight = function (FSM, event) {560            FSM.GamesRunner.togglePause();561            FSM.ModAttacher.fireEvent("onMouseDownRight");562            if (event && event.preventDefault !== undefined) {563                event.preventDefault();564            }565        };566        /**567         * Reacts to a regularly caused device motion event. Acceleration is checked568         * for changed tilt horizontally (to trigger left or right key statuses) or569         * changed tilt vertically (jumping). The mod event is also fired.570         *571         * @param FSM572         * @param event   The original user-caused Event.573         */574        FullScreenMario.prototype.deviceMotion = function (FSM, event) {575            var player = FSM.player, deviceMotionStatus = FSM.deviceMotionStatus, acceleration = event.accelerationIncludingGravity;576            FSM.ModAttacher.fireEvent("onDeviceMotion", event);577            if (deviceMotionStatus.y !== undefined) {578                deviceMotionStatus.dy = acceleration.y - deviceMotionStatus.y;579                if (deviceMotionStatus.dy > 0.21) {580                    FSM.keyDownUp(FSM);581                }582                else if (deviceMotionStatus.dy < -0.14) {583                    FSM.keyUpUp(FSM);584                }585            }586            deviceMotionStatus.x = acceleration.x;587            deviceMotionStatus.y = acceleration.y;588            if (deviceMotionStatus.x > 2.1) {589                if (!deviceMotionStatus.motionLeft) {590                    player.FSM.keyDownLeft(FSM);591                    deviceMotionStatus.motionLeft = true;592                }593            }594            else if (deviceMotionStatus.x < -2.1) {595                if (!deviceMotionStatus.motionRight) {596                    player.FSM.keyDownRight(FSM);597                    deviceMotionStatus.motionRight = true;598                }599            }600            else {601                if (deviceMotionStatus.motionLeft) {602                    player.FSM.keyUpLeft(FSM);603                    deviceMotionStatus.motionLeft = false;604                }605                if (deviceMotionStatus.motionRight) {606                    player.FSM.keyUpRight(FSM);607                    deviceMotionStatus.motionRight = false;608                }609            }610        };611        /**612         * Checks whether inputs can be fired, which is equivalent to the status of613         * the MapScreener's nokeys variable (an inverse value).614         *615         * @param FSM616         * @returns Whether inputs are allowed to trigger.617         */618        FullScreenMario.prototype.canInputsTrigger = function (FSM) {619            return !FSM.MapScreener.nokeys;620        };621        /* Upkeep maintenence622        */623        /**624         * Regular maintenance Function called to decrease time every 25 game ticks.625         *626         * @param FSM627         * @returns Whether time should stop counting, which is whether it's <= 0.628         */629        FullScreenMario.prototype.maintainTime = function (FSM) {630            if (!FSM.MapScreener.notime) {631                FSM.ItemsHolder.decrease("time", 1);632                return false;633            }634            if (!FSM.ItemsHolder.getItem("time")) {635                return true;636            }637            return false;638        };639        /**640         * Regular maintenance Function called on the Scenery group every 350641         * upkeeps (slightly over 5 seconds). Things are checked for being alive642         * and to the left of QuadsKeeper.left; if they aren't, they are removed.643         *644         * @param FSM645         */646        FullScreenMario.prototype.maintainScenery = function (FSM) {647            var things = FSM.GroupHolder.getGroup("Scenery"), delx = FSM.QuadsKeeper.left, thing, i;648            for (i = 0; i < things.length; i += 1) {649                thing = things[i];650                if (thing.right < delx && thing.outerok !== 2) {651                    FSM.arrayDeleteThing(thing, things, i);652                    i -= 1;653                }654            }655        };656        /**657         * Regular maintenance Function called on the Solids group every upkeep.658         * Things are checked for being alive and to the right of QuadsKeeper.left;659         * if they aren't, they are removed. Each Thing is also allowed a movement660         * Function.661         *662         * @param FSM663         * @param solids   FSM's GroupHolder's Solid group.664         */665        FullScreenMario.prototype.maintainSolids = function (FSM, solids) {666            var delx = FSM.QuadsKeeper.left, solid, i;667            FSM.QuadsKeeper.determineAllQuadrants("Solid", solids);668            for (i = 0; i < solids.length; i += 1) {669                solid = solids[i];670                if (solid.alive && solid.right > delx) {671                    if (solid.movement) {672                        solid.movement(solid);673                    }674                }675                else if (!solid.alive || solid.outerok !== 2) {676                    FSM.arrayDeleteThing(solid, solids, i);677                    i -= 1;678                }679            }680        };681        /**682         * Regular maintenance Function called on the Characters group every upkeep.683         * Things have gravity and y-velocities, collision detection, and resting684         * checks applied before they're checked for being alive. If they are, they685         * are allowed a movement Function; if not, they are removed.686         *687         * @param FSM688         * @param characters   FSM's GroupHolder's Characters group.689         */690        FullScreenMario.prototype.maintainCharacters = function (FSM, characters) {691            var delx = FSM.QuadsKeeper.right, character, i;692            for (i = 0; i < characters.length; i += 1) {693                character = characters[i];694                // Gravity695                if (character.resting) {696                    character.yvel = 0;697                }698                else {699                    if (!character.nofall) {700                        character.yvel += character.gravity || FSM.MapScreener.gravity;701                    }702                    character.yvel = Math.min(character.yvel, FSM.MapScreener.maxyvel);703                }704                // Position updating and collision detection705                character.under = character.undermid = undefined;706                FSM.updatePosition(character);707                FSM.QuadsKeeper.determineThingQuadrants(character);708                FSM.ThingHitter.checkHitsForThing(character);709                // Overlaps710                if (character.overlaps && character.overlaps.length) {711                    FSM.maintainOverlaps(character);712                }713                // Resting tests714                if (character.resting) {715                    if (!FSM.isCharacterOnResting(character, character.resting)) {716                        if (character.onRestingOff) {717                            character.onRestingOff(character, character.resting);718                        }719                        else {720                            // Necessary for moving platforms721                            character.resting = undefined;722                        }723                    }724                    else {725                        character.yvel = 0;726                        FSM.setBottom(character, character.resting.top);727                    }728                }729                // Movement or deletion730                // To do: rethink this...731                if (character.alive) {732                    if (!character.player &&733                        (character.numquads === 0 || character.left > delx) &&734                        (!character.outerok || (character.outerok !== 2735                            && character.right < FSM.MapScreener.width - delx))) {736                        FSM.arrayDeleteThing(character, characters, i);737                        i -= 1;738                    }739                    else {740                        if (!character.nomove && character.movement) {741                            character.movement(character);742                        }743                    }744                }745                else {746                    FSM.arrayDeleteThing(character, characters, i);747                    i -= 1;748                }749            }750        };751        /**752         * Maintenance Function only triggered for Things that are known to have753         * overlapping Solids stored in their overlaps attribute. This will slide754         * the offending Thing away from the midpoint of those overlaps once a call755         * until it's past the boundary (and check for those boundaries if not756         * already set).757         *758         * @param character   A Character that is known to be overlapping Solid(s).759         */760        FullScreenMario.prototype.maintainOverlaps = function (character) {761            // If checkOverlaps is still true, this is the first maintain call762            if (character.checkOverlaps) {763                if (!character.FSM.setOverlapBoundaries(character)) {764                    return;765                }766            }767            character.FSM.slideToX(character, character.overlapGoal, character.FSM.unitsize);768            // Goal to the right: has the thing gone far enough to the right?769            if (character.overlapGoRight) {770                if (character.left >= character.overlapCheck) {771                    character.FSM.setLeft(character, character.overlapCheck);772                }773                else {774                    return;775                }776            }777            else {778                // Goal to the left: has the thing gone far enough to the left?779                if (character.right <= character.overlapCheck) {780                    character.FSM.setRight(character, character.overlapCheck);781                }782                else {783                    return;784                }785            }786            // A check above didn't fail into a return, so overlapping is solved787            character.overlaps.length = 0;788            character.checkOverlaps = true;789        };790        /**791         * Sets the overlapping properties of a Thing when it is first detected as792         * overlapping in maintainOverlaps. All Solids in its overlaps Array are793         * checked to find the leftmost and rightmost extremes and midpoint.794         * Then, the Thing is checked for being to the left or right of the795         * midpoint, and the goal set to move it away from the midpoint.796         *797         * @param thing798         * @returns Whether the Thing's overlaps were successfully recorded.799         */800        FullScreenMario.prototype.setOverlapBoundaries = function (thing) {801            // Only having one overlap means nothing should be done802            if (thing.overlaps.length === 1) {803                thing.overlaps.length = 0;804                return false;805            }806            var rightX = -Infinity, leftX = Infinity, overlaps = thing.overlaps, other, leftThing, rightThing, midpoint, i;807            for (i = 0; i < overlaps.length; i += 1) {808                other = overlaps[i];809                if (other.right > rightX) {810                    rightThing = other;811                }812                if (other.left < leftX) {813                    leftThing = other;814                }815            }816            midpoint = (leftX + rightX) / 2;817            if (thing.FSM.getMidX(thing) >= midpoint) {818                thing.overlapGoal = Infinity;819                thing.overlapGoRight = true;820                thing.overlapCheck = rightThing.right;821            }822            else {823                thing.overlapGoal = -Infinity;824                thing.overlapGoRight = false;825                thing.overlapCheck = leftThing.left;826            }827            thing.checkOverlaps = false;828            return true;829        };830        /**831         * Regular maintenance Function called on a Player every upkeep. A barrage832         * of tests are applied, namely falling/jumping, dieing, x- and y-velocities,833         * running, and scrolling. This is separate from the movePlayer movement834         * Function that will be called in maintainCharacters.835         *836         * @param FSM837         */838        FullScreenMario.prototype.maintainPlayer = function (FSM) {839            var player = FSM.player;840            if (!FSM.isThingAlive(player)) {841                return;842            }843            // Player is falling844            if (player.yvel > 0) {845                if (!FSM.MapScreener.underwater) {846                    player.keys.jump = false;847                }848                // Jumping?849                if (!player.jumping && !player.crouching) {850                    // Paddling? (from falling off a solid)851                    if (FSM.MapScreener.underwater) {852                        if (!player.paddling) {853                            FSM.switchClass(player, "paddling", "paddling");854                            player.paddling = true;855                        }856                    }857                    else {858                        FSM.addClass(player, "jumping");859                        player.jumping = true;860                    }861                }862                // Player has fallen too far863                if (!player.dieing && player.top > FSM.MapScreener.bottom) {864                    // If the map has an exit (e.g. cloud world), transport there865                    if (FSM.AreaSpawner.getArea().exit) {866                        FSM.setLocation(FSM.AreaSpawner.getArea().exit);867                    }868                    else {869                        // Otherwise, since Player is below the screen, kill him dead870                        FSM.killPlayer(player, 2);871                    }872                    return;873                }874            }875            // Player is moving to the right876            if (player.xvel > 0) {877                if (player.right > FSM.MapScreener.middleX) {878                    // If Player is to the right of the screen's middle, move the screen879                    if (player.right > FSM.MapScreener.right - FSM.MapScreener.left) {880                        player.xvel = Math.min(0, player.xvel);881                    }882                }883            }884            else if (player.left < 0) {885                // Player is moving to the left886                // Stop Player from going to the left.887                player.xvel = Math.max(0, player.xvel);888            }889            // Player is hitting something (stop jumping)890            if (player.under) {891                player.jumpcount = 0;892            }893            // Scrolloffset is how far over the middle player's right is894            if (FSM.MapScreener.canscroll) {895                var scrolloffset = player.right - FSM.MapScreener.middleX;896                if (scrolloffset > 0) {897                    FSM.scrollWindow(Math.min(player.scrollspeed, scrolloffset));898                }899            }900        };901        /* Collision detectors902        */903        /**904         * Function generator for the generic canThingCollide checker. This is used905         * repeatedly by ThingHittr to generate separately optimized Functions for906         * different Thing types.907         *908         * @returns A Function that generates a canThingCollide checker.909         */910        FullScreenMario.prototype.generateCanThingCollide = function () {911            /**912             * Generic checker for canCollide, used for both Solids and Characters.913             * This just returns if the Thing is alive and doesn't have the914             * nocollide flag.915             *916             * @param thing917             * @returns Whether the thing can collide.918             */919            return function canThingCollide(thing) {920                return thing.alive && !thing.nocollide;921            };922        };923        /**924         * @param thing925         * @returns Whether the Thing is alive, meaning it has a true alive flag926         *          and a false dead flag.927         */928        FullScreenMario.prototype.isThingAlive = function (thing) {929            return thing && thing.alive && !thing.dead;930        };931        /**932         * Generic base function to check if one Thing is touching another. This933         * will be called by the more specific Thing touching functions.934         *935         * @param thing936         * @param other937         * @returns Whether the two Things are touching.938         * @remarks The horizontal checks use allow a unitsize of flexibility.939         */940        FullScreenMario.prototype.isThingTouchingThing = function (thing, other) {941            return (!thing.nocollide && !other.nocollide942                && thing.right - thing.FSM.unitsize > other.left943                && thing.left + thing.FSM.unitsize < other.right944                && thing.bottom >= other.top945                && thing.top <= other.bottom);946        };947        /**948         * General top collision detection Function for two Things to determine if949         * one Thing is on top of another. This takes into consideration factors950         * such as which are solid or an enemy, and y-velocity.951         *952         * @param thing953         * @param other954         * @returns Whether thing is on top of other.955         * @remarks This is a more specific form of isThingTouchingThing.956         */957        FullScreenMario.prototype.isThingOnThing = function (thing, other) {958            // If thing is a solid and other is falling, thing can't be above other959            if (thing.groupType === "Solid" && other.yvel > 0) {960                return false;961            }962            // If other is falling faster than thing, and isn't a solid,963            // thing can't be on top (if anything, the opposite is true)964            if (thing.yvel < other.yvel && other.groupType !== "Solid") {965                return false;966            }967            // If thing is a Player, and it's on top of an enemy, that's true968            if (thing.player && thing.bottom < other.bottom && other.enemy) {969                return true;970            }971            // If thing is too far to the right, it can't be touching other972            if (thing.left + thing.FSM.unitsize >= other.right) {973                return false;974            }975            // If thing is too far to the left, it can't be touching other976            if (thing.right - thing.FSM.unitsize <= other.left) {977                return false;978            }979            // If thing's bottom is below other's top, factoring tolerance and980            // other's vertical velocity, they're touching981            if (thing.bottom <= other.top + other.toly + other.yvel) {982                return true;983            }984            // Same as before, but with velocity as the absolute difference985            // between their two velocities986            if (thing.bottom <= other.top + other.toly + Math.abs(thing.yvel - other.yvel)) {987                return true;988            }989            // None of the above checks passed for true, so this is false (thing's990            // bottom is above other's top)991            return false;992        };993        /**994         * Top collision Function to determine if a Thing is on top of a Solid.995         *996         * @param thing997         * @param other998         * @returns Whether thing is on top of other.999         * @remarks Similar to isThingOnThing, but more specifically used for1000         *          isCharacterOnSolid and isCharacterOnResting1001         */1002        FullScreenMario.prototype.isThingOnSolid = function (thing, other) {1003            // If thing is too far to the right, they're not touching1004            if (thing.left + thing.FSM.unitsize >= other.right) {1005                return false;1006            }1007            // If thing is too far to the left, they're not touching1008            if (thing.right - thing.FSM.unitsize <= other.left) {1009                return false;1010            }1011            // If thing's bottom is below other's top, factoring thing's velocity1012            // and other's tolerance, they're touching1013            if (thing.bottom - thing.yvel <= other.top + other.toly + thing.yvel) {1014                return true;1015            }1016            // Same as before, but with velocity as the absolute difference between1017            // their two velocities1018            if (thing.bottom <= other.top + other.toly + Math.abs(thing.yvel - other.yvel)) {1019                return true;1020            }1021            // None of the above checks passed for true, so this is false (thing's1022            // bottom is above other's top1023            return false;1024        };1025        /**1026         * Top collision Function to determine if a character is on top of a solid.1027         * This is always true for resting (since resting checks happen before when1028         * this should be called).1029         *1030         * @param thing1031         * @param other1032         * @returns Whether thing is on top of other.1033         */1034        FullScreenMario.prototype.isCharacterOnSolid = function (thing, other) {1035            // If character is resting on solid, this is automatically true1036            if (thing.resting === other) {1037                return true;1038            }1039            // If the character is jumping upwards, it's not on a solid1040            // (removing this check would cause Mario to have "sticky" behavior when1041            // jumping at the corners of solids)1042            if (thing.yvel < 0) {1043                return false;1044            }1045            // The character and solid must be touching appropriately1046            if (!thing.FSM.isThingOnSolid(thing, other)) {1047                return false;1048            }1049            // Corner case: when character is exactly falling off the right (false)1050            if (thing.left + thing.xvel + thing.FSM.unitsize === other.right) {1051                return false;1052            }1053            // Corner case: when character is exactly falling off the left (false)1054            if (thing.right - thing.xvel - thing.FSM.unitsize === other.left) {1055                return false;1056            }1057            // None of the above checks caught a falsity, so this must be true1058            return true;1059        };1060        /**1061         * Top collision Function to determine if a character should be considered1062         * resting on a solid. This mostly uses isThingOnSolid, but also checks for1063         * the corner cases of the character being exactly at the edge of the solid1064         * (such as when jumping while next to it).1065         *1066         * @param thing1067         * @param other1068         * @returns Whether thing is on top of other.1069         */1070        FullScreenMario.prototype.isCharacterOnResting = function (thing, other) {1071            if (!thing.FSM.isThingOnSolid(thing, other)) {1072                return false;1073            }1074            // Corner case: when character is exactly falling off the right (false)1075            if (thing.left + thing.xvel + thing.FSM.unitsize === other.right) {1076                return false;1077            }1078            // Corner case: when character is exactly falling off the left (false)1079            if (thing.right - thing.xvel - thing.FSM.unitsize === other.left) {1080                return false;1081            }1082            // None of the above checks caught a falsity, so this must be true1083            return true;1084        };1085        /**1086         * Function generator for the generic isCharacterTouchingCharacter checker.1087         * This is used repeatedly by ThingHittr to generate separately optimized1088         * Functions for different Thing types.1089         *1090         * @returns A Function that generates isCharacterTouchingCharacter.1091         */1092        FullScreenMario.prototype.generateIsCharacterTouchingCharacter = function () {1093            /**1094             * Generic checker for whether two characters are touching each other.1095             * This mostly checks to see if either has the nocollidechar flag, and1096             * if the other is a player. isThingTouchingThing is used after.1097             *1098             * @param thing1099             * @param other1100             * @returns Whether thing is touching other.1101             */1102            return function isCharacterTouchingCharacter(thing, other) {1103                if (thing.nocollidechar && (!other.player || thing.nocollideplayer)) {1104                    return false;1105                }1106                if (other.nocollidechar && (!thing.player || other.nocollideplayer)) {1107                    return false;1108                }1109                return thing.FSM.isThingTouchingThing(thing, other);1110            };1111        };1112        /**1113         * Function generator for the generic isCharacterTouchingSolid checker. This1114         * is used repeatedly by ThingHittr to generate separately optimized1115         * Functions for different Thing types.1116         *1117         * @returns A Function that generates isCharacterTouchingSolid.1118         */1119        FullScreenMario.prototype.generateIsCharacterTouchingSolid = function () {1120            /**1121             * Generic checker for whether a character is touching a solid. The1122             * hidden, collideHidden, and nocollidesolid flags are most relevant.1123             *1124             * @param thing1125             * @param other1126             * @returns Whether thing is touching other.1127             */1128            return function isCharacterTouchingSolid(thing, other) {1129                // Hidden solids can only be touched by a Player bottom-bumping1130                // them, or by specifying collideHidden1131                if (other.hidden && !other.collideHidden) {1132                    if (!thing.player || !thing.FSM.isSolidOnCharacter(other, thing)) {1133                        return false;1134                    }1135                }1136                if (thing.nocollidesolid && !(thing.allowUpSolids && other.up)) {1137                    return false;1138                }1139                return thing.FSM.isThingTouchingThing(thing, other);1140            };1141        };1142        /**1143         * @param thing1144         * @param other1145         * @returns Whether thing's bottom is above other's top, allowing for1146         *          other's toly.1147         */1148        FullScreenMario.prototype.isCharacterAboveEnemy = function (thing, other) {1149            return thing.bottom < other.top + other.toly;1150        };1151        /**1152         * @param thing1153         * @param other1154         * @returns Whether thing's top is above other's bottom, allowing for1155         *          the Thing's toly and yvel.1156         */1157        FullScreenMario.prototype.isCharacterBumpingSolid = function (thing, other) {1158            return thing.top + thing.toly + Math.abs(thing.yvel) > other.bottom;1159        };1160        /**1161         * @param thing1162         * @param other1163         * @returns Whether thing is "overlapping" other.1164         */1165        FullScreenMario.prototype.isCharacterOverlappingSolid = function (thing, other) {1166            return thing.top <= other.top && thing.bottom > other.bottom;1167        };1168        /**1169         * @param thing1170         * @param other1171         * @returns Whether thing, typically a solid, is on top of other.1172         * @remarks This is similar to isThingOnThing, but more specifically1173         *          used for characterTouchedSolid.1174         */1175        FullScreenMario.prototype.isSolidOnCharacter = function (thing, other) {1176            // This can never be true if other is falling1177            if (other.yvel >= 0) {1178                return false;1179            }1180            // Horizontally, all that's required is for the other's midpoint to1181            // be within the thing's left and right1182            var midx = thing.FSM.getMidX(other);1183            if (midx <= thing.left || midx >= thing.right) {1184                return false;1185            }1186            // If the thing's bottom is below the other's top, factoring1187            // tolerance and velocity, that's false (this function assumes they're1188            // already touching)1189            if (thing.bottom - thing.yvel > other.top + other.toly - other.yvel) {1190                return false;1191            }1192            // The above checks never caught falsities, so this must be true1193            return true;1194        };1195        /* Collision reactions1196        */1197        /**1198         * Externally facing Function to gain some number of lives. ItemsHolder1199         * increases the "score" statistic, an audio is played, and the mod event is1200         * fired.1201         *1202         * @param amount   How many lives to gain (by default, 1).1203         * @param nosound   Whether the sound should be skipped (by default,1204         *                  false).1205         */1206        FullScreenMario.prototype.gainLife = function (amount, nosound) {1207            var FSM = FullScreenMario.prototype.ensureCorrectCaller(this);1208            amount = Number(amount) || 1;1209            FSM.ItemsHolder.increase("lives", amount);1210            if (!nosound) {1211                this.AudioPlayer.play("Gain Life");1212            }1213            FSM.ModAttacher.fireEvent("onGainLife", amount);1214        };1215        /**1216         * Basic Function for an item to jump slightly into the air, such as from1217         * a Player hitting a solid below it.1218         *1219         * @param thing   An item.1220         * @remarks This simply moves the thing up slightly and decreases its1221         *          y-velocity, without considering x-direction.1222         */1223        FullScreenMario.prototype.itemJump = function (thing) {1224            thing.yvel -= FullScreenMario.unitsize * 1.4;1225            this.shiftVert(thing, -FullScreenMario.unitsize);1226        };1227        /**1228         * Generic Function for when a Player jumps on top of an enemy. The enemy1229         * is killed, a Player's velocity points upward, and score is gained.1230         *1231         * @param thing   A Player jumping on other.1232         * @param other   An Enemy being jumped upon.1233         */1234        FullScreenMario.prototype.jumpEnemy = function (thing, other) {1235            if (thing.keys.up) {1236                thing.yvel = thing.FSM.unitsize * -1.4;1237            }1238            else {1239                thing.yvel = thing.FSM.unitsize * -0.7;1240            }1241            thing.xvel *= 0.91;1242            thing.FSM.AudioPlayer.play("Kick");1243            if (!thing.item || other.shell) {1244                thing.jumpcount += 1;1245                thing.FSM.scoreOn(thing.FSM.findScore(thing.jumpcount + thing.jumpers), other);1246            }1247            thing.jumpers += 1;1248            thing.FSM.TimeHandler.addEvent(function (thing) {1249                thing.jumpers -= 1;1250            }, 1, thing);1251        };1252        /**1253         * Callback for a Player hitting a Mushroom or FireFlower. A player's1254         * power and the ItemsHolder's "power" statistic both go up, and the1255         * corresponding animations and mod event are triggered.1256         *1257         * @param thing   A Player powering up.1258         * @param other   A Mushroom powering up hte Player.1259         */1260        FullScreenMario.prototype.playerShroom = function (thing, other) {1261            if (thing.shrooming || !thing.player) {1262                return;1263            }1264            thing.FSM.AudioPlayer.play("Powerup");1265            thing.FSM.scoreOn(1000, thing.FSM.player);1266            if (thing.power < 3) {1267                thing.FSM.ItemsHolder.increase("power");1268                if (thing.power < 3) {1269                    thing.shrooming = true;1270                    thing.power += 1;1271                    if (thing.power === 3) {1272                        thing.FSM.playerGetsFire(thing.FSM.player);1273                    }1274                    else {1275                        thing.FSM.playerGetsBig(thing.FSM.player);1276                    }1277                }1278            }1279            thing.FSM.ModAttacher.fireEvent("onPlayerShroom", thing, other);1280        };1281        /**1282         * Callback for a Player hitting a Mushroom1Up. The game simply calls1283         * gainLife and triggers the mod event.1284         *1285         * @param thing   A Player gaining a life.1286         * @param other   The Mushroom1Up giving the life.1287         */1288        FullScreenMario.prototype.playerShroom1Up = function (thing, other) {1289            if (!thing.player) {1290                return;1291            }1292            thing.FSM.gainLife(1);1293            thing.FSM.ModAttacher.fireEvent("onPlayerShroom1Up", thing, other);1294        };1295        /**1296         * Callback for a Player hitting a Star. A set of animation loops and1297         * sounds play, and the mod event is triggered. After some long period time,1298         * playerStarDown is called to start the process of removing star power.1299         *1300         * @param thing   A Player gaining star powers.1301         * @param timeout   How long to wait before calling playerStarDown1302         *                  (by default, 560).1303         */1304        FullScreenMario.prototype.playerStarUp = function (thing, timeout) {1305            if (timeout === void 0) { timeout = 560; }1306            thing.star += 1;1307            thing.FSM.switchClass(thing, "normal fiery", "star");1308            thing.FSM.AudioPlayer.play("Powerup");1309            thing.FSM.AudioPlayer.addEventListener("Powerup", "ended", thing.FSM.AudioPlayer.playTheme.bind(thing.FSM.AudioPlayer, "Star", true));1310            thing.FSM.TimeHandler.addClassCycle(thing, ["star1", "star2", "star3", "star4"], "star", 2);1311            thing.FSM.TimeHandler.addEvent(thing.FSM.playerStarDown, timeout || 560, thing);1312            thing.FSM.ModAttacher.fireEvent("onPlayerStarUp", thing);1313        };1314        /**1315         * Trigger to commence reducing a Player's star power. This slows the1316         * class cycle, times a playerStarOffCycle trigger, and fires the mod event.1317         *1318         * @param thing   A Player losing star powers.1319         */1320        FullScreenMario.prototype.playerStarDown = function (thing) {1321            if (!thing.player) {1322                return;1323            }1324            thing.FSM.TimeHandler.cancelClassCycle(thing, "star");1325            thing.FSM.TimeHandler.addClassCycle(thing, [1326                "star1", "star2", "star3", "star4"1327            ], "star", 5);1328            thing.FSM.TimeHandler.addEvent(thing.FSM.playerStarOffCycle, 140, thing);1329            thing.FSM.AudioPlayer.removeEventListeners("Powerup", "ended");1330            thing.FSM.ModAttacher.fireEvent("onPlayerStarDown", thing);1331        };1332        /**1333         * Trigger to continue reducing a Player's star power. This resumes1334         * playing the regular theme, times a playerStarOffFinal trigger, and fires1335         * the mod event.1336         *1337         * @param thing   A Player losing star powers.1338         */1339        FullScreenMario.prototype.playerStarOffCycle = function (thing) {1340            if (!thing.player) {1341                return;1342            }1343            if (thing.star > 1) {1344                thing.star -= 1;1345                return;1346            }1347            if (!thing.FSM.AudioPlayer.getTheme().paused) {1348                thing.FSM.AudioPlayer.playTheme();1349            }1350            thing.FSM.TimeHandler.addEvent(thing.FSM.playerStarOffFinal, 70, thing);1351            thing.FSM.ModAttacher.fireEvent("onPlayerStarOffCycle", thing);1352        };1353        /**1354         * Trigger to finish reducing a Player's star power. This actually reduces1355         * a Player's star attribute, cancels the sprite cycle, adds the previous1356         * classes back, and fires the mod event.1357         *1358         * @param thing   A Player losing star powers.1359         */1360        FullScreenMario.prototype.playerStarOffFinal = function (thing) {1361            if (!thing.player) {1362                return;1363            }1364            thing.star -= 1;1365            thing.FSM.TimeHandler.cancelClassCycle(thing, "star");1366            thing.FSM.removeClasses(thing, "star star1 star2 star3 star4");1367            thing.FSM.addClass(thing, "normal");1368            if (thing.power === 3) {1369                thing.FSM.addClass(thing, "fiery");1370            }1371            thing.FSM.ModAttacher.fireEvent("onPlayerStarOffFinal", thing);1372        };1373        /**1374         * Sizing modifier for a Player, typically called when entering a location1375         * or colliding with a Mushroom. This sets a Player's size to the large1376         * mode and optionally plays the animation. The mod event is then fired.1377         *1378         * @param thing   A Player increasing in size.1379         * @param noAnimation   Whether to skip the animation (by default,1380         *                      false).1381         */1382        FullScreenMario.prototype.playerGetsBig = function (thing, noAnimation) {1383            thing.FSM.setPlayerSizeLarge(thing);1384            thing.FSM.removeClasses(thing, "crouching small");1385            thing.FSM.updateBottom(thing, 0);1386            thing.FSM.updateSize(thing);1387            if (noAnimation) {1388                thing.FSM.addClass(thing, "large");1389            }1390            else {1391                thing.FSM.playerGetsBigAnimation(thing);1392            }1393            thing.FSM.ModAttacher.fireEvent("onPlayerGetsBig", thing);1394        };1395        /**1396         * Animation scheduler for a Player getting big. The shrooming classes are1397         * cycled through rapidly while a Player's velocity is paused.1398         *1399         * @param thing   A Player increasing in size.1400         */1401        FullScreenMario.prototype.playerGetsBigAnimation = function (thing) {1402            var stages = [1403                "shrooming1", "shrooming2",1404                "shrooming1", "shrooming2",1405                "shrooming3", "shrooming2", "shrooming3"1406            ];1407            thing.FSM.addClass(thing, "shrooming");1408            thing.FSM.animateCharacterPauseVelocity(thing);1409            // The last stage in the events clears it, resets movement, and stops1410            stages.push(function (thing) {1411                thing.shrooming = false;1412                stages.length = 0;1413                thing.FSM.addClass(thing, "large");1414                thing.FSM.removeClasses(thing, "shrooming shrooming3");1415                thing.FSM.animateCharacterResumeVelocity(thing);1416                return true;1417            });1418            thing.FSM.TimeHandler.addClassCycle(thing, stages, "shrooming", 6);1419        };1420        /**1421         * Sizing modifier for a Player, typically called when going down to1422         * normal size after being large. This containst eha nimation scheduling1423         * to cycle through paddling classes, then flickers a Player. The mod1424         * event is fired.1425         *1426         * @param thing   A Player decreasing in size.1427         */1428        FullScreenMario.prototype.playerGetsSmall = function (thing) {1429            var bottom = thing.bottom;1430            thing.FSM.animateCharacterPauseVelocity(thing);1431            // Step one1432            thing.nocollidechar = true;1433            thing.FSM.animateFlicker(thing);1434            thing.FSM.removeClasses(thing, "running skidding jumping fiery");1435            thing.FSM.addClasses(thing, "paddling small");1436            // Step two (t+21)1437            thing.FSM.TimeHandler.addEvent(function (thing) {1438                thing.FSM.removeClass(thing, "large");1439                thing.FSM.setPlayerSizeSmall(thing);1440                thing.FSM.setBottom(thing, bottom - FullScreenMario.unitsize);1441            }, 21, thing);1442            // Step three (t+42)1443            thing.FSM.TimeHandler.addEvent(function (thing) {1444                thing.FSM.animateCharacterResumeVelocity(thing, false);1445                thing.FSM.removeClass(thing, "paddling");1446                if (thing.running || thing.xvel) {1447                    thing.FSM.addClass(thing, "running");1448                }1449                thing.FSM.PixelDrawer.setThingSprite(thing);1450            }, 42, thing);1451            // Step four (t+70)1452            thing.FSM.TimeHandler.addEvent(function (thing) {1453                thing.nocollidechar = false;1454            }, 70, thing);1455            thing.FSM.ModAttacher.fireEvent("onPlayerGetsSmall");1456        };1457        /**1458         * Visual changer for when a Player collides with a FireFlower. The1459         * "fiery" class is added, and the mod event is fired.1460         *1461         * @param thing   A Player gaining fire powers.1462         */1463        FullScreenMario.prototype.playerGetsFire = function (thing) {1464            thing.shrooming = false;1465            if (!thing.star) {1466                thing.FSM.addClass(thing, "fiery");1467            }1468            thing.FSM.ModAttacher.fireEvent("onPlayerGetsFire");1469        };1470        /**1471         * Actually sets the size for a player to small (8x8) via setSize and1472         * updateSize.1473         *1474         * @param thing   A Player decreasing in size.1475         */1476        FullScreenMario.prototype.setPlayerSizeSmall = function (thing) {1477            thing.FSM.setSize(thing, 8, 8, true);1478            thing.FSM.updateSize(thing);1479        };1480        /**1481         * Actually sets the size for a player to large (8x16) via setSize and1482         * updateSize.1483         *1484         * @param thing   A Player increasing in size.1485         */1486        FullScreenMario.prototype.setPlayerSizeLarge = function (thing) {1487            thing.FSM.setSize(thing, 8, 16, true);1488            thing.FSM.updateSize(thing);1489        };1490        /**1491         * Removes the crouching flag from a Player and re-adds the running cycle.1492         * If a Player is large (has power > 1), size and classes must be set.1493         *1494         * @param thing   A Player that is no longer crouching.1495         */1496        FullScreenMario.prototype.animatePlayerRemoveCrouch = function (thing) {1497            thing.crouching = false;1498            thing.toly = thing.tolyOld || 0;1499            if (thing.power !== 1) {1500                thing.FSM.setHeight(thing, 16, true, true);1501                thing.FSM.removeClasses(thing, "crouching");1502                thing.FSM.updateBottom(thing, 0);1503                thing.FSM.updateSize(thing);1504            }1505            thing.FSM.animatePlayerRunningCycle(thing);1506        };1507        /**1508         * Officially unattaches a player from a solid. The thing's physics flags1509         * are reset to normal, the two have their attachment flags set, and the1510         * thing is set to be jumping off.1511         *1512         * @param thing   A Player attached to other.1513         * @param other   A Solid thing is attached to.1514         */1515        FullScreenMario.prototype.unattachPlayer = function (thing, other) {1516            thing.nofall = false;1517            thing.nocollide = false;1518            thing.checkOverlaps = true;1519            thing.attachedSolid = undefined;1520            thing.xvel = thing.keys ? thing.keys.run : 0;1521            thing.movement = thing.FSM.movePlayer;1522            thing.FSM.addClass(thing, "jumping");1523            thing.FSM.removeClasses(thing, "climbing", "animated");1524            other.attachedCharacter = undefined;1525        };1526        /**1527         * Adds an invisible RestingStone underneath a Player. It is hidden and1528         * unable to collide until a Player falls to its level, at which point the1529         * stone is set underneath a Player to be rested upon.1530         *1531         * @param thing   A Player respawning into the game.1532         */1533        FullScreenMario.prototype.playerAddRestingStone = function (thing) {1534            var stone = thing.FSM.addThing("RestingStone", thing.left, thing.top + thing.FSM.unitsize * 48);1535            thing.nocollide = true;1536            thing.FSM.TimeHandler.addEventInterval(function () {1537                if (thing.bottom < stone.top) {1538                    return false;1539                }1540                thing.nocollide = false;1541                thing.FSM.setMidXObj(stone, thing);1542                thing.FSM.setBottom(thing, stone.top);1543                return true;1544            }, 1, Infinity);1545        };1546        /**1547         * Marks a new overlapping Thing in the first Thing's overlaps Array,1548         * creating the Array if needed.1549         *1550         * @param thing   The Thing that is overlapping another Thing.1551         * @param other   The Thing being added to the overlaps Array.1552         */1553        FullScreenMario.prototype.markOverlap = function (thing, other) {1554            if (!thing.overlaps) {1555                thing.overlaps = [other];1556            }1557            else {1558                thing.overlaps.push(other);1559            }1560        };1561        /* Spawn / activate functions1562        */1563        /**1564         * Spawn callback for DeadGoombas. They simply disappear after 21 steps.1565         *1566         * @param thing   A DeadGoomba being spawned.1567         */1568        FullScreenMario.prototype.spawnDeadGoomba = function (thing) {1569            thing.FSM.TimeHandler.addEvent(FullScreenMario.prototype.killNormal, 21, thing);1570        };1571        /**1572         * Spawn callback for HammerBros. Gravity is reduced, and the hammer and1573         * jump event intervals are started. The cyclical movement counter is set to1574         * 0.1575         *1576         * @param thing   A HammerBro being spawned.1577         */1578        FullScreenMario.prototype.spawnHammerBro = function (thing) {1579            thing.counter = 0;1580            thing.gravity = thing.FSM.MapScreener.gravity / 2.1;1581            thing.FSM.TimeHandler.addEvent(thing.FSM.animateThrowingHammer, 35, thing, 7);1582            thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateJump, 140, Infinity, thing);1583        };1584        /**1585         * Spawn callback for Bowsers. The cyclical movement counter is set to 0 and1586         * the firing and jumping event intervals are started. If it also specifies1587         * a throwing interval, that's started too.1588         *1589         * @param thing   A Bowser being spawned.1590         */1591        FullScreenMario.prototype.spawnBowser = function (thing) {1592            var i;1593            thing.counter = 0;1594            thing.deathcount = 0;1595            for (i = 0; i < thing.fireTimes.length; i += 1) {1596                thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateBowserFire, thing.fireTimes[i], Infinity, thing);1597            }1598            for (i = 0; i < thing.jumpTimes.length; i += 1) {1599                thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateBowserJump, thing.jumpTimes[i], Infinity, thing);1600            }1601            if (thing.throwing) {1602                for (i = 0; i < thing.throwAmount; i += 1) {1603                    thing.FSM.TimeHandler.addEvent(function () {1604                        thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateBowserThrow, thing.throwPeriod, Infinity, thing);1605                    }, thing.throwDelay + i * thing.throwBetween);1606                }1607            }1608        };1609        /**1610         * Spawn callback for Piranhas. The movement counter and direction are1611         * reset, and if the Piranha is on a pipe, it has a reduced height (6).1612         *1613         * @param thing   A Piranha being spawned.1614         */1615        FullScreenMario.prototype.spawnPiranha = function (thing) {1616            var bottom;1617            thing.counter = 0;1618            thing.direction = thing.FSM.unitsize / -40;1619            if (thing.onPipe) {1620                bottom = thing.bottom;1621                thing.FSM.setHeight(thing, 6);1622                thing.FSM.setBottom(thing, bottom);1623            }1624        };1625        /**1626         * Spawn callback for Bloopers. Its squeeze and movement counters are1627         * set to 0.1628         *1629         * @param thing   A Blooper being spawned.1630         */1631        FullScreenMario.prototype.spawnBlooper = function (thing) {1632            thing.squeeze = 0;1633            thing.counter = 0;1634        };1635        /**1636         * Spawn callback for Podoboos. The jumping interval is set to the Thing's1637         * frequency.1638         *1639         * @param thing   A Podoboo being spawned.1640         */1641        FullScreenMario.prototype.spawnPodoboo = function (thing) {1642            thing.FSM.TimeHandler.addEventInterval(thing.FSM.animatePodobooJumpUp, thing.frequency, Infinity, thing);1643        };1644        /**1645         * Spawn callback for Lakitus. MapScreenr registers the most recently1646         * added Lakitu as some areas spawn them every once in a while.1647         *1648         * @param thing   A Lakitu being spawned.1649         */1650        FullScreenMario.prototype.spawnLakitu = function (thing) {1651            thing.FSM.MapScreener.lakitu = thing;1652            thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateLakituThrowingSpiny, 140, Infinity, thing);1653        };1654        /**1655         * Spawning callback for Cannons. Unless specified by the noBullets flag,1656         * the firing interval is set to the Thing's frequency.1657         *1658         * @param thing   A Cannon being spawned.1659         */1660        FullScreenMario.prototype.spawnCannon = function (thing) {1661            if (thing.noBullets) {1662                return;1663            }1664            thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateCannonFiring, thing.frequency, thing.frequency, thing);1665        };1666        /**1667         * Spawning callback for CastleBlocks. If the Thing has fireballs, an Array1668         * of them are made and animated to tick around the block like a clock, set1669         * by the thing's speed and direction.1670         *1671         * @param thing   A CastleBlock being spawned.1672         */1673        FullScreenMario.prototype.spawnCastleBlock = function (thing) {1674            if (!thing.fireballs) {1675                return;1676            }1677            var balls = [], i;1678            for (i = 0; i < thing.fireballs; i += 1) {1679                balls.push(thing.FSM.addThing("CastleFireball"));1680                thing.FSM.setMidObj(balls[i], thing);1681            }1682            if (thing.speed >= 0) {1683                thing.dt = 0.07;1684                thing.angle = 0.25;1685            }1686            else {1687                thing.dt = -0.07;1688                thing.angle = -0.25;1689            }1690            if (!thing.direction) {1691                thing.direction = -1;1692            }1693            thing.FSM.TimeHandler.addEventInterval(thing.FSM.animateCastleBlock, Math.round(7 / Math.abs(thing.speed)), Infinity, thing, balls);1694        };1695        /**1696         * Spawning callback for floating Things, such as Koopas and Platforms. The1697         * Thing's begin and end attributes are set relative to the MapScreener's1698         * floor, so its movement can handle cycling between the two.1699         *1700         * @param thing   A Thing being spawned to float around.1701         */1702        FullScreenMario.prototype.spawnMoveFloating = function (thing) {1703            // Make sure thing.begin <= thing.end1704            thing.FSM.setMovementEndpoints(thing);1705            // Make thing.begin and thing.end relative to the area's floor1706            thing.begin = thing.FSM.MapScreener.floor * thing.FSM.unitsize - thing.begin;1707            thing.end = thing.FSM.MapScreener.floor * thing.FSM.unitsize - thing.end;1708        };1709        /**1710         * Spawning callback for sliding Things, such as Platforms. The Thing's1711         * begin and end attributes do not need to be relative to anything.1712         *1713         * @param thing   A Thing being spawned to slide back and forth.1714         */1715        FullScreenMario.prototype.spawnMoveSliding = function (thing) {1716            // Make sure thing.begin <= thing.end1717            thing.FSM.setMovementEndpoints(thing);1718        };1719        /**1720         * Spawning callback for a Platform that's a part of a Scale.1721         *1722         * @param thing   A Platform being spawned within a Scale group.1723         */1724        FullScreenMario.prototype.spawnScalePlatform = function (thing) {1725            var collection = thing.collection || {}, ownKey = thing.collectionKey === "platformLeft" ? "Left" : "Right", partnerKey = ownKey === "Left" ? "Right" : "Left";1726            thing.partners = {1727                "ownString": collection["string" + ownKey],1728                "partnerString": collection["string" + partnerKey],1729                "partnerPlatform": collection["platform" + partnerKey]1730            };1731        };1732        /**1733         * Generator callback to create a random CheepCheep. The spawn is given a1734         * random x-velocity, is placed at a random point just below the screen, and1735         * is oriented towards a Player.1736         *1737         * @param FSM1738         * @returns Whether CheepCheep spawning has been cancelled.1739         */1740        FullScreenMario.prototype.spawnRandomCheep = function (FSM) {1741            if (!FSM.MapScreener.spawningCheeps) {1742                return true;1743            }1744            var spawn = FSM.ObjectMaker.make("CheepCheep", {1745                "flying": true,1746                "xvel": FSM.NumberMaker.random() * FSM.unitsize * 1.4,1747                "yvel": FSM.unitsize * -1.41748            });1749            FSM.addThing(spawn, FSM.NumberMaker.random() * FSM.MapScreener.width, FSM.MapScreener.height);1750            if (spawn.left < FSM.MapScreener.width / 2) {1751                FSM.flipHoriz(spawn);1752            }1753            else {1754                spawn.xvel *= -1;1755            }1756            return false;1757        };1758        /**1759         * Generator callback to create a BulleBill. The spawn moves horizontally1760         * at a constant rate towards the left side of the bill, and is placed at a1761         * random point to the right side of the screen.1762         *1763         * @param FSM1764         * @returns Whether BulletBill spawning has been cancelled.1765         */1766        FullScreenMario.prototype.spawnRandomBulletBill = function (FSM) {1767            if (!FSM.MapScreener.spawningBulletBills) {1768                return true;1769            }1770            var spawn = FSM.ObjectMaker.make("BulletBill");1771            spawn.direction = 1;1772            spawn.moveleft = true;1773            spawn.xvel *= -1;1774            FSM.flipHoriz(spawn);1775            FSM.addThing(spawn, FSM.MapScreener.width, Math.floor(FSM.NumberMaker.randomIntWithin(0, FSM.MapScreener.floor) / 8) * 8 * FSM.unitsize);1776            return false;1777        };1778        /**1779         * Spawns a CustomText by killing it and placing the contents of its texts1780         * member variable. These are written with a determined amount of spacing1781         * between them, as if by a typewriter.1782         *1783         * @param thing   A CustomText being spawned.1784         */1785        FullScreenMario.prototype.spawnCustomText = function (thing) {1786            var top = thing.top, texts = thing.texts, attributes = thing.textAttributes, spacingHorizontal = thing.spacingHorizontal * thing.FSM.unitsize, spacingVertical = thing.spacingVertical * thing.FSM.unitsize, spacingVerticalBlank = thing.spacingVerticalBlank * thing.FSM.unitsize, children = [], textChild, left, text, letter, i, j;1787            thing.children = children;1788            for (i = 0; i < texts.length; i += 1) {1789                if (!texts[i]) {1790                    top += spacingVerticalBlank;1791                    continue;1792                }1793                text = texts[i].text;1794                if (texts[i].offset) {1795                    left = thing.left + texts[i].offset * thing.FSM.unitsize;1796                }1797                else {1798                    left = thing.left;1799                }1800                for (j = 0; j < text.length; j += 1) {1801                    letter = text[j];1802                    if (thing.FSM.customTextMappings.hasOwnProperty(letter)) {1803                        letter = thing.FSM.customTextMappings[letter];1804                    }1805                    letter = "Text" + thing.size + letter;1806                    textChild = thing.FSM.ObjectMaker.make(letter, attributes);1807                    textChild.FSM.addThing(textChild, left, top);1808                    children.push(textChild);1809                    left += textChild.width * thing.FSM.unitsize;1810                    left += spacingHorizontal;1811                }1812                top += spacingVertical;1813            }1814            thing.FSM.killNormal(thing);1815        };1816        /**1817         * Spawning callback for generic detectors, activated as soon as they are1818         * placed. The Thing's activate trigger is called, then it is killed.1819         *1820         * @param thing   A Detector being spawned.1821         */1822        FullScreenMario.prototype.spawnDetector = function (thing) {1823            thing.activate(thing);1824            thing.FSM.killNormal(thing);1825        };1826        /**1827         * Spawning callback for ScrollBlockers. If the Thing is to the right of1828         * the visible viewframe, it should limit scrolling when triggered.1829         *1830         * @param thing   A ScrollBlocker being spawned.1831         */1832        FullScreenMario.prototype.spawnScrollBlocker = function (thing) {1833            if (thing.FSM.MapScreener.width < thing.right) {1834                thing.setEdge = true;1835            }1836        };1837        /**1838         * Used by Things in a collection to register themselves as a part of their1839         * container collection Object. This is called by onThingMake, so they're1840         * immediately put in the collection and have it as a member variable.1841         *1842         * @param collection   The collection Object shared by all members.1843         * @param thing   A member of the collection being spawned.1844         */1845        FullScreenMario.prototype.spawnCollectionComponent = function (collection, thing) {1846            thing.collection = collection;1847            collection[thing.collectionName] = thing;1848        };1849        /**1850         * Spawning callback for RandomSpawner Things, which generate a set of1851         * commands using the WorldSeeder to be piped into the AreaSpawnr, then1852         * spawn the immediate area.1853         *1854         * @param thing   A RandomSpawner being spawned.1855         */1856        FullScreenMario.prototype.spawnRandomSpawner = function (thing) {1857            var FSM = thing.FSM, left = (thing.left + FSM.MapScreener.left) / FSM.unitsize;1858            FSM.WorldSeeder.clearGeneratedCommands();1859            FSM.WorldSeeder.generateFull({1860                "title": thing.randomization,1861                "top": thing.randomTop,1862                "right": left + thing.randomWidth,1863                "bottom": thing.randomBottom,1864                "left": left,1865                "width": thing.randomWidth,1866                "height": thing.randomTop - thing.randomBottom1867            });1868            FSM.WorldSeeder.runGeneratedCommands();1869            FSM.AreaSpawner.spawnArea("xInc", FSM.QuadsKeeper.top / FSM.unitsize, FSM.QuadsKeeper.right / FSM.unitsize, FSM.QuadsKeeper.bottom / FSM.unitsize, FSM.QuadsKeeper.left / FSM.unitsize);1870        };1871        /**1872         * Activation callback for starting spawnRandomCheep on an interval.1873         * MapScreener is notified that spawningCheeps is true.1874         *1875         * @param thing   A Detector activated to start spawning CheepCheeps.1876         */1877        FullScreenMario.prototype.activateCheepsStart = function (thing) {1878            thing.FSM.MapScreener.spawningCheeps = true;1879            thing.FSM.TimeHandler.addEventInterval(thing.FSM.spawnRandomCheep, 21, Infinity, thing.FSM);1880        };1881        /**1882         * Activation callback to stop spawning CheepCheeps. MapScreener is notified1883         * that spawningCheeps is false.1884         *1885         * @param thing   A Detector activated to stop spawning CheepCheeps.1886         */1887        FullScreenMario.prototype.activateCheepsStop = function (thing) {1888            thing.FSM.MapScreener.spawningCheeps = false;1889        };1890        /**1891         * Activation callback for starting spawnRandomBulletBill on an interval.1892         * MapScreener is notified that spawningBulletBills is true.1893         *1894         * @param thing   A Detector activated to start spawning BulletBills.1895         */1896        FullScreenMario.prototype.activateBulletBillsStart = function (thing) {1897            thing.FSM.MapScreener.spawningBulletBills = true;1898            thing.FSM.TimeHandler.addEventInterval(thing.FSM.spawnRandomBulletBill, 210, Infinity, thing.FSM);1899        };1900        /**1901         * Activation callback to stop spawning BulletBills. MapScreener is notified1902         * that spawningBulletBills is false.1903         *1904         * @param thing   A Detector activated to stop spawning BulletBills.1905         */1906        FullScreenMario.prototype.activateBulletBillsStop = function (thing) {1907            thing.FSM.MapScreener.spawningBulletBills = false;1908        };1909        /**1910         * Activation callback to tell the area's Lakitu, if it exists, to start1911         * fleeing the scene.1912         *1913         * @param thing   A Detector activated to make the Lakitu flee.1914         */1915        FullScreenMario.prototype.activateLakituStop = function (thing) {1916            var lakitu = thing.FSM.MapScreener.lakitu;1917            if (!lakitu) {1918                return;1919            }1920            lakitu.fleeing = true;1921            lakitu.movement = thing.FSM.moveLakituFleeing;1922        };1923        /**1924         * Activation callback for a warp world area, triggered by a Player1925         * touching a collider on top of it. Piranhas disappear and texts are1926         * revealed.1927         *1928         * @param thing   A Player activating the warp world.1929         * @param other   A Detector triggered by thing to activate a warp world.1930         */1931        FullScreenMario.prototype.activateWarpWorld = function (thing, other) {1932            var collection = other.collection, key = 0, keyString, texts, j;1933            if (!thing.player) {1934                return;1935            }1936            texts = collection.Welcomer.children;1937            for (j = 0; j < texts.length; j += 1) {1938                if (texts[j].title !== "TextSpace") {1939                    texts[j].hidden = false;1940                }1941            }1942            while (true) {1943                keyString = key + "-Text";1944                if (!collection.hasOwnProperty(keyString)) {1945                    break;1946                }1947                texts = collection[keyString].children;1948                for (j = 0; j < texts.length; j += 1) {1949                    if (texts[j].title !== "TextSpace") {1950                        texts[j].hidden = false;1951                    }1952                }1953                thing.FSM.killNormal(collection[key + "-Piranha"]);1954                key += 1;1955            }1956        };1957        /**1958         * Activation callback for when a Player lands on a RestingStone. The1959         * stone "appears" (via opacity), the regular theme plays if it wasn't1960         * already, and the RestingStone waits to kill itself when a Player isn't1961         * touching it.1962         *1963         * @param thing   A RestingStone being landed on.1964         * @param other   A Player landing on thing.1965         */1966        FullScreenMario.prototype.activateRestingStone = function (thing, other) {1967            if (thing.activated) {1968                return;1969            }1970            thing.activated = true;1971            thing.opacity = 1;1972            thing.FSM.AudioPlayer.playTheme();1973            thing.FSM.TimeHandler.addEventInterval(function () {1974                if (other.resting === thing) {1975                    return false;1976                }1977                thing.FSM.killNormal(thing);1978                return true;1979            }, 1, Infinity);1980        };1981        /**1982         * Generic activation callback for DetectWindow Things. This is typically1983         * set as a .movement Function, so it waits until the calling Thing is1984         * within the MapScreener's area to call the activate Function and kill1985         * itself.1986         *1987         * @param thing   A DetectWindow that might be activated.1988         */1989        FullScreenMario.prototype.activateWindowDetector = function (thing) {1990            if (thing.FSM.MapScreener.right - thing.FSM.MapScreener.left < thing.left) {1991                return;1992            }1993            thing.activate(thing);1994            thing.FSM.killNormal(thing);1995        };1996        /**1997         * Activation callback for ScrollBlocker Things. These are WindowDetectors1998         * that set MapScreener.canscroll to false when they're triggered. If the1999         * latest scrollWindow call pushed it too far to the left, it scrolls back2000         * the other way.2001         *2002         * @param thing   A ScrollBlocker that might be activated.2003         */2004        FullScreenMario.prototype.activateScrollBlocker = function (thing) {2005            var dx = thing.FSM.MapScreener.width - thing.left;2006            thing.FSM.MapScreener.canscroll = false;2007            if (thing.setEdge && dx > 0) {2008                thing.FSM.scrollWindow(-dx);2009            }2010        };2011        /**2012         * Activation callback for ScrollBlocker Things. These are DetectCollision2013         * that set MapScreener.canscroll to true when they're triggered.2014         *2015         * @param thing   An activated ScrollEnabler.2016         */2017        FullScreenMario.prototype.activateScrollEnabler = function (thing) {2018            thing.FSM.MapScreener.canscroll = true;2019        };2020        /**2021         * Activates the "before" component of a stretchable section. The creation2022         * commands of the section are loaded onto the screen as is and a2023         * DetectWindow is added to their immediate right that will trigger the2024         * equivalent activateSectionStretch.2025         *2026         * @param thing   An activated SectionDecider.2027         */2028        FullScreenMario.prototype.activateSectionBefore = function (thing) {2029            var FSM = thing.FSM, MapsCreator = FSM.MapsCreator, MapScreener = FSM.MapScreener, AreaSpawner = FSM.AreaSpawner, area = AreaSpawner.getArea(), map = AreaSpawner.getMap(), prethings = AreaSpawner.getPreThings(), section = area.sections[thing.section || 0], left = (thing.left + MapScreener.left) / FSM.unitsize, before = section.before ? section.before.creation : undefined, command, i;2030            // If there is a before, parse each command into the prethings array2031            if (before) {2032                for (i = 0; i < before.length; i += 1) {2033                    // A copy of the command must be used to not modify the original 2034                    command = FSM.proliferate({}, before[i]);2035                    // The command's x must be shifted by the thing's placement2036                    if (!command.x) {2037                        command.x = left;2038                    }2039                    else {2040                        command.x += left;2041                    }2042                    // For Platforms that slide around, start and end are dynamic2043                    if (command.sliding) {2044                        command.begin += left;2045                        command.end += left;2046                    }2047                    MapsCreator.analyzePreSwitch(command, prethings, area, map);2048                }2049            }2050            // Add a prething at the end of all this to trigger the stretch part2051            command = {2052                "thing": "DetectWindow",2053                "x": left + (before ? section.before.width : 0), "y": 0,2054                "activate": FSM.activateSectionStretch,2055                "section": thing.section || 02056            };2057            MapsCreator.analyzePreSwitch(command, prethings, area, map);2058            // Spawn new Things that should be placed for being nearby2059            AreaSpawner.spawnArea("xInc", MapScreener.top / FSM.unitsize, (MapScreener.left + FSM.QuadsKeeper.right) / FSM.unitsize, MapScreener.bottom / FSM.unitsize, left);2060        };2061        /**2062         * Activates the "stretch" component of a stretchable section. The creation2063         * commands of the section are loaded onto the screen and have their widths2064         * set to take up the entire width of the screen. A DetectWindow is added2065         * to their immediate right that will trigger the equivalent2066         * activateSectionAfter.2067         *2068         * @param thing   An activated SectionDetector.2069         */2070        FullScreenMario.prototype.activateSectionStretch = function (thing) {2071            var FSM = thing.FSM, MapsCreator = FSM.MapsCreator, MapScreener = FSM.MapScreener, AreaSpawner = FSM.AreaSpawner, area = AreaSpawner.getArea(), map = AreaSpawner.getMap(), prethings = AreaSpawner.getPreThings(), section = area.sections[thing.section || 0], stretch = section.stretch ? section.stretch.creation : undefined, left = (thing.left + MapScreener.left) / FSM.unitsize, width = MapScreener.width / FSM.unitsize, command, i;2072            // If there is a stretch, parse each command into the current prethings array2073            if (stretch) {2074                for (i = 0; i < stretch.length; i += 1) {2075                    // A copy of the command must be used, so the original isn't modified2076                    command = FSM.proliferate({}, stretch[i]);2077                    command.x = left;2078                    // "stretch" the command by making its width equal to the screen2079                    command.width = width;2080                    MapsCreator.analyzePreSwitch(command, prethings, area, map);2081                }2082                // Add a prething at the end of all this to trigger the after part2083                command = {2084                    "thing": "DetectWindow",2085                    "x": left + width,2086                    "y": 0,2087                    "activate": FSM.activateSectionAfter,2088                    "section": thing.section || 02089                };2090                MapsCreator.analyzePreSwitch(command, prethings, area, map);2091            }2092            // Spawn the map, so new Things that should be placed will be spawned if nearby2093            AreaSpawner.spawnArea("xInc", MapScreener.top / FSM.unitsize, left + (MapScreener.width / FSM.unitsize), MapScreener.bottom / FSM.unitsize, left);2094        };2095        /**2096         * Activates the "after" component of a stretchable sectin. The creation2097         * commands of the stretch are loaded onto the screen as is.2098         *2099         * @param thing   An activated SectioNDetector.2100         */2101        FullScreenMario.prototype.activateSectionAfter = function (thing) {2102            // Since the section was passed, do the rest of things normally2103            var FSM = thing.FSM, MapsCreator = FSM.MapsCreator, MapScreener = FSM.MapScreener, AreaSpawner = FSM.AreaSpawner, area = AreaSpawner.getArea(), map = AreaSpawner.getMap(), prethings = AreaSpawner.getPreThings(), section = area.sections[thing.section || 0], left = (thing.left + MapScreener.left) / FSM.unitsize, after = section.after ? section.after.creation : undefined, command, i;2104            // If there is an after, parse each command into the current prethings array2105            if (after) {2106                for (i = 0; i < after.length; i += 1) {2107                    // A copy of the command must be used, so the original isn't modified2108                    command = FSM.proliferate({}, after[i]);2109                    // The command's x-location must be shifted by the thing's placement2110                    if (!command.x) {2111                        command.x = left;2112                    }2113                    else {2114                        command.x += left;2115                    }2116                    // For Platforms that slide around, start and end are dynamic2117                    if (command.sliding) {2118                        command.begin += left;2119                        command.end += left;2120                    }2121                    MapsCreator.analyzePreSwitch(command, prethings, area, map);2122                }2123            }2124            // Spawn the map, so new Things that should be placed will be spawned if nearby2125            AreaSpawner.spawnArea("xInc", MapScreener.top / FSM.unitsize, left + (MapScreener.right / FSM.unitsize), MapScreener.bottom / FSM.unitsize, left);2126        };2127        /* Collision functions2128        */2129        /**2130         * Function generator for the generic hitCharacterSolid callback. This is2131         * used repeatedly by ThingHittr to generate separately optimized Functions2132         * for different Thing types.2133         *2134         * @returns A Function that generates hitCharacterSolid.2135         */2136        FullScreenMario.prototype.generateHitCharacterSolid = function () {2137            /**2138             * Generic callback for when a character touches a solid. Solids that2139             * "up" kill anything that didn't cause the up, but otherwise this will2140             * normally involve the solid's collide callback being called and2141             * under/undermid checks activating.2142             *2143             * @param thing2144             * @param other2145             * @returns Whether thing is hitting other.2146             */2147            return function hitCharacterSolid(thing, other) {2148                // "Up" solids are special (they kill things that aren't their .up)2149                if (other.up && thing !== other.up) {2150                    return thing.FSM.collideCharacterSolidUp(thing, other);2151                }2152                other.collide(thing, other);2153                // If a character is bumping into the bottom, call that2154                if (thing.undermid) {2155                    if (thing.undermid.bottomBump) {2156                        thing.undermid.bottomBump(thing.undermid, thing);2157                    }2158                }2159                else if (thing.under && thing.under && thing.under.bottomBump) {2160                    thing.under.bottomBump(thing.under[0], thing);2161                }2162                // If the character is overlapping the solid, call that too2163                if (thing.checkOverlaps2164                    && thing.FSM.isCharacterOverlappingSolid(thing, other)) {2165                    thing.FSM.markOverlap(thing, other);2166                }2167            };2168        };2169        /**2170         * Function generator for the generic hitCharacterCharacter callback. This2171         * is used repeatedly by ThingHittr to generate separately optimized2172         * Functions for different Thing types.2173         *2174         * @returns A Function that generates hitCharacterCharacter.2175         */2176        FullScreenMario.prototype.generateHitCharacterCharacter = function () {2177            /**2178             * Generic callback for when a character touches another character. The2179             * first Thing's collide callback is called unless it's a player, in2180             * which the other Thing's is.2181             *2182             * @param thing2183             * @param other2184             * @returns Whether thing is hitting other.2185             */2186            return function hitCharacterCharacter(thing, other) {2187                // a Player calls the other's collide function, such as playerStar2188                if (thing.player) {2189                    if (other.collide) {2190                        return other.collide(thing, other);2191                    }2192                }2193                else if (thing.collide) {2194                    // Otherwise just use thing's collide function2195                    thing.collide(other, thing);2196                }2197            };2198        };2199        /**2200         * Collision callback used by most Items. The item's action callback will2201         * be called only if the first Thing is a player.2202         *2203         * @param thing   A Character touching other.2204         * @param other   An Item being touched by thing.2205         */2206        FullScreenMario.prototype.collideFriendly = function (thing, other) {2207            if (!thing.player || !thing.FSM.isThingAlive(other)) {2208                return;2209            }2210            if (other.action) {2211                other.action(thing, other);2212            }2213            other.death(other);2214        };2215        /**2216         * General callback for when a character touches a solid. This mostly2217         * determines if the character is on top (it should rest on the solid), to2218         * the side (it should shouldn't overlap), or undernearth (it also shouldn't2219         * overlap).2220         *2221         * @param thing   A Character touching other.2222         * @param other   A Solid being touched by thing.2223         */2224        FullScreenMario.prototype.collideCharacterSolid = function (thing, other) {2225            if (other.up === thing) {2226                return;2227            }2228            // Character on top of solid2229            if (thing.FSM.isCharacterOnSolid(thing, other)) {2230                if (other.hidden && !other.collideHidden) {2231                    return;2232                }2233                if (thing.resting !== other) {2234                    thing.resting = other;2235                    if (thing.onResting) {2236                        thing.onResting(thing, other);2237                    }2238                    if (other.onRestedUpon) {2239                        other.onRestedUpon(other, thing);2240                    }2241                }2242            }2243            else if (thing.FSM.isSolidOnCharacter(other, thing)) {2244                // Solid on top of character2245                var midx = thing.FSM.getMidX(thing);2246                if (midx > other.left && midx < other.right) {2247                    thing.undermid = other;2248                }2249                else if (other.hidden && !other.collideHidden) {2250                    return;2251                }2252                if (!thing.under) {2253                    thing.under = [other];2254                }2255                else {2256                    thing.under.push(other);2257                }2258                if (thing.player) {2259                    thing.keys.jump = false;2260                    thing.FSM.setTop(thing, other.bottom - thing.toly + other.yvel);2261                }2262                thing.yvel = other.yvel;2263            }2264            if (other.hidden && !other.collideHidden) {2265                return;2266            }2267            // Character bumping into the side of the solid2268            if (thing.resting !== other2269                && !thing.FSM.isCharacterBumpingSolid(thing, other)2270                && !thing.FSM.isThingOnThing(thing, other)2271                && !thing.FSM.isThingOnThing(other, thing)2272                && !thing.under) {2273                // Character to the left of the solid2274                if (thing.right <= other.right) {2275                    thing.xvel = Math.min(thing.xvel, 0);2276                    thing.FSM.shiftHoriz(thing, Math.max(other.left + thing.FSM.unitsize - thing.right, thing.FSM.unitsize / -2));2277                }2278                else {2279                    // Character to the right of the solid2280                    thing.xvel = Math.max(thing.xvel, 0);2281                    thing.FSM.shiftHoriz(thing, Math.min(other.right - thing.FSM.unitsize - thing.left, thing.FSM.unitsize / 2));2282                }2283                // Non-players flip horizontally2284                if (!thing.player) {2285                    if (!thing.noflip) {2286                        thing.moveleft = !thing.moveleft;2287                    }2288                    // Some items require fancy versions (e.g. Shell)2289                    if (thing.item) {2290                        thing.collide(other, thing);2291                    }2292                }2293                else if (other.actionLeft) {2294                    // Players trigger other actions (e.g. Pipe's mapExitPipeHorizontal)2295                    thing.FSM.ModAttacher.fireEvent("onPlayerActionLeft", thing, other);2296                    other.actionLeft(thing, other, other.transport);2297                }2298            }2299        };2300        /**2301         * Collision callback for a character hitting an "up" solid. If it has an2302         * onCollideUp callback, that is called; otherwise, it is killed.2303         *2304         * @param thing   A Character touching other.2305         * @param other   A Solid being touched by thing.2306         */2307        FullScreenMario.prototype.collideCharacterSolidUp = function (thing, other) {2308            if (thing.onCollideUp) {2309                thing.onCollideUp(thing, other);2310            }2311            else {2312                thing.FSM.scoreOn(thing.scoreBelow, thing);2313                thing.death(thing, 2);2314            }2315        };2316        /**2317         * Collision callback for an item hitting an "up" solid. Items just hop2318         * and switch direction.2319         *2320         * @param thing   An Item touching other.2321         * @param other   A Solid being touched by thing.2322         */2323        FullScreenMario.prototype.collideUpItem = function (thing, other) {2324            thing.FSM.animateCharacterHop(thing);2325            thing.moveleft = thing.FSM.objectToLeft(thing, other);2326        };2327        /**2328         * Collision callback for a floating coin being hit by an "up" solid. It is2329         * animated, as if it were hit as the contents of a solid.2330         *2331         * @param thing   A Coin being touched by other.2332         * @param other   A Solid touching thing.2333         */2334        FullScreenMario.prototype.collideUpCoin = function (thing, other) {2335            thing.blockparent = other;2336            thing.animate(thing, other);2337        };2338        /**2339         * Collision callback for a player hitting a regular Coin. The Coin2340         * disappears but points and Coin totals are both increased, along with2341         * the "Coin" sound being played.2342         *2343         * @param thing   A Player touching other.2344         * @param other   A Coin being touched by thing.2345         */2346        FullScreenMario.prototype.collideCoin = function (thing, other) {2347            if (!thing.player) {2348                return;2349            }2350            thing.FSM.AudioPlayer.play("Coin");2351            thing.FSM.ItemsHolder.increase("score", 200);2352            thing.FSM.ItemsHolder.increase("coins", 1);2353            thing.FSM.killNormal(other);2354        };2355        /**2356         * Collision callback for a player hitting a Star. The Star is killed, and2357         * a PlayerStarUp trigger is called on the Thing.2358         *2359         * @param thing   A Player touching other.2360         * @param other   A Star being touched by thing.2361         */2362        FullScreenMario.prototype.collideStar = function (thing, other) {2363            if (!thing.player || thing.star) {2364                return;2365            }2366            thing.FSM.playerStarUp(thing);2367            thing.FSM.ModAttacher.fireEvent("onCollideStar", thing, other);2368        };2369        /**2370         * Collision callback for a character being hit by a fireball. It will2371         * most likely be killed with an explosion unless it has the nofiredeath2372         * flag, in which case only the fireball dies.2373         *2374         * @param thing   A Character being touched by other.2375         * @param other   A Fireball touching thing.2376         */2377        FullScreenMario.prototype.collideFireball = function (thing, other) {2378            if (!thing.FSM.isThingAlive(thing) || thing.height < thing.FSM.unitsize) {2379                return;2380            }2381            if (thing.nofire) {2382                if (thing.nofire > 1) {2383                    other.death(other);2384                }2385                return;2386            }2387            if (thing.nofiredeath) {2388                thing.FSM.AudioPlayer.playLocal("Bump", thing.FSM.getMidX(other));2389                thing.death(thing);2390            }2391            else {2392                thing.FSM.AudioPlayer.playLocal("Kick", thing.FSM.getMidX(other));2393                thing.death(thing, 2);2394                thing.FSM.scoreOn(thing.scoreFire, thing);2395            }2396            other.death(other);2397        };2398        /**2399         * Collision callback for hitting a CastleFireball. The character is killed2400         * unless it has the star flag, in which case the CastleFireball is.2401         *2402         * @param thing   A Character being touched by other.2403         * @param other   A CastleFireball touching thing.2404         */2405        FullScreenMario.prototype.collideCastleFireball = function (thing, other) {2406            if (thing.star) {2407                other.death(other);2408            }2409            else {2410                thing.death(thing);2411            }2412        };2413        /**2414         * Collision callback for when a character hits a Shell. This covers various2415         * cases, such as deaths, side-to-side Shell collisions, player stomps, and2416         * so on.2417         *2418         * @param thing   A Character touching other.2419         * @param other   A Shell being touched by thing.2420         */2421        FullScreenMario.prototype.collideShell = function (thing, other) {2422            // If only one is a shell, it should be other, not thing2423            if (thing.shell) {2424                if (other.shell) {2425                    return thing.FSM.collideShellShell(thing, other);2426                }2427                return thing.FSM.collideShell(thing, other);2428            }2429            // Hitting a solid (e.g. wall) 2430            if (thing.groupType === "Solid") {2431                return thing.FSM.collideShellSolid(thing, other);2432            }2433            // Hitting a Player2434            if (thing.player) {2435                return thing.FSM.collideShellPlayer(thing, other);2436            }2437            // Assume anything else to be an enemy, which only moving shells kill2438            if (other.xvel) {2439                thing.FSM.killFlip(thing);2440                if (thing.shellspawn) {2441                    thing = thing.FSM.killSpawn(thing);2442                }2443                thing.FSM.AudioPlayer.play("Kick");2444                thing.FSM.scoreOn(thing.FSM.findScore(other.enemyhitcount), thing);2445                other.enemyhitcount += 1;2446            }2447            else {2448                thing.moveleft = thing.FSM.objectToLeft(thing, other);2449            }2450        };2451        /**2452         * Collision callback for a solid being hit by a Shell. The Shell will2453         * bounce the opposition direction.2454         *2455         * @param thing   A Solid being touched by other.2456         * @param other   A Shell touching thing.2457         */2458        FullScreenMario.prototype.collideShellSolid = function (thing, other) {2459            if (other.right < thing.right) {2460                thing.FSM.AudioPlayer.playLocal("Bump", thing.left);2461                thing.FSM.setRight(other, thing.left);2462                other.xvel = -other.speed;2463                other.moveleft = true;2464            }2465            else {2466                thing.FSM.AudioPlayer.playLocal("Bump", thing.right);2467                thing.FSM.setLeft(other, thing.right);2468                other.xvel = other.speed;2469                other.moveleft = false;2470            }2471        };2472        /**2473         * Collision callback for when a Player hits a Shell. This covers all the2474         * possible scenarios, and is much larger than common sense dictates.2475         *2476         * @param thing   A Player touching other.2477         * @param other   A Shell being touched by thing.2478         */2479        FullScreenMario.prototype.collideShellPlayer = function (thing, other) {2480            var shelltoleft = thing.FSM.objectToLeft(other, thing), playerjump = thing.yvel > 0 && (thing.bottom <= other.top + thing.FSM.unitsize * 2);2481            // Star players kill the shell no matter what2482            if (thing.star) {2483                thing.FSM.scorePlayerShell(thing, other);2484                other.death(other, 2);2485                return;2486            }2487            // If the shell is already being landed on by a Player, see if it's2488            // still being pushed to the side, or has reversed direction (is deadly)2489            if (other.landing) {2490                // Equal shelltoleft measurements: it's still being pushed2491                if (other.shelltoleft === shelltoleft) {2492                    // Tepmorarily increase the landing count of the shell; if it is 2493                    // just being started, that counts as the score hit2494                    other.landing += 1;2495                    if (other.landing === 1) {2496                        thing.FSM.scorePlayerShell(thing, other);2497                    }2498                    thing.FSM.TimeHandler.addEvent(function (other) {2499                        other.landing -= 1;2500                    }, 2, other);2501                }2502                else {2503                    // Different shelltoleft measurements: it's deadly2504                    thing.death(thing);2505                }2506                return;2507            }2508            // If the shell is being kicked by a Player, either by hitting a still2509            // shell or jumping onto an already moving one2510            if (other.xvel === 0 || playerjump) {2511                // Reset any signs of peeking from the shell2512                other.counting = 0;2513                // If the shell is standing still, make it move2514                if (other.xvel === 0) {2515                    thing.FSM.AudioPlayer.play("Kick");2516                    thing.FSM.scorePlayerShell(thing, other);2517                    if (shelltoleft) {2518                        other.moveleft = true;2519                        other.xvel = -other.speed;2520                    }2521                    else {2522                        other.moveleft = false;2523                        other.xvel = other.speed;2524                    }2525                    other.hitcount += 1;2526                    thing.FSM.TimeHandler.addEvent(function (other) {2527                        other.hitcount -= 1;2528                    }, 2, other);2529                }2530                else {2531                    // Otherwise it was moving, but should now be still2532                    other.xvel = 0;2533                }2534                if (other.peeking) {2535                    other.peeking = 0;2536                    thing.FSM.removeClass(other, "peeking");2537                    other.height -= thing.FSM.unitsize / 8;2538                    thing.FSM.updateSize(other);2539                }2540                // If a Player is landing on the shell (with movements and xvels2541                // already set), a Player should then jump up a bit2542                if (playerjump) {2543                    thing.FSM.AudioPlayer.play("Kick");2544                    if (!other.xvel) {2545                        thing.FSM.jumpEnemy(thing, other);2546                        thing.yvel *= 2;2547                        // thing.FSM.scorePlayerShell(thing, other);2548                        thing.FSM.setBottom(thing, other.top - thing.FSM.unitsize);2549                    }2550                    else {2551                    }2552                    other.landing += 1;2553                    other.shelltoleft = shelltoleft;2554                    thing.FSM.TimeHandler.addEvent(function (other) {2555                        other.landing -= 1;2556                    }, 2, other);2557                }2558            }2559            else {2560                // Since a Player is touching the shell normally, that's a death if2561                // the shell isn't moving away2562                if (!other.hitcount && ((shelltoleft && other.xvel > 0)2563                    || (!shelltoleft && other.xvel < 0))) {2564                    thing.death(thing);2565                }2566            }2567        };2568        /**2569         * Collision callback for two Shells. If one is moving, it kills the other;2570         * otherwise, they bounce off.2571         *2572         * @param thing   A Shell touching other.2573         * @param other   A Shell being touched by thing.2574         */2575        FullScreenMario.prototype.collideShellShell = function (thing, other) {2576            if (thing.xvel !== 0) {2577                if (other.xvel !== 0) {2578                    var temp = thing.xvel;2579                    thing.xvel = other.xvel;2580                    other.xvel = temp;2581                    thing.FSM.shiftHoriz(thing, thing.xvel);2582                    thing.FSM.shiftHoriz(other, other.xvel);2583                }2584                else {2585                    thing.FSM.ItemsHolder.increase("score", 500);2586                    other.death(other);2587                }2588            }2589            else {2590                thing.FSM.ItemsHolder.increase("score", 500);2591                thing.death(thing);2592            }2593        };2594        /**2595         * Collision callback for a general character hitting an enemy. This covers2596         * many general cases, most of which involve a player and an enemy.2597         *2598         * @param thing   A Character touching other.2599         * @param other   An Enemy being touched by thing.2600         */2601        FullScreenMario.prototype.collideEnemy = function (thing, other) {2602            // If either is a player, make it thing (not other)2603            if (!thing.player && other.player) {2604                return thing.FSM.collideEnemy(thing, other);2605            }2606            // Death: nothing happens2607            if (!thing.FSM.isThingAlive(thing) || !thing.FSM.isThingAlive(other)) {2608                return;2609            }2610            // Items2611            if (thing.item) {2612                if (thing.collidePrimary) {2613                    return thing.collide(other, thing);2614                }2615                return;2616            }2617            // For non-players, it's just to characters colliding: they bounce2618            if (!thing.player) {2619                thing.moveleft = thing.FSM.objectToLeft(thing, other);2620                other.moveleft = !thing.moveleft;2621                return;2622            }2623            // Player landing on top of an enemy2624            if ((thing.star && !other.nostar)2625                || (!thing.FSM.MapScreener.underwater2626                    && (!other.deadly && thing.FSM.isThingOnThing(thing, other)))) {2627                // For the sake of typing. Should be optimized during runtime.2628                var player = thing;2629                // Enforces toly (not touching means stop)2630                if (player.FSM.isCharacterAboveEnemy(player, other)) {2631                    return;2632                }2633                // A star player just kills the enemy, no matter what2634                if (player.star) {2635                    other.nocollide = true;2636                    other.death(other, 2);2637                    player.FSM.scoreOn(other.scoreStar, other);2638                    player.FSM.AudioPlayer.play("Kick");2639                }2640                else {2641                    // A non-star player kills the enemy with spawn, and hops2642                    player.FSM.setBottom(player, Math.min(player.bottom, other.top + player.FSM.unitsize));2643                    player.FSM.TimeHandler.addEvent(player.FSM.jumpEnemy, 0, player, other);2644                    other.death(other, player.star ? 2 : 0);2645                    player.FSM.addClass(player, "hopping");2646                    player.FSM.removeClasses(player, "running skidding jumping one two three");2647                    player.hopping = true;2648                    if (player.power === 1) {2649                        player.FSM.setPlayerSizeSmall(player);2650                    }2651                }2652            }2653            else if (!thing.FSM.isCharacterAboveEnemy(thing, other)) {2654                // Player being landed on by an enemy2655                thing.death(thing);2656            }2657        };2658        /**2659         * Collision callback for a character bumping into the bottom of a solid.2660         * Only players cause the solid to jump and be considered "up", though large2661         * players will kill solids that have the breakable flag on. If the solid2662         * does jump and has contents, they emerge.2663         *2664         * @param thing   A Brick being touched by other.2665         * @param other   A Character touching thing.2666         */2667        FullScreenMario.prototype.collideBottomBrick = function (thing, other) {2668            if (other.solid && !thing.solid) {2669                return thing.FSM.collideBottomBrick(other, thing);2670            }2671            if (thing.up || !other.player) {2672                return;2673            }2674            thing.FSM.AudioPlayer.play("Bump");2675            if (thing.used) {2676                return;2677            }2678            thing.up = other;2679            if (other.power > 1 && thing.breakable && !thing.contents) {2680                thing.FSM.TimeHandler.addEvent(thing.FSM.killBrick, 2, thing, other);2681                return;2682            }2683            thing.FSM.animateSolidBump(thing);2684            if (thing.contents) {2685                thing.FSM.TimeHandler.addEvent(function () {2686                    thing.FSM.animateSolidContents(thing, other);2687                    if (thing.contents !== "Coin") {2688                        thing.FSM.animateBlockBecomesUsed(thing);2689                    }2690                    else {2691                        if (thing.lastcoin) {2692                            thing.FSM.animateBlockBecomesUsed(thing);2693                        }2694                        else {2695                            thing.FSM.TimeHandler.addEvent(function () {2696                                thing.lastcoin = true;2697                            }, 245);2698                        }2699                    }2700                }, 7);2701            }2702        };2703        /**2704         * Collision callback for a Player hitting the bottom of a Block. Unused2705         * Blocks have their contents emerge (by default a Coin), while used Blocks2706         * just have a small bump noise played.2707         *2708         * @param thing   A Block being touched by other.2709         * @param other   A Player touching thing.2710         */2711        FullScreenMario.prototype.collideBottomBlock = function (thing, other) {2712            if (other.solid && !thing.solid) {2713                return thing.FSM.collideBottomBlock(other, thing);2714            }2715            if (thing.up || !other.player) {2716                return;2717            }2718            if (thing.used) {2719                thing.FSM.AudioPlayer.play("Bump");2720                return;2721            }2722            thing.used = true;2723            thing.hidden = false;2724            thing.up = other;2725            thing.FSM.animateSolidBump(thing);2726            thing.FSM.removeClass(thing, "hidden");2727            thing.FSM.switchClass(thing, "unused", "used");2728            thing.FSM.TimeHandler.addEvent(thing.FSM.animateSolidContents, 7, thing, other);2729        };2730        /**2731         * Collision callback for Vines. A player becomes "attached" to the Vine2732         * and starts climbing it, with movement set to movePlayerVine.2733         *2734         * @param thing   A Player touching other.2735         * @param other   A Solid being touched by thing.2736         */2737        FullScreenMario.prototype.collideVine = function (thing, other) {2738            if (!thing.player || thing.attachedSolid || thing.climbing) {2739                return;2740            }2741            if (thing.bottom > other.bottom + thing.FSM.unitsize * 2) {2742                return;2743            }2744            other.attachedCharacter = thing;2745            thing.attachedSolid = other;2746            thing.nofall = true;2747            thing.checkOverlaps = false;2748            thing.resting = undefined;2749            // To the left of the vine2750            if (thing.right < other.right) {2751                thing.lookleft = false;2752                thing.moveleft = false;2753                thing.attachedDirection = -1;2754                thing.FSM.unflipHoriz(thing);2755            }2756            else {2757                // To the right of the vine2758                thing.lookleft = true;2759                thing.moveleft = true;2760                thing.attachedDirection = 1;2761                thing.FSM.flipHoriz(thing);2762            }2763            thing.FSM.animateCharacterPauseVelocity(thing);2764            thing.FSM.addClass(thing, "climbing");2765            thing.FSM.removeClasses(thing, "running", "jumping", "skidding");2766            thing.FSM.TimeHandler.cancelClassCycle(thing, "running");2767            thing.FSM.TimeHandler.addClassCycle(thing, ["one", "two"], "climbing", 0);2768            thing.attachedLeft = !thing.FSM.objectToLeft(thing, other);2769            thing.attachedOff = thing.attachedLeft ? 1 : -1;2770            thing.movement = thing.FSM.movePlayerVine;2771        };2772        /**2773         * Collision callback for a character hitting a Springboard. This acts as a2774         * normal solid to non-players, and only acts as a spring if a Player is2775         * above it and moving down.2776         *2777         * @param thing   A Character touching other.2778         * @param other   A Springboard being touched by thing.2779         */2780        FullScreenMario.prototype.collideSpringboard = function (thing, other) {2781            if (thing.player && thing.yvel >= 0 && !other.tension2782                && thing.FSM.isCharacterOnSolid(thing, other)) {2783                other.tension = other.tensionSave = Math.max(thing.yvel * 0.77, thing.FSM.unitsize);2784                thing.movement = thing.FSM.movePlayerSpringboardDown;2785                thing.spring = other;2786                thing.xvel /= 2.8;2787            }2788            else {2789                thing.FSM.collideCharacterSolid(thing, other);2790            }2791        };2792        /**2793         * Collision callback for a character hitting a WaterBlocker on the top of2794         * an underwater area. It simply stops them from moving up.2795         *2796         * @param thing   A Character touching other.2797         * @param other   A WaterBlocker being touched by thing.2798         */2799        FullScreenMario.prototype.collideWaterBlocker = function (thing, other) {2800            thing.FSM.collideCharacterSolid(thing, other);2801        };2802        /**2803         * Collision callback for the DetectCollision on a flagpole at the end of an2804         * EndOutsideCastle. The Flagpole cutscene is started.2805         *2806         * @param thing   A Player touching other.2807         * @param other   A DetectCollision being touched by thing.2808         */2809        FullScreenMario.prototype.collideFlagpole = function (thing, other) {2810            if (thing.bottom > other.bottom) {2811                return;2812            }2813            thing.FSM.ScenePlayer.startCutscene("Flagpole", {2814                "player": thing,2815                "collider": other2816            });2817        };2818        /**2819         * Collision callback for a Player hitting a CastleAxe. A player and2820         * screen are paused for 140 steps (other callbacks should be animating2821         * the custcene).2822         *2823         * @param thing   A Player touching other.2824         * @param other   A CastleAxe being touched by thing.2825         */2826        FullScreenMario.prototype.collideCastleAxe = function (thing, other) {2827            if (!thing.FSM.MathDecider.compute("canPlayerTouchCastleAxe", thing, other)) {2828                return;2829            }2830            thing.FSM.ScenePlayer.startCutscene("BowserVictory", {2831                "player": thing,2832                "axe": other2833            });2834        };2835        /**2836         * Collision callback for a player hitting the DetectCollision placed next2837         * a CastleDoor in EndOutsideCastle. Things and the current time are added2838         * to cutscene settings. Infinite time goes directly to the Fireworks2839         * routine, while having non-infinite time goes to the Countdown routine.2840         *2841         * @param thing   A Player touching other.2842         * @param other   A DetectCollision being touched by thing.2843         */2844        FullScreenMario.prototype.collideCastleDoor = function (thing, other) {2845            thing.FSM.killNormal(thing);2846            if (!thing.player) {2847                return;2848            }2849            var time = thing.FSM.ItemsHolder.getItem("time");2850            thing.FSM.ScenePlayer.addCutsceneSetting("player", thing);2851            thing.FSM.ScenePlayer.addCutsceneSetting("detector", other);2852            thing.FSM.ScenePlayer.addCutsceneSetting("time", time);2853            if (time === Infinity) {2854                thing.FSM.ScenePlayer.playRoutine("Fireworks");2855            }2856            else {2857                thing.FSM.ScenePlayer.playRoutine("Countdown");2858            }2859        };2860        /**2861         * Collision callback for a player reaching a castle NPC. Things and2862         * the NPC's keys are added to cutscene settings, and the Dialog routine2863         * is played.2864         *2865         * @param thing   A Player touching other.2866         * @param other   A DetectCollision being touched by thing.2867         */2868        FullScreenMario.prototype.collideCastleNPC = function (thing, other) {2869            var keys = other.collection.npc.collectionKeys;2870            thing.FSM.ScenePlayer.addCutsceneSetting("keys", keys);2871            thing.FSM.ScenePlayer.addCutsceneSetting("player", thing);2872            thing.FSM.ScenePlayer.addCutsceneSetting("detector", other);2873            thing.FSM.ScenePlayer.playRoutine("Dialog");2874        };2875        /**2876         * Collision callback for a player hitting the transportation Platform in2877         * cloud worlds. A player collides with it as normal for solids, but if2878         * a Player is then resting on it, it becomes a normal moving platform2879         * with only horizontal momentum.2880         *2881         * @param thing   A Player touching other.2882         * @param other   A Solid being touched by thing.2883         */2884        FullScreenMario.prototype.collideTransport = function (thing, other) {2885            if (!thing.player) {2886                return;2887            }2888            thing.FSM.collideCharacterSolid(thing, other);2889            if (thing.resting !== other) {2890                return;2891            }2892            other.xvel = thing.FSM.unitsize / 2;2893            other.movement = thing.FSM.movePlatform;2894            other.collide = thing.FSM.collideCharacterSolid;2895        };2896        /**2897         * General collision callback for DetectCollision Things. The real activate2898         * callback is only hit if the Thing is a player; otherwise, an optional2899         * activateFail may be activated. The DetectCollision is then killed if it2900         * doesn't have the noActivateDeath flag.2901         *2902         * @param thing   A Character touching other.2903         * @param other   A DetectCollision being touched by thing.2904         */2905        FullScreenMario.prototype.collideDetector = function (thing, other) {2906            if (!thing.player) {2907                if (other.activateFail) {2908                    other.activateFail(thing);2909                }2910                return;2911            }2912            other.activate(thing, other);2913            if (!other.noActivateDeath) {2914                thing.FSM.killNormal(other);2915            }2916        };2917        /**2918         * Collision callback for level transports (any Thing with a .transport2919         * attribute). Depending on the transport, either the map or location are2920         * shifted to it.2921         *2922         * @param thing   A Player touching other.2923         * @param other   A Solid being touched by thing.2924         */2925        FullScreenMario.prototype.collideLevelTransport = function (thing, other) {2926            if (!thing.player) {2927                return;2928            }2929            var transport = other.transport;2930            if (typeof transport === "undefined") {2931                throw new Error("No transport given to collideLevelTransport");2932            }2933            if (transport.constructor === String) {2934                thing.FSM.setLocation(transport);2935            }2936            else if (typeof transport.map !== "undefined") {2937                if (typeof transport.location !== "undefined") {2938                    thing.FSM.setMap(transport.map, transport.location);2939                }2940                else {2941                    thing.FSM.setMap(transport.map);2942                }2943            }2944            else if (typeof transport.location !== "undefined") {2945                thing.FSM.setLocation(transport.location);2946            }2947            else {2948                throw new Error("Unknown transport type:" + transport);2949            }2950        };2951        /* Movement functions2952        */2953        /**2954         * Base, generic movement Function for simple characters. The Thing moves2955         * at a constant rate in either the x or y direction, and switches direction2956         * only if directed by the engine (e.g. when it hits a Solid)2957         *2958         * @param thing   A Character that should move.2959         * @remarks thing.speed is the only required member attribute; .direction2960         *          and .moveleft should be set by the game engine.2961         */2962        FullScreenMario.prototype.moveSimple = function (thing) {2963            // If the thing is looking away from the intended direction, flip it2964            if (thing.direction !== (thing.moveleft ? 1 : 0)) {2965                // thing.moveleft is truthy: it should now be looking to the right2966                if (thing.moveleft) {2967                    thing.xvel = -thing.speed;2968                    if (!thing.noflip) {2969                        thing.FSM.unflipHoriz(thing);2970                    }2971                }2972                else {2973                    // thing.moveleft is falsy: it should now be looking to the left2974                    thing.xvel = thing.speed;2975                    if (!thing.noflip) {2976                        thing.FSM.flipHoriz(thing);2977                    }2978                }2979                thing.direction = thing.moveleft ? 1 : 0;2980            }2981        };2982        /**2983         * Extension of the moveSimple movement Function for Things that shouldn't2984         * fall off the edge of their resting blocks2985         *2986         * @param thing   A Character that should move.2987         */2988        FullScreenMario.prototype.moveSmart = function (thing) {2989            // Start off by calling moveSimple for normal movement2990            thing.FSM.moveSimple(thing);2991            // If this isn't resting, it's the same as moveSimple2992            if (thing.yvel !== 0) {2993                return;2994            }2995            if (!thing.resting || !thing.FSM.isCharacterOnResting(thing, thing.resting)) {2996                if (thing.moveleft) {2997                    thing.FSM.shiftHoriz(thing, thing.FSM.unitsize, true);2998                }2999                else {3000                    thing.FSM.shiftHoriz(thing, -thing.FSM.unitsize, true);3001                }3002                thing.moveleft = !thing.moveleft;3003            }3004        };3005        /**3006         * Extension of the moveSimple movement Function for Things that should3007         * jump whenever they start resting.3008         *3009         * @param thing   A Character that should move.3010         * @remarks thing.jumpheight is required to know how high to jump.3011         */3012        FullScreenMario.prototype.moveJumping = function (thing) {3013            // Start off by calling moveSimple for normal movement3014            thing.FSM.moveSimple(thing);3015            // If .resting, jump!3016            if (thing.resting) {3017                thing.yvel = -Math.abs(thing.jumpheight);3018                thing.resting = undefined;3019            }3020        };3021        /**3022         * Movement Function for Characters that slide back and forth, such as3023         * HammerBros and Lakitus.3024         *3025         * @param thing   A HammerBro or Lakitu that should move.3026         * @remarks thing.counter must be set elsewhere, such as during spawning.3027         */3028        FullScreenMario.prototype.movePacing = function (thing) {3029            thing.counter += .007;3030            thing.xvel = Math.sin(Math.PI * thing.counter) / 2.1;3031        };3032        /**3033         * Movement Function for HammerBros. They movePacing, look towards the3034         * player, and have the nocollidesolid flag if they're jumping up or3035         * intentionally falling through a solid.3036         *3037         * @param thing   A HammerBro that should move.3038         */3039        FullScreenMario.prototype.moveHammerBro = function (thing) {3040            thing.FSM.movePacing(thing);3041            thing.FSM.lookTowardsPlayer(thing);3042            thing.nocollidesolid = thing.yvel < 0 || thing.falling;3043        };3044        /**3045         * Movement Function for Bowser. Bowser always faces a Player and3046         * movePaces if he's to the right of a Player, or moves to the right if3047         * he's to the left.3048         *3049         * @param thing   A Bowser that should move.3050         */3051        FullScreenMario.prototype.moveBowser = function (thing) {3052            // Facing to the right3053            if (thing.flipHoriz) {3054                // To the left of player: walk to the right3055                if (thing.FSM.objectToLeft(thing, thing.FSM.player)) {3056                    thing.FSM.moveSimple(thing);3057                }3058                else {3059                    // To the right of player: look to the left and movePacing as normal3060                    thing.moveleft = thing.lookleft = true;3061                    thing.FSM.unflipHoriz(thing);3062                    thing.FSM.movePacing(thing);3063                }3064            }3065            else {3066                // Facing to the left3067                // To the left of player: look and walk to the right3068                if (thing.FSM.objectToLeft(thing, thing.FSM.player)) {3069                    thing.moveleft = thing.lookleft = false;3070                    thing.FSM.flipHoriz(thing);3071                    thing.FSM.moveSimple(thing);3072                }3073                else {3074                    // To the right of a Player: movePacing as normal3075                    thing.FSM.movePacing(thing);3076                }3077            }3078        };3079        /**3080         * Movement Function for Bowser's spewed fire. It has a ylev stored from3081         * creation that will tell it when to stop changing its vertical3082         * velocity from this Function; otherwise, it shifts its vertical3083         * position to move to the ylev.3084         *3085         * @param thing   A BowserFire that should move.3086         */3087        FullScreenMario.prototype.moveBowserFire = function (thing) {3088            if (Math.round(thing.bottom) === Math.round(thing.ylev)) {3089                thing.movement = undefined;3090                return;3091            }3092            thing.FSM.shiftVert(thing, Math.min(Math.max(0, thing.ylev - thing.bottom), thing.FSM.unitsize));3093        };3094        /**3095         * Movement function for Things that float up and down (vertically).3096         * If the Thing has reached thing.begin or thing.end, it gradually switches3097         * thing.yvel3098         *3099         * @param thing   A Thing that should move.3100         * @remarks thing.maxvel is used as the maximum absolute speed vertically3101         * @remarks thing.begin and thing.end are used as the vertical endpoints;3102         *          .begin is the bottom and .end is the top (since begin <= end)3103         */3104        FullScreenMario.prototype.moveFloating = function (thing) {3105            // If above the endpoint:3106            if (thing.top <= thing.end) {3107                thing.yvel = Math.min(thing.yvel + thing.FSM.unitsize / 64, thing.maxvel);3108            }3109            else if (thing.bottom >= thing.begin) {3110                // If below the endpoint:3111                thing.yvel = Math.max(thing.yvel - thing.FSM.unitsize / 64, -thing.maxvel);3112            }3113            // Deal with velocities and whether a Player is resting on this3114            thing.FSM.movePlatform(thing);3115        };3116        /**3117         * Actual movement Function for Things that float sideways (horizontally).3118         * If the Thing has reached thing.begin or thing.end, it gradually switches3119         * thing.xvel.3120         *3121         * @param thing   A Thing that should move.3122         * @remarks thing.maxvel is used as the maximum absolute speed horizontally3123         * @remarks thing.begin and thing.end are used as the horizontal endpoints;3124         *          .begin is the left and .end is the right (since begin <= end)3125         */3126        FullScreenMario.prototype.moveSliding = function (thing) {3127            // If to the left of the endpoint:3128            if (thing.FSM.MapScreener.left + thing.left <= thing.begin) {3129                thing.xvel = Math.min(thing.xvel + thing.FSM.unitsize / 64, thing.maxvel);3130            }3131            else if (thing.FSM.MapScreener.left + thing.right > thing.end) {3132                // If to the right of the endpoint:3133                thing.xvel = Math.max(thing.xvel - thing.FSM.unitsize / 64, -thing.maxvel);3134            }3135            // Deal with velocities and whether a Player is resting on this3136            thing.FSM.movePlatform(thing);3137        };3138        /**3139         * Ensures thing.begin <= thing.end (so there won't be glitches pertaining3140         * to them in functions like moveFloating and moveSliding3141         *3142         * @param thing   A spawning Thing that needs its movement endpoings set.3143         */3144        FullScreenMario.prototype.setMovementEndpoints = function (thing) {3145            if (thing.begin > thing.end) {3146                var temp = thing.begin;3147                thing.begin = thing.end;3148                thing.end = temp;3149            }3150            thing.begin *= thing.FSM.unitsize;3151            thing.end *= thing.FSM.unitsize;3152        };3153        /**3154         * General movement Function for Platforms. Moves a Platform by its3155         * velocities, and checks for whether a Thing is resting on it (if so,3156         * the Thing is accordingly).3157         *3158         * @param thing   A Platform that should move.3159         */3160        FullScreenMario.prototype.movePlatform = function (thing) {3161            thing.FSM.shiftHoriz(thing, thing.xvel);3162            thing.FSM.shiftVert(thing, thing.yvel);3163            // If a Player is resting on this and this is alive, move a Player3164            if (thing === thing.FSM.player.resting && thing.FSM.player.alive) {3165                thing.FSM.setBottom(thing.FSM.player, thing.top);3166                thing.FSM.shiftHoriz(thing.FSM.player, thing.xvel);3167                // If a Player is too far to the right or left, stop that overlap3168                if (thing.FSM.player.right > thing.FSM.MapScreener.width) {3169                    thing.FSM.setRight(thing.FSM.player, thing.FSM.MapScreener.width);3170                }3171                else if (thing.FSM.player.left < 0) {3172                    thing.FSM.setLeft(thing.FSM.player, 0);3173                }3174            }3175        };3176        /**3177         * Movement Function for platforms that are in a PlatformGenerator. They3178         * have the typical movePlatform applied to them, but if they reach the3179         * bottom or top of the screen, they are shifted to the opposite side.3180         *3181         * @param thing   A Platform that should move.3182         */3183        FullScreenMario.prototype.movePlatformSpawn = function (thing) {3184            if (thing.bottom < 0) {3185                thing.FSM.setTop(thing, thing.FSM.MapScreener.bottomPlatformMax);3186            }3187            else if (thing.top > thing.FSM.MapScreener.bottomPlatformMax) {3188                thing.FSM.setBottom(thing, 0);3189            }3190            else {3191                thing.FSM.movePlatform(thing);3192                return;3193            }3194            if (thing.FSM.player3195                && thing.FSM.player.resting === thing) {3196                thing.FSM.player.resting = undefined;3197            }3198        };3199        /**3200         * Movement Function for Platforms that fall whenever rested upon by a3201         * player. Being rested upon means the Platform falls; when it reaches a3202         * terminal velocity, it switches to moveFreeFalling forever.3203         *3204         * @param thing   A Platform that should move.3205         */3206        FullScreenMario.prototype.moveFalling = function (thing) {3207            // If a Player isn't resting on this thing (any more?), ignore it3208            if (thing.FSM.player.resting !== thing) {3209                // Since a Player might have been on this thing but isn't anymore, 3210                // set the yvel to 0 just in case3211                thing.yvel = 0;3212                return;3213            }3214            // Since a Player is on this thing, start falling more3215            thing.FSM.shiftVert(thing, thing.yvel += thing.FSM.unitsize / 8);3216            thing.FSM.setBottom(thing.FSM.player, thing.top);3217            // After a velocity threshold, start always falling3218            if (thing.yvel >= (thing.fallThresholdStart || thing.FSM.unitsize * 2.8)) {3219                thing.freefall = true;3220                thing.movement = thing.FSM.moveFreeFalling;3221            }3222        };3223        /**3224         * Movement Function for Platforms that have reached terminal velocity in3225         * moveFalling and are now destined to die. The Platform will continue to3226         * accelerate towards certain death until another velocity threshold,3227         * and then switches to movePlatform to remain at that rate.3228         *3229         * @param thing   A Platform that should move.3230         */3231        FullScreenMario.prototype.moveFreeFalling = function (thing) {3232            // Accelerate downwards, increasing the thing's y-velocity3233            thing.yvel += thing.acceleration || thing.FSM.unitsize / 16;3234            thing.FSM.shiftVert(thing, thing.yvel);3235            // After a velocity threshold, stop accelerating3236            if (thing.yvel >= (thing.fallThresholdEnd || thing.FSM.unitsize * 2.1)) {3237                thing.movement = thing.FSM.movePlatform;3238            }3239        };3240        /**3241         * Movement Function for Platforms that are a part of a scale.  Nothing3242         * happens if a Platform isn't being rested and doesn't have a y-velocity.3243         * Being rested upon means the y-velocity increases, and not being rested3244         * means the y-velocity decreases: either moves the corresponding Platform3245         * "partner" in the other vertical direction. When the Platform is too far3246         * down (visually has no string left), they both fall.3247         *3248         * @param thing   A Platform that should move.3249         */3250        FullScreenMario.prototype.movePlatformScale = function (thing) {3251            // If a Player is resting on this, fall hard3252            if (thing.FSM.player.resting === thing) {3253                thing.yvel += thing.FSM.unitsize / 16;3254            }3255            else if (thing.yvel > 0) {3256                // If this still has velocity from a Player, stop or fall less3257                if (!thing.partners) {3258                    thing.yvel = 0;3259                }3260                else {3261                    thing.yvel = Math.max(thing.yvel - thing.FSM.unitsize / 16, 0);3262                }3263            }3264            else {3265                // Not being rested upon or having a yvel means nothing happens3266                return;3267            }3268            thing.tension += thing.yvel;3269            thing.FSM.shiftVert(thing, thing.yvel);3270            // The rest of the logic is for the platform's partner(s)3271            if (!thing.partners) {3272                return;3273            }3274            thing.partners.partnerPlatform.tension -= thing.yvel;3275            // If the partner has fallen off, everybody falls!3276            if (thing.partners.partnerPlatform.tension <= 0) {3277                thing.FSM.scoreOn(1000, thing);3278                thing.partners.partnerPlatform.yvel = thing.FSM.unitsize / 2;3279                thing.collide = thing.partners.partnerPlatform.collide = (thing.FSM.collideCharacterSolid);3280                thing.movement = thing.partners.partnerPlatform.movement = (thing.FSM.moveFreeFalling);3281            }3282            // The partner has yvel equal and opposite to this platform's3283            thing.FSM.shiftVert(thing.partners.partnerPlatform, -thing.yvel);3284            // This platform's string grows with its yvel3285            thing.FSM.setHeight(thing.partners.ownString, thing.partners.ownString.height + thing.yvel / thing.FSM.unitsize);3286            // The partner's string shrinks while this platform's string grows3287            thing.FSM.setHeight(thing.partners.partnerString, Math.max(thing.partners.partnerString.height - (thing.yvel / thing.FSM.unitsize), 0));3288        };3289        /**3290         * Movement Function for Vines. They are constantly growing upward, until3291         * some trigger (generally from animateEmergeVine) sets movement to3292         * undefined. If there is an attached Thing, it is moved up at the same rate3293         * as the Vine.3294         *3295         * @param thing   A Vine that should move.3296         */3297        FullScreenMario.prototype.moveVine = function (thing) {3298            thing.FSM.increaseHeight(thing, thing.speed);3299            thing.FSM.updateSize(thing);3300            if (thing.attachedSolid) {3301                thing.FSM.setBottom(thing, thing.attachedSolid.top);3302            }3303            if (thing.attachedCharacter) {3304                thing.FSM.shiftVert(thing.attachedCharacter, -thing.speed);3305            }3306        };3307        /**3308         * Movement Function for Springboards that are "pushing up" during or after3309         * being hit by a player. The Springboard changes its height based on its3310         * tension. If a Player is still on it, then a Player is given extra3311         * vertical velocity and taken off.3312         *3313         * @param thing   A Springboard that should move.3314         */3315        FullScreenMario.prototype.moveSpringboardUp = function (thing) {3316            var player = thing.FSM.player;3317            thing.FSM.reduceHeight(thing, -thing.tension, true);3318            thing.tension *= 2;3319            // If the spring height is past the normal, it's done moving3320            if (thing.height > thing.heightNormal) {3321                thing.FSM.reduceHeight(thing, (thing.height - thing.heightNormal) * thing.FSM.unitsize);3322                if (thing === player.spring) {3323                    player.yvel = thing.FSM.MathDecider.compute("springboardYvelUp", thing);3324                    player.resting = player.spring = undefined;3325                    player.movement = thing.FSM.movePlayer;3326                }3327                thing.tension = 0;3328                thing.movement = undefined;3329            }3330            else {3331                thing.FSM.setBottom(player, thing.top);3332            }3333            if (thing === player.spring) {3334                if (!thing.FSM.isThingTouchingThing(player, thing)) {3335                    player.spring = undefined;3336                    player.movement = FullScreenMario.prototype.movePlayer;3337                }3338            }3339        };3340        /**3341         * Movement Function for Shells. This actually does nothing for moving3342         * Shells (since they only interact unusually on collision). For Shells with3343         * no x-velocity, a counting variable is increased. Once it reaches 350, the3344         * shell is "peeking" visually; when it reaches 490, the Shell spawns back3345         * into its original spawner (typically Koopa or Beetle).3346         *3347         * @param thing   A Shell that should move.3348         */3349        FullScreenMario.prototype.moveShell = function (thing) {3350            if (thing.xvel !== 0) {3351                return;3352            }3353            thing.counting += 1;3354            if (thing.counting === 350) {3355                thing.peeking = 1;3356                thing.height += thing.FSM.unitsize / 8;3357                thing.FSM.addClass(thing, "peeking");3358                thing.FSM.updateSize(thing);3359            }3360            else if (thing.counting === 455) {3361                thing.peeking = 2;3362            }3363            else if (thing.counting === 490) {3364                thing.spawnSettings = {3365                    "smart": thing.smart3366                };3367                thing.FSM.killSpawn(thing);3368            }3369        };3370        /**3371         * Movement Function for Piranhas. These constantly change their height3372         * except when they reach 0 or full height (alternating direction), at which3373         * point they switch to movePiranhaLatent to wait to move in the opposite3374         * direction.3375         *3376         * @param thing   A Piranha that should move.3377         */3378        FullScreenMario.prototype.movePiranha = function (thing) {3379            var bottom = thing.bottom, height = thing.height + thing.direction, atEnd = false;3380            if (thing.resting && !thing.FSM.isThingAlive(thing.resting)) {3381                bottom = thing.constructor.prototype.height * thing.FSM.unitsize + thing.top;3382                height = Infinity;3383                thing.resting = undefined;3384            }3385            if (height <= 0) {3386                height = thing.height = 0;3387                atEnd = true;3388            }3389            else if (height >= thing.constructor.prototype.height) {3390                height = thing.height = thing.constructor.prototype.height;3391                atEnd = true;3392            }3393            thing.FSM.setHeight(thing, height);3394            thing.FSM.setBottom(thing, bottom);3395            // Canvas height should be manually reset, as PixelRendr will otherwise3396            // store the height as the initial small height from spawnPiranha...3397            thing.canvas.height = height * thing.FSM.unitsize;3398            thing.FSM.PixelDrawer.setThingSprite(thing);3399            if (atEnd) {3400                thing.counter = 0;3401                thing.movement = thing.FSM.movePiranhaLatent;3402            }3403        };3404        /**3405         * Movement Function for Piranhas that are not changing size. They wait3406         * until a counter reaches a point (and then, if their height is 0, for the3407         * player to go away) to switch back to movePiranha.3408         *3409         * @param thing   A Piranha that should move.3410         */3411        FullScreenMario.prototype.movePiranhaLatent = function (thing) {3412            var playerX = thing.FSM.getMidX(thing.FSM.player);3413            if (thing.counter >= thing.countermax3414                && (thing.height > 03415                    || playerX < thing.left - thing.FSM.unitsize * 83416                    || playerX > thing.right + thing.FSM.unitsize * 8)) {3417                thing.movement = undefined;3418                thing.direction *= -1;3419                thing.FSM.TimeHandler.addEvent(function () {3420                    thing.movement = thing.FSM.movePiranha;3421                }, 7);3422            }3423            else {3424                thing.counter += 1;3425            }3426        };3427        /**3428         * Movement Function for the Bubbles that come out of a player's mouth3429         * underwater. They die when they reach a top threshold of unitsize * 16.3430         *3431         * @param thing   A Thing that should move.3432         */3433        FullScreenMario.prototype.moveBubble = function (thing) {3434            if (thing.top < (thing.FSM.MapScreener.top + thing.FSM.unitsize * 16)) {3435                thing.FSM.killNormal(thing);3436            }3437        };3438        /**3439         * Movement Function for typical CheepCheeps, which are underwater. They3440         * move according to their native velocities except that they cannot travel3441         * above the unitsize * 16 top threshold.3442         *3443         * @param thing   A CheepCheep that should move.3444         */3445        FullScreenMario.prototype.moveCheepCheep = function (thing) {3446            if (thing.top < thing.FSM.unitsize * 16) {3447                thing.FSM.setTop(thing, thing.FSM.unitsize * 16);3448                thing.yvel *= -1;3449            }3450        };3451        /**3452         * Movement Function for flying CheepCheeps, like in bridge areas. They3453         * lose a movement Function (and therefore just fall) at a unitsize * 28 top3454         * threshold.3455         *3456         * @param thing   A CheepCheep that should move.3457         */3458        FullScreenMario.prototype.moveCheepCheepFlying = function (thing) {3459            if (thing.top < thing.FSM.unitsize * 28) {3460                thing.movement = undefined;3461                thing.nofall = false;3462            }3463        };3464        /**3465         * Movement Function for Bloopers. These switch between "squeezing" (moving3466         * down) and moving up ("unsqueezing"). They always try to unsqueeze if the3467         * player is above them.3468         *3469         * @param thing   A Blooper that should move.3470         */3471        FullScreenMario.prototype.moveBlooper = function (thing) {3472            // If a Player is dead, just drift aimlessly3473            if (!thing.FSM.isThingAlive(thing.FSM.player)) {3474                thing.xvel = thing.FSM.unitsize / -4;3475                thing.yvel = 0;3476                thing.movement = undefined;3477                return;3478            }3479            switch (thing.counter) {3480                case 56:3481                    thing.squeeze = 1;3482                    thing.counter += 1;3483                    break;3484                case 63:3485                    thing.FSM.moveBlooperSqueezing(thing);3486                    break;3487                default:3488                    thing.counter += 1;3489                    if (thing.top < thing.FSM.unitsize * 18) {3490                        thing.FSM.moveBlooperSqueezing(thing);3491                    }3492                    break;3493            }3494            if (thing.squeeze) {3495                thing.yvel = Math.max(thing.yvel + .021, .7); // going down3496            }3497            else {3498                thing.yvel = Math.min(thing.yvel - .035, -.7); // going up3499            }3500            if (thing.top > thing.FSM.unitsize * 16) {3501                thing.FSM.shiftVert(thing, thing.yvel, true);3502            }3503            if (!thing.squeeze) {3504                if (thing.FSM.player.left > thing.right + thing.FSM.unitsize * 8) {3505                    // Go to the right3506                    thing.xvel = Math.min(thing.speed, thing.xvel + thing.FSM.unitsize / 32);3507                }3508                else if (thing.FSM.player.right < thing.left - thing.FSM.unitsize * 8) {3509                    // Go to the left3510                    thing.xvel = Math.max(-thing.speed, thing.xvel - thing.FSM.unitsize / 32);3511                }3512            }3513        };3514        /**3515         * Additional movement Function for Bloopers that are "squeezing". Squeezing3516         * Bloopers travel downard at a gradual pace until they reach either the3517         * player's bottom or a threshold of unitsize * 90.3518         *3519         * @param thing   A Blooper that should move.3520         */3521        FullScreenMario.prototype.moveBlooperSqueezing = function (thing) {3522            if (thing.squeeze !== 2) {3523                thing.squeeze = 2;3524                thing.FSM.addClass(thing, "squeeze");3525                thing.FSM.setHeight(thing, 10, true, true);3526            }3527            if (thing.squeeze < 7) {3528                thing.xvel /= 1.4;3529            }3530            else if (thing.squeeze === 7) {3531                thing.xvel = 0;3532            }3533            thing.squeeze += 1;3534            if (thing.top > thing.FSM.player.bottom || thing.bottom > thing.FSM.unitsize * 91) {3535                thing.FSM.animateBlooperUnsqueezing(thing);3536            }3537        };3538        /**3539         * Movement Function for Podoboos that is only used when they are falling.3540         * Podoboo animations trigger this when they reach a certain height, and3541         * use this to determine when they should stop accelerating downward, which3542         * is their starting location.3543         *3544         * @param thing   A Podoboo that should move.3545         */3546        FullScreenMario.prototype.movePodobooFalling = function (thing) {3547            if (thing.top >= thing.starty) {3548                thing.yvel = 0;3549                thing.movement = undefined;3550                thing.FSM.unflipVert(thing);3551                thing.FSM.setTop(thing, thing.starty);3552                return;3553            }3554            if (thing.yvel >= thing.speed) {3555                thing.yvel = thing.speed;3556                return;3557            }3558            if (!thing.flipVert && thing.yvel > 0) {3559                thing.FSM.flipVert(thing);3560            }3561            thing.yvel += thing.gravity;3562        };3563        /**3564         * Movement Function for Lakitus that have finished their moveLakituInitial3565         * run. This is similar to movePacing in that it makes the Lakitu pace to3566         * left and right of a Player, and moves with a Player rather than the3567         * scrolling window.3568         *3569         * @param thing   A Lakitu that should move.3570         */3571        FullScreenMario.prototype.moveLakitu = function (thing) {3572            var player = thing.FSM.player;3573            // If a Player is moving quickly to the right, move in front and stay there3574            if (player.xvel > thing.FSM.unitsize / 83575                && player.left > thing.FSM.MapScreener.width / 2) {3576                if (thing.left < player.right + thing.FSM.unitsize * 16) {3577                    // slide to xloc3578                    thing.FSM.slideToX(thing, player.right + player.xvel + thing.FSM.unitsize * 32, player.maxspeed * 1.4);3579                    thing.counter = 0;3580                }3581            }3582            else {3583                thing.counter += .007;3584                thing.FSM.slideToX(thing, player.left + player.xvel + Math.sin(Math.PI * thing.counter) * 117, player.maxspeed * .7);3585            }3586        };3587        /**3588         * Initial entry movement Function for Lakitus. They enter by sliding across3589         * the top of the screen until they reach a Player, and then switch to3590         * their standard moveLakitu movement.3591         *3592         * @param thing   A Lakitu that should move.3593         */3594        FullScreenMario.prototype.moveLakituInitial = function (thing) {3595            if (thing.right < thing.FSM.player.left) {3596                thing.counter = 0;3597                thing.movement = thing.FSM.moveLakitu;3598                thing.movement(thing);3599                return;3600            }3601            thing.FSM.shiftHoriz(thing, -thing.FSM.unitsize);3602        };3603        /**3604         * Alternate movement Function for Lakitus. This is used when a Player3605         * reaches the ending flagpole in a level and the Lakitu just flies to the3606         * left.3607         *3608         * @param thing   A Lakitu that should move.3609         */3610        FullScreenMario.prototype.moveLakituFleeing = function (thing) {3611            thing.FSM.shiftHoriz(thing, -thing.FSM.unitsize);3612        };3613        /**3614         * Movement Function for Coins that have been animated. They move based on3615         * their yvel, and if they have a parent, die when they go below the parent.3616         *3617         * @param thing   A Coin that should move up.3618         * @param parent   A parent Solid spawning thing.3619         */3620        FullScreenMario.prototype.moveCoinEmerge = function (thing, parent) {3621            thing.FSM.shiftVert(thing, thing.yvel);3622            if (parent && thing.bottom >= thing.blockparent.bottom) {3623                thing.FSM.killNormal(thing);3624            }3625        };3626        /**3627         * Movement Function for a Player. It reacts to almost all actions that3628         * to be done, but is horribly written so that is all the documentation you3629         * get here. Sorry! Sections are labeled on the inside.3630         *3631         * @param thing   A player that should move.3632         */3633        FullScreenMario.prototype.movePlayer = function (thing) {3634            // Not jumping3635            if (!thing.keys.up) {3636                thing.keys.jump = false;3637            }3638            else if (3639            // Jumping3640            thing.keys.jump3641                && (thing.yvel <= 0 || thing.FSM.MapScreener.underwater)) {3642                if (thing.FSM.MapScreener.underwater) {3643                    thing.FSM.animatePlayerPaddling(thing);3644                    thing.FSM.removeClass(thing, "running");3645                }3646                if (thing.resting) {3647                    if (thing.resting.xvel) {3648                        thing.xvel += thing.resting.xvel;3649                    }3650                    thing.resting = undefined;3651                }3652                else {3653                    // Jumping, not resting3654                    if (!thing.jumping && !thing.FSM.MapScreener.underwater) {3655                        thing.FSM.switchClass(thing, "running skidding", "jumping");3656                    }3657                    thing.jumping = true;3658                    if (thing.power > 1 && thing.crouching) {3659                        thing.FSM.removeClass(thing, "jumping");3660                    }3661                }3662                if (!thing.FSM.MapScreener.underwater) {3663                    thing.keys.jumplev += 1;3664                    thing.FSM.MathDecider.compute("decreasePlayerJumpingYvel", thing);3665                }3666            }3667            // Crouching3668            if (thing.keys.crouch && !thing.crouching && thing.resting) {3669                if (thing.power > 1) {3670                    thing.crouching = true;3671                    thing.FSM.removeClass(thing, "running");3672                    thing.FSM.addClass(thing, "crouching");3673                    thing.FSM.setHeight(thing, 11, true, true);3674                    thing.height = 11;3675                    thing.tolyOld = thing.toly;3676                    thing.toly = thing.FSM.unitsize * 4;3677                    thing.FSM.updateBottom(thing, 0);3678                    thing.FSM.updateSize(thing);3679                }3680                // Pipe movement3681                if (thing.resting.actionTop) {3682                    thing.FSM.ModAttacher.fireEvent("onPlayerActionTop", thing, thing.resting);3683                    thing.resting.actionTop(thing, thing.resting);3684                }3685            }3686            // Running3687            if (thing.FSM.MathDecider.compute("decreasePlayerRunningXvel", thing)) {3688                if (thing.skidding) {3689                    thing.FSM.addClass(thing, "skidding");3690                }3691                else {3692                    thing.FSM.removeClass(thing, "skidding");3693                }3694            }3695            // Movement mods3696            // Slowing down3697            if (Math.abs(thing.xvel) < .14) {3698                if (thing.running) {3699                    thing.running = false;3700                    if (thing.power === 1) {3701                        thing.FSM.setPlayerSizeSmall(thing);3702                    }3703                    thing.FSM.removeClasses(thing, "running skidding one two three");3704                    thing.FSM.addClass(thing, "still");3705                    thing.FSM.TimeHandler.cancelClassCycle(thing, "running");3706                }3707            }3708            else if (!thing.running) {3709                // Not moving slowly3710                thing.running = true;3711                thing.FSM.animatePlayerRunningCycle(thing);3712                if (thing.power === 1) {3713                    thing.FSM.setPlayerSizeSmall(thing);3714                }3715            }3716            if (thing.xvel > 0) {3717                thing.xvel = Math.min(thing.xvel, thing.maxspeed);3718                if (thing.moveleft && (thing.resting || thing.FSM.MapScreener.underwater)) {3719                    thing.FSM.unflipHoriz(thing);3720                    thing.moveleft = false;3721                }3722            }3723            else if (thing.xvel < 0) {3724                thing.xvel = Math.max(thing.xvel, thing.maxspeed * -1);3725                if (!thing.moveleft && (thing.resting || thing.FSM.MapScreener.underwater)) {3726                    thing.moveleft = true;3727                    thing.FSM.flipHoriz(thing);3728                }3729            }3730            // Resting stops a bunch of other stuff3731            if (thing.resting) {3732                // Hopping3733                if (thing.hopping) {3734                    thing.hopping = false;3735                    thing.FSM.removeClass(thing, "hopping");3736                    if (thing.xvel) {3737                        thing.FSM.addClass(thing, "running");3738                    }3739                }3740                // Jumping3741                thing.keys.jumplev = thing.yvel = thing.jumpcount = 0;3742                if (thing.jumping) {3743                    thing.jumping = false;3744                    thing.FSM.removeClass(thing, "jumping");3745                    if (thing.power === 1) {3746                        thing.FSM.setPlayerSizeSmall(thing);3747                    }3748                    thing.FSM.addClass(thing, Math.abs(thing.xvel) < .14 ? "still" : "running");3749                }3750                // Paddling3751                if (thing.paddling) {3752                    thing.paddling = thing.swimming = false;3753                    thing.FSM.TimeHandler.cancelClassCycle(thing, "paddling");3754                    thing.FSM.removeClasses(thing, "paddling swim1 swim2");3755                    thing.FSM.addClass(thing, "running");3756                }3757            }3758        };3759        /**3760         * Alternate movement Function for players attached to a Vine. They may3761         * climb up or down the Vine, or jump off.3762         *3763         * @param thing   A Player that should move.3764         */3765        FullScreenMario.prototype.movePlayerVine = function (thing) {3766            var attachedSolid = thing.attachedSolid, animatedClimbing;3767            if (!attachedSolid) {3768                thing.movement = thing.FSM.movePlayer;3769                return;3770            }3771            if (thing.bottom < thing.attachedSolid.top) {3772                thing.FSM.unattachPlayer(thing, thing.attachedSolid);3773                return;3774            }3775            // Running away from the vine means dropping off3776            if (thing.keys.run !== 0 && thing.keys.run === thing.attachedDirection) {3777                // Leaving to the left3778                if (thing.attachedDirection === -1) {3779                    thing.FSM.setRight(thing, attachedSolid.left - thing.FSM.unitsize);3780                }3781                else if (thing.attachedDirection === 1) {3782                    // Leaving to the right3783                    thing.FSM.setLeft(thing, attachedSolid.right + thing.FSM.unitsize);3784                }3785                thing.FSM.unattachPlayer(thing, attachedSolid);3786                return;3787            }3788            // If a Player is moving up, simply move up3789            if (thing.keys.up) {3790                animatedClimbing = true;3791                thing.FSM.shiftVert(thing, thing.FSM.unitsize / -4);3792            }3793            else if (thing.keys.crouch) {3794                // If the thing is moving down, move down and check for unattachment3795                animatedClimbing = true;3796                thing.FSM.shiftVert(thing, thing.FSM.unitsize / 2);3797                if (thing.top > attachedSolid.bottom) {3798                    thing.FSM.unattachPlayer(thing, thing.attachedSolid);3799                }3800                return;3801            }3802            else {3803                animatedClimbing = false;3804            }3805            if (animatedClimbing && !thing.animatedClimbing) {3806                thing.FSM.addClass(thing, "animated");3807            }3808            else if (!animatedClimbing && thing.animatedClimbing) {3809                thing.FSM.removeClass(thing, "animated");3810            }3811            thing.animatedClimbing = animatedClimbing;3812            if (thing.bottom < thing.FSM.MapScreener.top - thing.FSM.unitsize * 4) {3813                thing.FSM.setLocation(thing.attachedSolid.transport);3814            }3815        };3816        /**3817         * Movement Function for players pressing down onto a Springboard. This does3818         * basically nothing except check for when a Player is off the spring or3819         * the spring is fully contracted. The former restores a Player's movement3820         * and the latter clears it (to be restored in moveSpringboardUp).3821         *3822         * @param thing   A Player that should move.3823         */3824        FullScreenMario.prototype.movePlayerSpringboardDown = function (thing) {3825            var other = thing.spring;3826            // If a Player has moved off the spring, get outta here3827            if (!thing.FSM.isThingTouchingThing(thing, other)) {3828                thing.movement = thing.FSM.movePlayer;3829                other.movement = thing.FSM.moveSpringboardUp;3830                thing.spring = undefined;3831                return;3832            }3833            // If the spring is fully contracted, go back up3834            if (other.height < thing.FSM.unitsize * 2.53835                || other.tension < thing.FSM.unitsize / 32) {3836                thing.movement = undefined;3837                other.movement = thing.FSM.moveSpringboardUp;3838                return;3839            }3840            // Make sure it's hard to slide off3841            if (thing.left < other.left + thing.FSM.unitsize * 23842                || thing.right > other.right - thing.FSM.unitsize * 2) {3843                thing.xvel /= 1.4;3844            }3845            thing.FSM.reduceHeight(other, other.tension, true);3846            other.tension /= 2;3847            thing.FSM.setBottom(thing, other.top);3848            thing.FSM.updateSize(other);3849        };3850        /* Animations3851        */3852        /**3853         * Animates a solid that has just had its bottom "bumped" by a player. It3854         * moves with a dx that is initially negative (up) and increases (to down).3855         *3856         * @param thing   A Solid being bumped.3857         */3858        FullScreenMario.prototype.animateSolidBump = function (thing) {3859            var dx = -3;3860            thing.FSM.TimeHandler.addEventInterval(function (thing) {3861                thing.FSM.shiftVert(thing, dx);3862                dx += .5;3863                if (dx === 3.5) {3864                    thing.up = undefined;3865                    return true;3866                }3867                return false;3868            }, 1, Infinity, thing);3869        };3870        /**3871         * Animates a Block to switch from unused to used.3872         *3873         * @param thing   A Block that is now marked as used.3874         */3875        FullScreenMario.prototype.animateBlockBecomesUsed = function (thing) {3876            thing.used = true;3877            thing.FSM.switchClass(thing, "unused", "used");3878        };3879        /**3880         * Animates a solid to have its contents emerge. A new Thing based on the3881         * contents is spawned directly on top of (visually behind) the solid, and3882         * has its animate callback triggered.3883         *3884         * @param thing   A Solid whose contents are coming out.3885         * @param other   A Playe triggering the Solid contents.3886         * @remarks If the contents are "Mushroom" and a large player hits the3887         *          solid, they turn into "FireFlower".3888         * @remarks For level editors, if thing.contents is falsy, the prototype3889         *          is tried (so nothing becomes Coin in Blocks).3890         */3891        FullScreenMario.prototype.animateSolidContents = function (thing, other) {3892            var output;3893            if (other && other.player && other.power > 1 && thing.contents === "Mushroom") {3894                thing.contents = "FireFlower";3895            }3896            output = thing.FSM.addThing(thing.contents || thing.constructor.prototype.contents);3897            thing.FSM.setMidXObj(output, thing);3898            thing.FSM.setTop(output, thing.top);3899            output.blockparent = thing;3900            output.animate(output, thing);3901            return output;3902        };3903        /**3904         * Animates a Brick turning into four rotating shards flying out of it. The3905         * shards have an initial x- and y-velocities, and die after 70 steps.3906         *3907         * @param thing   A destroyed Brick to be animated.3908         */3909        FullScreenMario.prototype.animateBrickShards = function (thing) {3910            var unitsize = thing.FSM.unitsize, shard, left, top, i;3911            for (i = 0; i < 4; i += 1) {3912                left = thing.left + Number(i < 2) * thing.width * unitsize - unitsize * 2;3913                top = thing.top + (i % 2) * thing.height * unitsize - unitsize * 2;3914                shard = thing.FSM.addThing("BrickShard", left, top);3915                shard.xvel = shard.speed = unitsize / 2 - unitsize * Number(i > 1);3916                shard.yvel = unitsize * -1.4 + i % 2;3917                thing.FSM.TimeHandler.addEvent(thing.FSM.killNormal, 70, shard);3918            }3919        };3920        /**3921         * Standard animation Function for Things emerging from a solid as contents.3922         * They start at inside the solid, slowly move up, then moveSimple until3923         * they're off the solid, at which point they revert to their normal3924         * movement.3925         *3926         * @param thing   A Character emerging from other.3927         * @param other   A Solid that thing is emerging from.3928         */3929        FullScreenMario.prototype.animateEmerge = function (thing, other) {3930            thing.nomove = thing.nocollide = thing.nofall = thing.alive = true;3931            thing.FSM.flipHoriz(thing);3932            thing.FSM.AudioPlayer.play("Powerup Appears");3933            thing.FSM.arraySwitch(thing, thing.FSM.GroupHolder.getGroup("Character"), thing.FSM.GroupHolder.getGroup("Scenery"));3934            thing.FSM.TimeHandler.addEventInterval(function () {3935                thing.FSM.shiftVert(thing, thing.FSM.unitsize / -8);3936                // Only stop once the bottom has reached the solid's top3937                if (thing.bottom > other.top) {3938                    return false;3939                }3940                thing.FSM.setBottom(thing, other.top);3941                thing.FSM.GroupHolder.switchMemberGroup(thing, "Scenery", "Character");3942                thing.nomove = thing.nocollide = thing.nofall = thing.moveleft = false;3943                if (thing.emergeOut) {3944                    thing.emergeOut(thing, other);3945                }3946                // Wait for movement until moveSimple moves this off the solid3947                if (thing.movement) {3948                    thing.movementOld = thing.movement;3949                    thing.movement = thing.FSM.moveSimple;3950                    thing.FSM.TimeHandler.addEventInterval(function () {3951                        if (thing.resting === other) {3952                            return false;3953                        }3954                        thing.FSM.TimeHandler.addEvent(function () {3955                            thing.movement = thing.movementOld;3956                        }, 1);3957                        return true;3958                    }, 1, Infinity);3959                }3960                return true;3961            }, 1, Infinity);3962        };3963        /**3964         * Animation Function for Coins emerging from (or being hit by) a solid. The3965         * Coin switches to the Scenery group, rotates between animation classes,3966         * moves up then down then dies, plays the "Coin" sound, and increaes the3967         * "coins" and "score" statistics.3968         *3969         * @param thing   A Coin emerging from other.3970         * @param other   A Solid thing is emerging from.3971         */3972        FullScreenMario.prototype.animateEmergeCoin = function (thing, other) {3973            thing.nocollide = thing.alive = thing.nofall = true;3974            thing.yvel -= thing.FSM.unitsize;3975            thing.FSM.switchClass(thing, "still", "anim");3976            thing.FSM.GroupHolder.switchMemberGroup(thing, "Character", "Scenery");3977            thing.FSM.AudioPlayer.play("Coin");3978            thing.FSM.ItemsHolder.increase("coins", 1);3979            thing.FSM.ItemsHolder.increase("score", 200);3980            thing.FSM.TimeHandler.cancelClassCycle(thing, "0");3981            thing.FSM.TimeHandler.addClassCycle(thing, [3982                "anim1", "anim2", "anim3", "anim4", "anim3", "anim2"3983            ], "0", 5);3984            thing.FSM.TimeHandler.addEventInterval(function () {3985                thing.FSM.moveCoinEmerge(thing, other);3986                return !thing.FSM.isThingAlive(thing);3987            }, 1, Infinity);3988            thing.FSM.TimeHandler.addEvent(function () {3989                thing.FSM.killNormal(thing);3990            }, 49);3991            thing.FSM.TimeHandler.addEvent(function () {3992                thing.yvel *= -1;3993            }, 25);3994        };3995        /**3996         * Animation Function for a Vine emerging from a solid. It continues to grow3997         * as normal via moveVine for 700 steps, then has its movement erased to3998         * stop.3999         *4000         * @param thing   A Vine emerging from other.4001         * @param other   A Solid thing is emerging from.4002         */4003        FullScreenMario.prototype.animateEmergeVine = function (thing, solid) {4004            // This allows the thing's movement to keep it on the solid4005            thing.attachedSolid = solid;4006            thing.FSM.setHeight(thing, 0);4007            thing.FSM.AudioPlayer.play("Vine Emerging");4008            thing.FSM.TimeHandler.addEvent(function () {4009                thing.nocollide = false;4010            }, 14);4011            thing.FSM.TimeHandler.addEvent(function () {4012                thing.movement = undefined;4013            }, 700);4014        };4015        /**4016         * Animates a "flicker" effect on a Thing by repeatedly toggling its hidden4017         * flag for a little while.4018         *4019         * @param thing   A Thing switching between hidden and visible.4020         * @param cleartime   How long to wait to stop the effect (by default, 49).4021         * @param interval   How many steps between hidden toggles (by default, 2).4022         */4023        FullScreenMario.prototype.animateFlicker = function (thing, cleartime, interval) {4024            cleartime = Math.round(cleartime) || 49;4025            interval = Math.round(interval) || 2;4026            thing.flickering = true;4027            thing.FSM.TimeHandler.addEventInterval(function () {4028                thing.hidden = !thing.hidden;4029                thing.FSM.PixelDrawer.setThingSprite(thing);4030            }, interval, cleartime);4031            thing.FSM.TimeHandler.addEvent(function () {4032                thing.flickering = thing.hidden = false;4033                thing.FSM.PixelDrawer.setThingSprite(thing);4034            }, cleartime * interval + 1);4035        };4036        /**4037         * Animate Function for a HammerBro to throw a hammer. The HammerBro4038         * switches to the "throwing" class, waits and throws a few repeats, then4039         * goes back to normal.4040         *4041         * @param thing   A HammerBro throwing hammers.4042         * @param count   How many times left there are to throw a hammer. If equal4043         *                to 3, a hammer will not be thrown (to mimic the pause in4044         *                the original game).4045         */4046        FullScreenMario.prototype.animateThrowingHammer = function (thing, count) {4047            if (!thing.FSM.isThingAlive(thing)) {4048                return true;4049            }4050            if (thing.FSM.isThingAlive(thing.FSM.player)4051                && thing.right >= thing.FSM.unitsize * -324052                && count !== 3) {4053                thing.FSM.switchClass(thing, "thrown", "throwing");4054            }4055            thing.FSM.TimeHandler.addEvent(function () {4056                if (!thing.FSM.isThingAlive(thing)) {4057                    return;4058                }4059                // Schedule the next animateThrowingHammer call4060                if (count > 0) {4061                    thing.FSM.TimeHandler.addEvent(thing.FSM.animateThrowingHammer, 7, thing, count - 1);4062                }4063                else {4064                    thing.FSM.TimeHandler.addEvent(thing.FSM.animateThrowingHammer, 70, thing, 7);4065                    thing.FSM.removeClass(thing, "thrown");4066                }4067                // Don't throw if a Player is dead, or this is too far to the left4068                if (!thing.FSM.isThingAlive(thing.FSM.player) || thing.right < thing.FSM.unitsize * -32) {4069                    thing.FSM.switchClass(thing, "throwing", "thrown");4070                    return;4071                }4072                // Don't throw in the third iteration (makes a gap in the hammers)4073                if (count === 3) {4074                    return;4075                }4076                // Throw by creating a hammer and visually updating4077                thing.FSM.switchClass(thing, "throwing", "thrown");4078                thing.FSM.addThing(["Hammer", {4079                        "xvel": thing.lookleft4080                            ? thing.FSM.unitsize / -1.44081                            : thing.FSM.unitsize / 1.4,4082                        "yvel": thing.FSM.unitsize * -1.4,4083                        "gravity": thing.FSM.MapScreener.gravity / 2.14084                    }], thing.left - thing.FSM.unitsize * 2, thing.top - thing.FSM.unitsize * 2);4085            }, 14);4086            return false;4087        };4088        /**4089         * Animation Function for when Bowser jumps. This will only trigger if he is4090         * facing left and a player exists. If either Bowser or a Player die, it4091         * is cancelled. He is given a negative yvel to jump, and the nocollidesolid4092         * flag is enabled as long as he is rising.4093         *4094         * @param thing   A Bowser about to jump.4095         * @returns Whether to stop the event interval occasionally triggering this.4096         */4097        FullScreenMario.prototype.animateBowserJump = function (thing) {4098            if (!thing.lookleft || !thing.FSM.isThingAlive(thing.FSM.player)) {4099                return false;4100            }4101            if (!thing.FSM.isThingAlive(thing)) {4102                return true;4103            }4104            thing.resting = undefined;4105            thing.yvel = thing.FSM.unitsize * -1.4;4106            // If there is a platform, don't bump into it4107            thing.nocollidesolid = true;4108            thing.FSM.TimeHandler.addEventInterval(function () {4109                if (thing.dead || thing.yvel > thing.FSM.unitsize) {4110                    thing.nocollidesolid = false;4111                    return true;4112                }4113                return false;4114            }, 3, Infinity);4115            return false;4116        };4117        /**4118         * Animation Function for when Bowser fires. This will only trigger if he is4119         * facing left and a player exists. If either Bowser or a Player die, it4120         * is cancelled. His mouth is closed and an animateBowserFireOpen call is4121         * scheduled to complete the animation.4122         *4123         * @param thing   A Bowser about to fire.4124         * @returns Whether to stop the event interval occasionally triggering this.4125         */4126        FullScreenMario.prototype.animateBowserFire = function (thing) {4127            if (!thing.lookleft || !thing.FSM.isThingAlive(thing.FSM.player)) {4128                return false;4129            }4130            if (!thing.FSM.isThingAlive(thing)) {4131                return true;4132            }4133            // Close the mouth4134            thing.FSM.addClass(thing, "firing");4135            thing.FSM.AudioPlayer.playLocal("Bowser Fires", thing.left);4136            // After a bit, re-open and fire4137            thing.FSM.TimeHandler.addEvent(thing.FSM.animateBowserFireOpen, 14, thing);4138            return false;4139        };4140        /**4141         * Animation Function for when Bowser actually fires. A BowserFire Thing is4142         * placed at his mouth, given a (rounded to unitsize * 8) destination y, and4143         * sent firing to a Player.4144         *4145         * @param thing   A Bowser opening its mouth.4146         * @returns Whether to stop the event interval occasionally triggering this.4147         */4148        FullScreenMario.prototype.animateBowserFireOpen = function (thing) {4149            var unitsize = thing.FSM.unitsize, ylev = Math.max(-thing.height * unitsize, Math.round(thing.FSM.player.bottom / (unitsize * 8))4150                * unitsize * 8);4151            if (!thing.FSM.isThingAlive(thing)) {4152                return true;4153            }4154            thing.FSM.removeClass(thing, "firing");4155            thing.FSM.addThing(["BowserFire", {4156                    "ylev": ylev4157                }], thing.left - thing.FSM.unitsize * 8, thing.top + thing.FSM.unitsize * 4);4158            return false;4159        };4160        /**4161         * Animation Function for when Bowser throws a Hammer. It's similar to a4162         * HammerBro, but the hammer appears on top of Bowser for a few steps4163         * before being thrown in the direction Bowser is facing (though it will4164         * only be added if facing left).4165         *4166         * @param thing   A Bowser about to throw a hammer.4167         * @returns Whether to stop the event interval occasionally triggering this.4168         */4169        FullScreenMario.prototype.animateBowserThrow = function (thing) {4170            if (!thing.lookleft || !thing.FSM.player || !thing.FSM.isThingAlive(thing.FSM.player)) {4171                return false;4172            }4173            if (!thing.FSM.isThingAlive(thing)) {4174                return true;4175            }4176            var hammer = thing.FSM.addThing("Hammer", thing.left + thing.FSM.unitsize * 2, thing.top - thing.FSM.unitsize * 2);4177            thing.FSM.TimeHandler.addEventInterval(function () {4178                if (!thing.FSM.isThingAlive(thing)) {4179                    thing.FSM.killNormal(hammer);4180                    return true;4181                }4182                thing.FSM.setTop(hammer, thing.top - thing.FSM.unitsize * 2);4183                if (thing.lookleft) {4184                    thing.FSM.setLeft(hammer, thing.left + thing.FSM.unitsize * 2);4185                }4186                else {4187                    thing.FSM.setLeft(hammer, thing.right - thing.FSM.unitsize * 2);4188                }4189                return true;4190            }, 1, 14);4191            thing.FSM.TimeHandler.addEvent(function () {4192                hammer.xvel = thing.FSM.unitsize * 1.17;4193                hammer.yvel = thing.FSM.unitsize * -2.1;4194                // hammer.gravity = thing.FSM.MapScreener.gravity / 1.4;4195                if (thing.lookleft) {4196                    hammer.xvel *= -1;4197                }4198            }, 14);4199            return false;4200        };4201        /**4202         * Animation Function for when Bowser freezes upon a Player hitting a4203         * CastleAxe. Velocity and movement are paused, and the Bowser is added to4204         * the current cutscene's settings.4205         *4206         * @param thing   A Bowser that has just been killed.4207         * @remarks This is triggered as Bowser's killonend property.4208         */4209        FullScreenMario.prototype.animateBowserFreeze = function (thing) {4210            thing.nofall = true;4211            thing.nothrow = true;4212            thing.movement = undefined;4213            thing.dead = true;4214            thing.FSM.animateCharacterPauseVelocity(thing);4215            thing.FSM.ScenePlayer.addCutsceneSetting("bowser", thing);4216            thing.FSM.TimeHandler.addEvent(function () {4217                thing.nofall = false;4218            }, 70);4219        };4220        /**4221         * Animation Function for a standard jump, such as what HammerBros do. The4222         * jump may be in either up or down, chosen at random by the NumberMaker.4223         * Steps are taken to ensure the Thing does not collide at improper points4224         * during the jump.4225         *4226         * @param thing   A HammerBro about to jump.4227         * @returns Whether to stop the event interval occasionally triggering this.4228         */4229        FullScreenMario.prototype.animateJump = function (thing) {4230            // Finish4231            if (!thing.FSM.isThingAlive(thing) || !thing.FSM.isThingAlive(thing.FSM.player)) {4232                return true;4233            }4234            // Skip4235            if (!thing.resting) {4236                return false;4237            }4238            // Jump up?4239            if (thing.FSM.MapScreener.floor - (thing.bottom / thing.FSM.unitsize) >= 304240                && thing.resting.title !== "Floor"4241                && thing.FSM.NumberMaker.randomBoolean()) {4242                thing.falling = true;4243                thing.yvel = thing.FSM.unitsize * -.7;4244                thing.FSM.TimeHandler.addEvent(function () {4245                    thing.falling = false;4246                }, 42);4247            }4248            else {4249                // Jump down4250                thing.nocollidesolid = true;4251                thing.yvel = thing.FSM.unitsize * -2.1;4252                thing.FSM.TimeHandler.addEvent(function () {4253                    thing.nocollidesolid = false;4254                }, 42);4255            }4256            thing.resting = undefined;4257            return false;4258        };4259        /**4260         * Animation Function for Bloopers starting to "unsqueeze". The "squeeze"4261         * class is removed, their height is reset to 12, and their counter reset.4262         *4263         * @param thing   An unsqueezing Blooper.4264         */4265        FullScreenMario.prototype.animateBlooperUnsqueezing = function (thing) {4266            thing.counter = 0;4267            thing.squeeze = 0;4268            thing.FSM.removeClass(thing, "squeeze");4269            thing.FSM.setHeight(thing, 12, true, true);4270        };4271        /**4272         * Animation Function for Podoboos jumping up. Their top is recorded and a4273         * large negative yvel is given; after the jumpheight number of steps, they4274         * fall back down.4275         *4276         * @param thing   A Podoboo jumping up.4277         */4278        FullScreenMario.prototype.animatePodobooJumpUp = function (thing) {4279            thing.starty = thing.top;4280            thing.yvel = thing.speed * -1;4281            thing.FSM.TimeHandler.addEvent(thing.FSM.animatePodobooJumpDown, thing.jumpHeight, thing);4282        };4283        /**4284         * Animation Function for when a Podoboo needs to stop jumping. It obtains4285         * the movePodobooFalling movement to track its descent.4286         *4287         * @param thing   A Podoboo jumping down.4288         */4289        FullScreenMario.prototype.animatePodobooJumpDown = function (thing) {4290            thing.movement = thing.FSM.movePodobooFalling;4291        };4292        /**4293         * Animation Function for a Lakitu throwing a SpinyEgg. The Lakitu hides4294         * behind its cloud ("hiding" class), waits 21 steps, then throws an egg up4295         * and comes out of "hiding".4296         *4297         * @param thing   A Lakitu throwing a Spiny.4298         * @returns Whether to stop the event interval occasionally triggering this.4299         */4300        FullScreenMario.prototype.animateLakituThrowingSpiny = function (thing) {4301            if (thing.fleeing || !thing.FSM.isThingAlive(thing)) {4302                return true;4303            }4304            thing.FSM.switchClass(thing, "out", "hiding");4305            thing.FSM.TimeHandler.addEvent(function () {4306                if (thing.dead) {4307                    return;4308                }4309                var spawn = thing.FSM.addThing("SpinyEgg", thing.left, thing.top);4310                spawn.yvel = thing.FSM.unitsize * -2.1;4311                thing.FSM.switchClass(thing, "hiding", "out");4312            }, 21);4313        };4314        /**4315         * Animation Function for when a SpinyEgg hits the ground. The SpinyEgg is4316         * killed and a Spiny is put in its place, moving towards a Player.4317         *4318         * @param thing   A SpinyEgg hatching into a Spiny.4319         */4320        FullScreenMario.prototype.animateSpinyEggHatching = function (thing) {4321            if (!thing.FSM.isThingAlive(thing)) {4322                return;4323            }4324            var spawn = thing.FSM.addThing("Spiny", thing.left, thing.top - thing.yvel);4325            spawn.moveleft = thing.FSM.objectToLeft(thing.FSM.player, spawn);4326            thing.FSM.killNormal(thing);4327        };4328        /**4329         * Animation Function for when a Fireball emerges from a Player. All that4330         * happens is the "Fireball" sound plays.4331         *4332         * @param thing   A Fireball emerging from a Player.4333         */4334        FullScreenMario.prototype.animateFireballEmerge = function (thing) {4335            thing.FSM.AudioPlayer.play("Fireball");4336        };4337        /**4338         * Animation Function for when a Fireball explodes. It is deleted and,4339         * unless big is === 2 (as this is used as a kill Function), a Firework is4340         * put in its place.4341         *4342         * @param thing   An exploding Fireball.4343         * @param big   The "level" of death this is (a 2 implies this is a sudden4344         *              death, without animations).4345         */4346        FullScreenMario.prototype.animateFireballExplode = function (thing, big) {4347            thing.nocollide = true;4348            thing.FSM.killNormal(thing);4349            if (big === 2) {4350                return;4351            }4352            var output = thing.FSM.addThing("Firework");4353            thing.FSM.setMidXObj(output, thing);4354            thing.FSM.setMidYObj(output, thing);4355            output.animate(output);4356        };4357        /**4358         * Animation Function for a Firework, triggered immediately upon spawning.4359         * The Firework cycles between "n1" through "n3", then dies.4360         *4361         * @param thing   An exploding Firework.4362         */4363        FullScreenMario.prototype.animateFirework = function (thing) {4364            var name = thing.className + " n", i;4365            for (i = 0; i < 3; i += 1) {4366                thing.FSM.TimeHandler.addEvent(function (i) {4367                    thing.FSM.setClass(thing, name + (i + 1).toString());4368                }, i * 7, i);4369            }4370            thing.FSM.AudioPlayer.play("Firework");4371            thing.FSM.TimeHandler.addEvent(function () {4372                thing.FSM.killNormal(thing);4373            }, i * 7);4374        };4375        /**4376         * Animation Function for a Cannon outputting a BulletBill. This will only4377         * happen if the Cannon isn't within 8 units of a Player. The spawn flies4378         * at a constant rate towards a Player.4379         *4380         * @param thing   A firing Cannon.4381         */4382        FullScreenMario.prototype.animateCannonFiring = function (thing) {4383            if (!thing.FSM.isThingAlive(thing)) {4384                return;4385            }4386            // Don't fire if Player is too close4387            if (thing.FSM.player.right > (thing.left - thing.FSM.unitsize * 8)4388                && thing.FSM.player.left < (thing.right + thing.FSM.unitsize * 8)) {4389                return;4390            }4391            var spawn = thing.FSM.ObjectMaker.make("BulletBill");4392            if (thing.FSM.objectToLeft(thing.FSM.player, thing)) {4393                spawn.direction = 1;4394                spawn.moveleft = true;4395                spawn.xvel *= -1;4396                thing.FSM.flipHoriz(spawn);4397                thing.FSM.addThing(spawn, thing.left, thing.top);4398            }4399            else {4400                thing.FSM.addThing(spawn, thing.left + thing.width, thing.top);4401            }4402            thing.FSM.AudioPlayer.playLocal("Bump", thing.right);4403        };4404        /**4405         * Animation Function for a fiery player throwing a Fireball. A player may4406         * only do so if fewer than 2 other thrown Fireballs exist. A new Fireball4407         * is created in front of where a Player is facing and are sent bouncing4408         * away.4409         *4410         * @param thing   A Player throwing a fireball.4411         */4412        FullScreenMario.prototype.animatePlayerFire = function (thing) {4413            if (thing.numballs >= 2) {4414                return;4415            }4416            var xloc = thing.moveleft4417                ? (thing.left - thing.FSM.unitsize / 4)4418                : (thing.right + thing.FSM.unitsize / 4), ball = thing.FSM.ObjectMaker.make("Fireball", {4419                "moveleft": thing.moveleft,4420                "speed": thing.FSM.unitsize * 1.75,4421                "jumpheight": thing.FSM.unitsize * 1.56,4422                "gravity": thing.FSM.MapScreener.gravity * 1.56,4423                "yvel": thing.FSM.unitsize,4424                "movement": thing.FSM.moveJumping4425            });4426            thing.FSM.addThing(ball, xloc, thing.top + thing.FSM.unitsize * 8);4427            ball.animate(ball);4428            ball.onDelete = function () {4429                thing.numballs -= 1;4430            };4431            thing.numballs += 1;4432            thing.FSM.addClass(thing, "firing");4433            thing.FSM.TimeHandler.addEvent(function () {4434                thing.FSM.removeClass(thing, "firing");4435            }, 7);4436        };4437        /**4438         * Animation Function that regularly spings CastleFireballs around their4439         * parent CastleBlock. The CastleBlock's location and angle determine the4440         * location of each CastleFireball, and its dt and direction determine how4441         * the angle is changed for the next call.4442         *4443         * @param thing   A CastleBlock with CastleFireballs around it.4444         * @param balls   CastleFireballs rotating from thing's center.4445         */4446        FullScreenMario.prototype.animateCastleBlock = function (thing, balls) {4447            var midx = thing.EightBitter.getMidX(thing), midy = thing.EightBitter.getMidY(thing), ax = Math.cos(thing.angle * Math.PI) * thing.FSM.unitsize * 4, ay = Math.sin(thing.angle * Math.PI) * thing.FSM.unitsize * 4, i;4448            for (i = 0; i < balls.length; i += 1) {4449                thing.FSM.setMidX(balls[i], midx + ax * i);4450                thing.FSM.setMidY(balls[i], midy + ay * i);4451            }4452            thing.angle += thing.dt * thing.direction;4453        };4454        /**4455         * Animation Function to close a CastleBridge when a Player triggers its4456         * killonend after hitting the CastleAxe in EndInsideCastle. Its width is4457         * reduced repeatedly on an interval until it's 0.4458         *4459         * @param thing   A CastleBridge opening from a CastleAxe's trigger.4460         * @remarks This is triggered as the killonend property of the bridge.4461         */4462        FullScreenMario.prototype.animateCastleBridgeOpen = function (thing) {4463            thing.FSM.ScenePlayer.playRoutine("CastleBridgeOpen", thing);4464        };4465        /**4466         * Animation Function for when a CastleChain opens, which just delays a4467         * killNormal call for 7 steps.4468         *4469         * @param thing   A CastleChain opening from a CastleAxe's trigger.4470         * @remarks This is triggered as the killonend property of the chain.4471         */4472        FullScreenMario.prototype.animateCastleChainOpen = function (thing) {4473            thing.FSM.TimeHandler.addEvent(thing.FSM.killNormal, 3, thing);4474        };4475        /**4476         * Animation Function for when a Player paddles underwater. Any previous4477         * Any previous paddling classes and cycle are removed, and a new one is4478         * added that, when it finishes, remnoves a Player's paddlingCycle as4479         * well.4480         *4481         * @param thing   A Player paddling in water.4482         */4483        FullScreenMario.prototype.animatePlayerPaddling = function (thing) {4484            if (!thing.paddlingCycle) {4485                thing.FSM.removeClasses(thing, "skidding paddle1 paddle2 paddle3 paddle4 paddle5");4486                thing.FSM.addClass(thing, "paddling");4487                thing.FSM.TimeHandler.cancelClassCycle(thing, "paddlingCycle");4488                thing.FSM.TimeHandler.addClassCycle(thing, [4489                    "paddle1", "paddle2", "paddle3", "paddle2", "paddle1",4490                    function () { return thing.paddlingCycle = false; }4491                ], "paddlingCycle", 7);4492            }4493            thing.paddling = thing.paddlingCycle = thing.swimming = true;4494            thing.yvel = thing.FSM.unitsize * -.84;4495        };4496        /**4497         * Animation Function for when a player lands to reset size and remove4498         * hopping (and if underwater, paddling) classes. The mod event is fired.4499         *4500         * @param thing   A Player landing on a Solid.4501         */4502        FullScreenMario.prototype.animatePlayerLanding = function (thing) {4503            if (thing.crouching && thing.power > 1) {4504                thing.FSM.setHeight(thing, 11, true, true);4505            }4506            if (thing.FSM.hasClass(thing, "hopping")) {4507                thing.FSM.switchClass(thing, "hopping", "jumping");4508            }4509            if (thing.FSM.MapScreener.underwater) {4510                thing.FSM.removeClass(thing, "paddling");4511            }4512            thing.FSM.ModAttacher.fireEvent("onPlayerLanding", thing, thing.resting);4513        };4514        /**4515         * Animation Function for when a Player moves off a resting solid. It4516         * sets resting to undefined, and if underwater, switches the "running" and4517         * "paddling" classes.4518         *4519         * @param thing   A Player moving off a resting Solid.4520         */4521        FullScreenMario.prototype.animatePlayerRestingOff = function (thing) {4522            thing.resting = undefined;4523            if (thing.FSM.MapScreener.underwater) {4524                thing.FSM.switchClass(thing, "running", "paddling");4525            }4526        };4527        /**4528         * Animation Function for when a player breathes a underwater. This creates4529         * a Bubble, which slowly rises to the top of the screen.4530         *4531         * @param thing   An underwater Player.4532         */4533        FullScreenMario.prototype.animatePlayerBubbling = function (thing) {4534            thing.FSM.addThing("Bubble", thing.right, thing.top);4535        };4536        /**4537         * Animation Function to give a Player a cycle of running classes. The4538         * cycle auto-updates its time as a function of how fast a Player is4539         * moving relative to its maximum speed.4540         *4541         * @param thing   A running player.4542         */4543        FullScreenMario.prototype.animatePlayerRunningCycle = function (thing) {4544            thing.FSM.switchClass(thing, "still", "running");4545            thing.running = thing.FSM.TimeHandler.addClassCycle(thing, [4546                "one", "two", "three", "two"4547            ], "running", function () {4548                return 5 + Math.ceil(thing.maxspeedsave - Math.abs(thing.xvel));4549            });4550        };4551        /**4552         * Completely pauses a Thing by setting its velocities to zero and disabling4553         * it from falling, colliding, or moving. Its old attributes for those are4554         * saved so thingResumeVelocity may restore them.4555         *4556         * @param thing   A Character being forzen in place.4557         * @param keepMovement   Whether to keep movement instead of wiping it4558         *                       (by default, false).4559         */4560        FullScreenMario.prototype.animateCharacterPauseVelocity = function (thing, keepMovement) {4561            thing.xvelOld = thing.xvel || 0;4562            thing.yvelOld = thing.yvel || 0;4563            thing.nofallOld = thing.nofall || false;4564            thing.nocollideOld = thing.nocollide || false;4565            thing.movementOld = thing.movement || thing.movementOld;4566            thing.nofall = thing.nocollide = true;4567            thing.xvel = thing.yvel = 0;4568            if (!keepMovement) {4569                thing.movement = undefined;4570            }4571        };4572        /**4573         * Resumes a Thing's velocity and movements after they were paused by4574         * thingPauseVelocity.4575         *4576         * @param thing   A Character being unfrozen.4577         * @param noVelocity   Whether to skip restoring the Thing's velocity4578         *                     (by default, false).4579         */4580        FullScreenMario.prototype.animateCharacterResumeVelocity = function (thing, noVelocity) {4581            if (!noVelocity) {4582                thing.xvel = thing.xvelOld || 0;4583                thing.yvel = thing.yvelOld || 0;4584            }4585            thing.movement = thing.movementOld || thing.movement;4586            thing.nofall = thing.nofallOld || false;4587            thing.nocollide = thing.nocollideOld || false;4588        };4589        /**4590         * Animation Function for when a player hops on an enemy. Resting is set to4591         * undefined, and a small vertical yvel is given.4592         *4593         * @param thing   A Character hopping up.4594         */4595        FullScreenMario.prototype.animateCharacterHop = function (thing) {4596            thing.resting = undefined;4597            thing.yvel = thing.FSM.unitsize * -1.4;4598        };4599        /**4600         * Animation Function to start a player transferring through a Pipe. This is4601         * generic for entrances and exists horizontally and vertically: movement4602         * and velocities are frozen, size is reset, and the piping flag enabled.4603         * a Player is also moved into the Scenery group to be behind the Pipe.4604         *4605         * @param thing   A Player entering a Pipe.4606         */4607        FullScreenMario.prototype.animatePlayerPipingStart = function (thing) {4608            thing.nocollide = thing.nofall = thing.piping = true;4609            thing.xvel = thing.yvel = 0;4610            thing.movementOld = thing.movement;4611            thing.movement = undefined;4612            if (thing.power > 1) {4613                thing.FSM.animatePlayerRemoveCrouch(thing);4614                thing.FSM.setPlayerSizeLarge(thing);4615            }4616            else {4617                thing.FSM.setPlayerSizeSmall(thing);4618            }4619            thing.FSM.removeClasses(thing, "jumping running crouching");4620            thing.FSM.AudioPlayer.clearTheme();4621            thing.FSM.TimeHandler.cancelAllCycles(thing);4622            thing.FSM.GroupHolder.switchMemberGroup(thing, "Character", "Scenery");4623        };4624        /**4625         * Animation Function for when a player is done passing through a Pipe. This4626         * is abstracted for exits both horizontally and vertically, typically after4627         * an area has just been entered.4628         *4629         * @param thing   A Player completing a pass through a Pipe.4630         */4631        FullScreenMario.prototype.animatePlayerPipingEnd = function (thing) {4632            thing.movement = thing.movementOld;4633            thing.nocollide = thing.nofall = thing.piping = false;4634            thing.FSM.AudioPlayer.resumeTheme();4635            thing.FSM.GroupHolder.switchMemberGroup(thing, "Scenery", "Character");4636        };4637        /**4638         * Animation Function for when a player is hopping off a pole. It hops off4639         * and faces the opposite direction.4640         *4641         * @param thing   A Player moving a way from a pole.4642         * @param doRun   Whether a Player should have a running cycle added4643         *                added immediately, such as during cutscenes (by4644         *                default, false).4645         */4646        FullScreenMario.prototype.animatePlayerOffPole = function (thing, doRun) {4647            thing.FSM.removeClasses(thing, "climbing running");4648            thing.FSM.addClass(thing, "jumping");4649            thing.xvel = 1.4;4650            thing.yvel = -.7;4651            thing.nocollide = thing.nofall = false;4652            thing.gravity = thing.FSM.MapScreener.gravity / 14;4653            thing.FSM.TimeHandler.addEvent(function () {4654                thing.movement = thing.FSM.movePlayer;4655                thing.gravity = thing.FSM.MapScreener.gravity;4656                thing.FSM.unflipHoriz(thing);4657                if (doRun) {4658                    thing.FSM.animatePlayerRunningCycle(thing);4659                }4660            }, 21);4661        };4662        /**4663         * Animation Function for when a player must hop off a Vine during an area's4664         * opening cutscene. A player switches sides, waits 14 steps, then calls4665         * animatePlayerOffPole.4666         *4667         * @param thing   A Player moving away from a Vine.4668         */4669        FullScreenMario.prototype.animatePlayerOffVine = function (thing) {4670            thing.FSM.flipHoriz(thing);4671            thing.FSM.shiftHoriz(thing, (thing.width - 1) * thing.FSM.unitsize);4672            thing.FSM.TimeHandler.addEvent(thing.FSM.animatePlayerOffPole, 14, thing);4673        };4674        /* Appearance utilities4675        */4676        /**4677         * Makes one Thing look towards another, chainging lookleft and moveleft in4678         * the process.4679         *4680         * @param thing   A Character looking towards other.4681         * @param other   A Thing being looked at by thing.4682         */4683        FullScreenMario.prototype.lookTowardsThing = function (thing, other) {4684            // Case: other is to the left4685            if (other.right <= thing.left) {4686                thing.lookleft = true;4687                thing.moveleft = true;4688                thing.FSM.unflipHoriz(thing);4689            }4690            else if (other.left >= thing.right) {4691                // Case: other is to the right4692                thing.lookleft = false;4693                thing.moveleft = false;4694                thing.FSM.flipHoriz(thing);4695            }4696        };4697        /**4698         * Makes one Thing look towards a Player, chainging lookleft and moveleft4699         * in the process.4700         *4701         * @param thing   A Character looking towards the Player.4702         * @param big   Whether to always change lookleft and moveleft,4703         *              even if lookleft is already accurate (by4704         *              default, false).4705         */4706        FullScreenMario.prototype.lookTowardsPlayer = function (thing, big) {4707            // Case: Player is to the left4708            if (thing.FSM.player.right <= thing.left) {4709                if (!thing.lookleft || big) {4710                    thing.lookleft = true;4711                    thing.moveleft = false;4712                    thing.FSM.unflipHoriz(thing);4713                }4714            }4715            else if (thing.FSM.player.left >= thing.right) {4716                // Case: Player is to the right4717                if (thing.lookleft || big) {4718                    thing.lookleft = false;4719                    thing.moveleft = true;4720                    thing.FSM.flipHoriz(thing);4721                }4722            }4723        };4724        /* Death functions4725        */4726        /**4727         * Standard Function to kill a Thing, which means marking it as dead and4728         * clearing its numquads, resting, movement, and cycles. It will later be4729         * marked as gone by its maintain* Function (Solids or Characters).4730         *4731         * @param thing   A Thing to kill.4732         */4733        FullScreenMario.prototype.killNormal = function (thing) {4734            if (!thing) {4735                return;4736            }4737            thing.hidden = thing.dead = true;4738            thing.alive = false;4739            thing.numquads = 0;4740            thing.movement = undefined;4741            if (this.hasOwnProperty("resting")) {4742                thing.resting = undefined;4743            }4744            if (thing.FSM) {4745                thing.FSM.TimeHandler.cancelAllCycles(thing);4746            }4747            thing.FSM.ModAttacher.fireEvent("onKillNormal", thing);4748        };4749        /**4750         * Death Function commonly called on characters to animate a small flip4751         * before killNormal is called.4752         *4753         * @param thing   A Thing to kill.4754         * @param extra   How much time to wait beyond the standard 70 steps4755         *                before calling killNormal (by default, 0).4756         */4757        FullScreenMario.prototype.killFlip = function (thing, extra) {4758            if (extra === void 0) { extra = 0; }4759            thing.FSM.flipVert(thing);4760            if (thing.bottomBump) {4761                thing.bottomBump = undefined;4762            }4763            thing.nocollide = thing.dead = true;4764            thing.speed = thing.xvel = 0;4765            thing.nofall = false;4766            thing.resting = thing.movement = undefined;4767            thing.yvel = -thing.FSM.unitsize;4768            thing.FSM.TimeHandler.addEvent(thing.FSM.killNormal, 70 + extra, thing);4769        };4770        /**4771         * Kill Function to replace a Thing with a spawned Thing, determined by the4772         * thing's spawnType, in the same location.4773         *4774         * @param thing    A Thing to kill.4775         * @param big   Whether this should skip creating the spawn (by default,4776         *              false).4777         */4778        FullScreenMario.prototype.killSpawn = function (thing, big) {4779            if (big) {4780                thing.FSM.killNormal(thing);4781                return;4782            }4783            if (!thing.spawnType) {4784                throw new Error("Thing " + thing.title + " has no .spawnType.");4785            }4786            var spawn = thing.FSM.ObjectMaker.make(thing.spawnType, thing.spawnSettings || {});4787            thing.FSM.addThing(spawn);4788            thing.FSM.setBottom(spawn, thing.bottom);4789            thing.FSM.setMidXObj(spawn, thing);4790            thing.FSM.killNormal(thing);4791            return spawn;4792        };4793        /**4794         * A kill Function similar to killSpawn but more configurable. A spawned4795         * Thing is created with the given attributes and copies over any specified4796         * attributes from the original Thing.4797         *4798         * @param thing   A Thing to kill.4799         * @param title   The type of new Thing to create, such as "Goomba".4800         * @param attributes   An optional object to pass in to the ObjectMaker.make4801         *                     call (by default, {}).4802         * @param attributesCopied   An optional listing of attributes to copy from4803         *                           the original Thing (by default, none).4804         */4805        FullScreenMario.prototype.killReplace = function (thing, title, attributes, attributesCopied) {4806            if (attributes === void 0) { attributes = {}; }4807            var spawn, i;4808            if (typeof attributesCopied !== "undefined") {4809                for (i = 0; i < attributesCopied.length; i += 1) {4810                    attributes[attributesCopied[i]] = thing[attributesCopied[i]];4811                }4812            }4813            spawn = thing.FSM.ObjectMaker.make(title, attributes);4814            if (thing.flipHoriz) {4815                thing.FSM.flipHoriz(spawn);4816            }4817            if (thing.flipVert) {4818                thing.FSM.flipVert(spawn);4819            }4820            thing.FSM.addThing(spawn, thing.left, thing.top);4821            thing.FSM.killNormal(thing);4822            return spawn;4823        };4824        /**4825         * Kill Function for Goombas. If big isn't specified, it replaces the4826         * killed Goomba with a DeadGoomba via killSpawn.4827         *4828         * @param thing   A Goomba to kill.4829         * @param big   Whether to call killFlip on the Thing instead of4830         *              killSpawn, such as when a Shell hits it.4831         */4832        FullScreenMario.prototype.killGoomba = function (thing, big) {4833            if (big) {4834                thing.FSM.killFlip(thing);4835                return;4836            }4837            thing.FSM.killSpawn(thing);4838        };4839        /**4840         * Kill Function for Koopas. Jumping and floating Koopas are replacing with4841         * an equivalent Koopa that's just walking, while walking Koopas become4842         * Shells.4843         *4844         * @param thing   A Koopa to kill.4845         * @param big   Whether shells should be immediately killed.4846         * @remarks This isn't called when a Shell hits a Koopa.4847         */4848        FullScreenMario.prototype.killKoopa = function (thing, big) {4849            var spawn;4850            if (thing.jumping || thing.floating) {4851                spawn = thing.FSM.killReplace(thing, "Koopa", undefined, ["smart", "direction", "moveleft"]);4852                spawn.xvel = spawn.moveleft ? -spawn.speed : spawn.speed;4853            }4854            else {4855                spawn = thing.FSM.killToShell(thing, Number(big));4856            }4857            return spawn;4858        };4859        /**4860         * Kill Function for Lakitus. If this is the last Lakitu in Characters,4861         * a new one is scheduled to be spawned at the same y-position.4862         *4863         * @param thing   A Lakitu to kill.4864         */4865        FullScreenMario.prototype.killLakitu = function (thing) {4866            var characters = thing.FSM.GroupHolder.getGroup("Character"), i;4867            thing.FSM.killFlip(thing);4868            thing.FSM.MapScreener.lakitu = undefined;4869            // If any other Lakitu exists after killNormal, killLakitu is done4870            for (i = 0; i < characters.length; i += 1) {4871                if (characters[i].title === "Lakitu") {4872                    thing.FSM.MapScreener.lakitu = characters[i];4873                    return;4874                }4875            }4876            // The next Lakitu is spawned ~5 seconds later, give or take4877            thing.FSM.TimeHandler.addEvent(thing.FSM.addThing.bind(thing.FSM), 350, "Lakitu", thing.FSM.MapScreener.right, thing.top);4878        };4879        /**4880         * Kill Function for Bowsers. In reality this is only called when a Player4881         * Fireballs him or all NPCs are to be killed. It takes five Fireballs to4882         * killFlip a Bowser, which scores 5000 points.4883         *4884         * @param thing   A Bowser to kill.4885         * @param big   Whether this should default to killFlip, as in an4886         *              EndInsideCastle cutscene.4887         */4888        FullScreenMario.prototype.killBowser = function (thing, big) {4889            if (big) {4890                thing.nofall = false;4891                thing.movement = undefined;4892                thing.FSM.killFlip(thing.FSM.killSpawn(thing));4893                return;4894            }4895            thing.deathcount += 1;4896            if (thing.deathcount === 5) {4897                thing.yvel = thing.speed = 0;4898                thing.movement = undefined;4899                thing.FSM.killFlip(thing.FSM.killSpawn(thing), 350);4900                thing.FSM.scoreOn(5000, thing);4901            }4902        };4903        /**4904         * Kills a Thing by replacing it with another Thing, typically a Shell or4905         * BeetleShell (determined by thing.shelltype). The spawn inherits smartness4906         * and location from its parent, and is temporarily given nocollidechar to4907         * stop double collision detections.4908         *4909         * @param thing   A Character to kill.4910         * @param big   Whether the spawned Shell should be killed4911         *              immediately (by default, false).4912         */4913        FullScreenMario.prototype.killToShell = function (thing, big) {4914            var spawn, nocollidecharold, nocollideplayerold;4915            thing.spawnSettings = {4916                "smart": thing.smart4917            };4918            if (big && big !== 2) {4919                thing.spawnType = thing.title;4920            }4921            else {4922                thing.spawnType = thing.shelltype || "Shell";4923            }4924            thing.spawnSettings = {4925                "smart": thing.smart4926            };4927            spawn = thing.FSM.killSpawn(thing);4928            nocollidecharold = spawn.nocollidechar;4929            nocollideplayerold = spawn.nocollideplayer;4930            spawn.nocollidechar = true;4931            spawn.nocollideplayer = true;4932            thing.FSM.TimeHandler.addEvent(function () {4933                spawn.nocollidechar = nocollidecharold;4934                spawn.nocollideplayer = nocollideplayerold;4935            }, 7);4936            thing.FSM.killNormal(thing);4937            if (big === 2) {4938                thing.FSM.killFlip(spawn);4939            }4940            return spawn;4941        };4942        /**4943         * Wipes the screen of any characters or solids that should be gone during4944         * an important cutscene, such as hitting an end-of-level flag.4945         * For characters, they're deleted if .nokillonend isn't truthy. If they4946         * have a .killonend function, that's called on them.4947         * Solids are only deleted if their .killonend is true.4948         *4949         * @remarks If thing.killonend is a Function, it is called on the Thing.4950         */4951        FullScreenMario.prototype.killNPCs = function () {4952            var FSM = FullScreenMario.prototype.ensureCorrectCaller(this), group, character, solid, i;4953            // Characters: they must opt out of being killed with .nokillonend, and4954            // may opt into having a function called instead (such as Lakitus).4955            group = FSM.GroupHolder.getGroup("Character");4956            for (i = group.length - 1; i >= 0; --i) {4957                character = group[i];4958                if (!character.nokillend) {4959                    character.FSM.killNormal(character);4960                    character.FSM.arrayDeleteThing(character, group, i);4961                }4962                else if (character.killonend) {4963                    character.killonend(character);4964                }4965            }4966            // Solids: they may opt into being deleted4967            group = FSM.GroupHolder.getGroup("Solid");4968            for (i = group.length - 1; i >= 0; --i) {4969                solid = group[i];4970                if (solid.killonend) {4