//
// Copyright(C) 2014-2015 Samuel Villarreal
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//      Warp Portal Object Class
//

#include "scripts/common.txt"

// globals
kVec3   warpStoreOrigin;
int     warpStoreSector;
float   warpStoreYaw;
int     warpStoreMap;

/*
==============================================================
TurokWarpPortal
==============================================================
*/

class TurokWarpPortal : ScriptObject
{
    kActor @self;
    float time;
    float delayTime;
    bool bClosedWarp;
    bool bPersistent;
    bool bStoreWarpReturn;
    
    TurokWarpPortal(kActor @actor)
    {
        @self = actor;
        time = 0;
        delayTime = 0;
        bClosedWarp = false;
        bPersistent = false;
        bStoreWarpReturn = false;
		
		//if on challenge mao then remove
		if (Game.GetCurrentMapID() >= 54) {
			self.Remove();
		}
    }
    
    /*
    ==============================================================
    OnTick
    ==============================================================
    */
    
    void OnTick(void)
    {
        const float WARP_START_SPEED = 27.5f;
        const float WARP_IDLE_SPEED = 8.0f;
        const float WARP_END_SPEED = -20.0f;
        
        const float WARP_START_TIME = 0.25f;
        const float WARP_CLOSE_TIME = 0.87f;
        const float WARP_IDLE_TIME = (0.75f - WARP_START_TIME);
        
        float scaler, t, v, end;
        
        if(bPersistent)
        {
            self.PlaySound("sounds/shaders/generic_187.ksnd");
            return;
        }
        else
        {
            delayTime -= GAME_SECONDS;
            if(delayTime > 0.0f)
            {
                return;
            }
        }
        
        time += GAME_SECONDS;
        
        if((self.Flags() & AF_HIDDEN) != 0)
        {
            // wait for 'param1' seconds to appear
            end = self.SpawnParams(7);
            
            if(time >= end)
            {
                self.Flags() &= ~AF_HIDDEN;
                self.Flags() |= AF_CANBETOUCHED;
                
                bClosedWarp = false;
                time = 0;
            }
        }
        else
        {
            self.PlaySound("sounds/shaders/generic_187.ksnd");
            
            // wait for 'attackChance' seconds to disappear
            end = self.SpawnParams(4) * 6.0f;
            
            if(time >= end)
            {
                self.Flags() |= AF_HIDDEN;
                self.Flags() &= ~AF_CANBETOUCHED;
                self.StopSound();
                time = 0;
            }
        }
        
        if(end == 0 || ((self.Flags() & AF_HIDDEN) != 0))
        {
            scaler = 1.0f;
        }
        else
        {
            t = time / end;
            
            if(t < WARP_START_TIME)
            {
                v = 4 * t - 1;
                scaler = 1 - v * v;
            }
            else if(t > 0.75f)
            {
                v = 4 * t - 3;
                scaler = 1 - v * v;
            }
            else
            {
                scaler = 1;
            }
            
            if(t > WARP_CLOSE_TIME)
            {
                bClosedWarp = true;
            }
            
            if(t < WARP_START_TIME)
            {
                t = t * (1.0f / WARP_START_TIME);
                t = Math::Lerp(WARP_START_SPEED, WARP_END_SPEED, t);
            }
            else if(t < (WARP_IDLE_TIME + WARP_START_TIME))
            {
                t = WARP_IDLE_SPEED;
            }
            else
            {
                float u = 1 - (WARP_IDLE_TIME + WARP_START_TIME);
                
                t = (t - (WARP_IDLE_TIME + WARP_START_TIME)) * (1.0f / u);
                t = Math::Lerp(WARP_IDLE_SPEED, WARP_END_SPEED, t);
            }
        }
        
        self.Scale().Set(0.35f, 0.35f, 0.35f);
        self.Scale() *= scaler;
        
        if(!(self.RenderModel() is null))
        {
            self.RenderModel().Offset().z = 200.0f * (1.0f - scaler) * 0.38f;
        }
    }
    
    /*
    ==============================================================
    OnBeginLevel
    ==============================================================
    */
    
    void OnBeginLevel(void)
    {
        bPersistent         = ((self.SpawnFlags3() & (1 <<  0)) != 0);
        bStoreWarpReturn    = ((self.SpawnFlags2() & (1 << 29)) != 0);
        
        if(bPersistent)
        {
            self.Flags() &= ~AF_HIDDEN;
            self.Flags() |= AF_CANBETOUCHED;
        }
        else
        {
            self.Flags() |= AF_HIDDEN;
            self.Flags() &= ~AF_CANBETOUCHED;
        }
        
        delayTime = Math::RandRange(5.0f, 50.0f);
    }
    
    /*
    ==============================================================
    GetMapToWarpTo
    ==============================================================
    */
    
    const int GetMapToWarpTo(void)
    {
        int lastWarpChoice;
        int mapID = Game.GetCurrentMapID();
        
        GameVariables.GetInt("lastPortalWarpChoice", lastWarpChoice);
        
        if(lastWarpChoice > 1 || lastWarpChoice < 0)
        {
            lastWarpChoice = 0;
        }
        
        switch(self.TID())
        {
        case 19600: mapID = 26 + lastWarpChoice; break;
        case 19100: mapID = 28 + lastWarpChoice; break;
        case 19200: mapID = 30 + lastWarpChoice; break;
        case 19300: mapID = 32 + lastWarpChoice; break;
        case 19400: mapID = 34 + lastWarpChoice; break;
        case 19500: mapID = 36 + lastWarpChoice; break;
        case 19700: mapID = 38 + lastWarpChoice; break;
        case 19800: mapID = 40 + lastWarpChoice; break;
        default:
            return -1;
        }
        
        lastWarpChoice = (lastWarpChoice + 1) % 2;
        
        GameVariables.SetValue("lastPortalWarpChoice", "" + lastWarpChoice);
        return mapID;
    }
    
    /*
    ==============================================================
    StoreWarpPoint
    ==============================================================
    */
    
    void StoreWarpPoint(kActor @actor)
    {
        warpStoreMap = Game.GetCurrentMapID();
        
        warpStoreOrigin.x = self.Origin().x + Math::Sin(self.Yaw()) * -122.88f;
        warpStoreOrigin.y = self.Origin().y + Math::Cos(self.Yaw()) * -122.88f;
        warpStoreOrigin.z = actor.Origin().z;
        
        warpStoreSector = actor.GetSectorIndexAtLocation(warpStoreOrigin);
        warpStoreOrigin = CModel.InterceptVector();
        
        warpStoreYaw = (self.Origin() - warpStoreOrigin).ToYaw();
    }
    
    /*
    ==============================================================
    OnTouch
    ==============================================================
    */
    
    void OnTouch(kActor @theActorThatTouchedMe)
    {
        int mapID = 0;
        
        if(bClosedWarp || self.TID() <= 0)
        {
            return;
        }
        
        if(!theActorThatTouchedMe.InstanceOf("kexPuppet"))
        {
            return;
        }
        
        if(bPersistent)
        {
            // do free warp
            PlayLoop.StartFreeWarp(theActorThatTouchedMe,
                                   warpStoreOrigin,
                                   warpStoreYaw,
                                   warpStoreSector,
                                   warpStoreMap);
            return;
        }
        
        if(bStoreWarpReturn)
        {
            StoreWarpPoint(theActorThatTouchedMe);
        }
        
        mapID = GetMapToWarpTo();
        
        if(mapID <= -1)
        {
            return;
        }
        
        PlayLoop.StartWarp(theActorThatTouchedMe, self.TID(), mapID);
    }
    
    /*
    ==============================================================
    OnSpawn
    ==============================================================
    */
    
    void OnSpawn(void)
    {
        self.Flags() |= AF_HIDDEN;
    }
};
