Copy to Clipboard Test

Terrorpin (Flippy Turtle) Code

// Number of frames and A.Speed for animations
// Walking
CONFIG TERRORPIN_FRAMES_WALK = 2;
CONFIG TERRORPIN_ASPEED_WALK = 8;
// Flipped over
CONFIG TERRORPIN_FRAMES_FLIP = 2;
CONFIG TERRORPIN_ASPEED_FLIP = 8;

// Settings for the enemy's flip arc
CONFIG TERRORPIN_FLIP_JUMP = 2.4; // Initial jump
CONFIG TERRORPIN_FLIP_BOUNCES = 2; // Extra bounces
CONFIG TERRORPIN_FLIP_DECAY = 0.3; // Decay of the jump value for each bounce
CONFIG TERRORPIN_FLIP_SPEED_MULT = 1.0; // Multiplier for the enemy's movement speed in mid air

@InitD0("Hammer Distance"),
@InitDHelp0("Distance in pixels the enemy detects hammer hits for. 40 by default."),
@InitD1("Flip Time"),
@InitDHelp1("How many frames the enemy stays flipped for. 180 by default."),
@InitD2("Can Reflip?"),
@InitDHelp2("If true, the hammer can still flip the enemy when vulnerable.")
npc script Terrorpin
{
    using namespace NPCAnim;
    using namespace GhostBasedMovement;
    enum Animations
    {
        ANIM_WALK,
        ANIM_FLIP
    };
    void run(int hammerDist, int flipTime, bool canReflip)
    {
        Waitspawn(this);
        
        if(!hammerDist)
            hammerDist = 40;
        if(!flipTime)
            flipTime = 180;
        AnimHandler aptr = new AnimHandler(this);
        aptr->AddAnim(ANIM_WALK, 0, TERRORPIN_FRAMES_WALK, TERRORPIN_ASPEED_WALK, 0);
        aptr->AddAnim(ANIM_FLIP, TERRORPIN_FRAMES_WALK, TERRORPIN_FRAMES_FLIP, TERRORPIN_ASPEED_FLIP, 0);

        int defenses[MAX_DEFENSE];
        for(int i=0; i<MAX_DEFENSE; ++i)
        {
            defenses[i] = this->Defense[i];
            this->Defense[i] = i==NPCD_HAMMER?NPCDT_IGNORE:NPCDT_BLOCK;
        }

        int counter = -1;
        while(true)
        {
            // Walking
            while(true)
            {
                counter = ConstWalk4(this, counter);
                if(DetectHammer(this, hammerDist, false))
                    break;
                Waitframe(this);
            }
            // Flipping
            aptr->PlayAnim(ANIM_FLIP);
            int jump = TERRORPIN_FLIP_JUMP;
            this->Dir = AngleDir4(Angle(Link->X, Link->Y, this->X, this->Y));
            for(int i=0; i<TERRORPIN_FLIP_BOUNCES+1; ++i)
            {
                this->Jump = jump;
                jump *= TERRORPIN_FLIP_DECAY;
                while(this->Jump>0||this->Z>0)
                {
                    this->Move(OppositeDir(this->Dir), this->Step/100*TERRORPIN_FLIP_SPEED_MULT);
                    Waitframe(this);
                }
            }
            // Make vulnerable
            for(int i=0; i<MAX_DEFENSE; ++i)
                this->Defense[i] = defenses[i];
            int frames = flipTime;
            while(true)
            {
                if(frames)
                    --frames;
                if(frames<60)
                {
                    this->DrawXOffset = (frames%4<2)?-1:1;
                }
                if(frames==0||(canReflip&&DetectHammer(this, hammerDist, true)))
                    break;
                Waitframe(this);
            }
            this->DrawXOffset = 0;
            // Make invulnerable
            for(int i=0; i<MAX_DEFENSE; ++i)
                this->Defense[i] = i==NPCD_HAMMER?NPCDT_IGNORE:NPCDT_BLOCK;
            // Flipping
            aptr->PlayAnim(ANIM_WALK);
            jump = TERRORPIN_FLIP_JUMP;
            this->Dir = AngleDir4(Angle(this->X, this->Y, Link->X, Link->Y));
            for(int i=0; i<TERRORPIN_FLIP_BOUNCES+1; ++i)
            {
                this->Jump = jump;
                jump *= TERRORPIN_FLIP_DECAY;
                while(this->Jump>0||this->Z>0)
                {
                    this->Move(this->Dir, this->Step/100*TERRORPIN_FLIP_SPEED_MULT);
                    Waitframe(this);
                }
            }
            // Slide back onto the grid
            int tX = GridX(this->X+8);
            int tY = GridY(this->Y+8);
            int safety = Ceiling(32/(this->Step/100));
            while(safety&&Distance(this->X, this->Y, tX, tY)>this->Step/100)
            {
                --safety;
                this->MoveAtAngle(Angle(this->X, this->Y, tX, tY), this->Step/100);
                Waitframe(this);
            }
            counter = -1;
        }
    }
    bool DetectHammer(npc this, int hammerDist, bool checkInvFrames)
    {
        if(this->HitBy[HIT_BY_LWEAPON])
            return false;
        if(checkInvFrames&&this->InvFrames)
            return false;
        for(int i=Screen->NumLWeapons(); i>0; --i)
        {
            lweapon l = Screen->LoadLWeapon(i);
            if(l->ID==LW_HAMMER)
            {
                if((l->Tile-l->OriginalTile)%3==2)
                {
                    int cx = l->X+l->HitWidth/2;
                    int cy = l->Y+l->HitHeight/2;
                    if(Distance(this->X+8, this->Y+8, cx, cy)<hammerDist)
                        return true;
                }
            }
        }
        return false;
    }
}