//************************************************************************************************************
//	Global library of useful functions/tasks
//	Author: Helepolis
//	Version: 1.0
//  Library:
//		wait						- Yields the desired number of frames.
//		waitForNoEnemy				- Yields while there are any enemies on the screen (alive).
//		waitForAnyEnemy				- Yields until an enemy appears on the screen.
//		GetTimer					- Gets the current timer on attacks.
//		GetDistanceXY				- Gets the distance between specified X and Y coordinates. 
//		GetPointToPointAngle		- Uses atan2 to get the angle between two objects X/Y positions.
//		ObjMove_Special				- Special move code to move 2D sprites. Similar to moving object lasers.
//		rand_int					- Truncates a value between min and max value into an integer with no decimals.
//		GetCenterX/Y				- Gets the centre of the field.
//		GetClipMaxX/Y				- Gets the maximum X/Y coordinates of the field.
//		GetClipMinX/Y				- Gets the minimum X/Y coordinates of the field. 
//		GetEnemyX/Y					- Gets the X/Y coordinates of the boss.
//		ObjMove_RandomPos 			- Moves to a random location at speed given in the boundary field.
//		ObjMove_RandomPosWeight 	- Moves to a random location at weight given in the boundary field.
//		CreateShotA					- Creates and mimics ShotA from 0.12m.
//		SetShotDataA				- Sets behaviour for ShotA, mimicking 0.12m.
//		DeleteShotA					- Deletes ShotA after specified number of frames.
//		quakeCam2D					- Global camera to shake the screen in 2D. Cannot be used for 3D stages.
//		quakeCam3D					- Global camera to shake the screen in 3D. Can be combined with 2D stages.
//************************************************************************************************************

#include "script/thdcs/functions/const_sound.txt"

function calculateAndGetStageClearBonus() {
    let stageNumber = GetAreaCommonData("game", "stageNum", 1);
    return stageNumber * 5000000;
}

function calculateAndGetGameClearBonus() {
    return (30000000 + 10000000 * GetPlayerLife) + (3000000 * GetPlayerSpell);
}

function calculateAndGetSpellCardBonus() {
    let EASY_MODIFIER = 0;
    let NORMAL_MODIFIER = 1;
    let HARD_MODIFIER = 2;
    let LUNATIC_MODIFIER = 3;
    let EXTRA_MODIFIER = 4;
    let gameDifficulty = 0;

    let baseSpellCardValue = 1000000;
    let stageNumber = GetAreaCommonData("game","stageNum",1);

    if(GetAreaCommonData("game", "difficulty", 0) == 0) { gameDifficulty = NORMAL_MODIFIER; }
    if(GetAreaCommonData("game", "difficulty", 0) == 1) { gameDifficulty = HARD_MODIFIER; }
    if(GetAreaCommonData("game", "difficulty", 0) == 2) { gameDifficulty = LUNATIC_MODIFIER; }

    return (baseSpellCardValue * stageNumber) + (baseSpellCardValue * gameDifficulty);
}

// best friend
function wait(w) { loop(w) { yield; } } 

// Allows yielding while there is any enemy on the screen
function waitForNoEnemy {
	while(length(GetAllEnemyID) > 0) { yield; } 
}

// Allows yielding until there is an enemy appearing (opposite of noEnemy)
function waitForAnyEnemy {
	while(length(GetAllEnemyID) <= 0) { yield; } 
}

// Gets the current time on a spell card or attack.
function GetTimer() {
	let AttackTimer = ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID,INFO_TIMER);
	return AttackTimer;
}

// Gets the distance beteween two given xy coordinates
function GetDistanceXY(x1,y1,x2,y2) {
	let distance = (((x2-x1)^2+(y2-y1)^2)^(1/2));
	return distance;
}

// Gets the true angle between two points
function GetPointToPointAngle(x1,y1,x2,y2) {
	let dir = atan2(y1-y2,x1-x2);
	return dir;
}

// Because ObjMove_SetSpeed does not work with Primitive 2D Sprites, I decided to make my own move code.
task ObjMove_Special(obj,x,y,v,dir) {
	let vx = v * cos(dir);
	let vy = v * sin(dir);

	while(!Obj_IsDeleted(obj)) {
		ObjRender_SetPosition(obj,x,y,0);
		yield;
		x += vx;
		y += vy;
	}
}

// 0.12m personal transition for rand_int.
function rand_int(min,max) { 
	let rand_int_result;
	rand_int_result = truncate(rand(min,max));
	return rand_int_result;
} 

// Gets the centre X of stage field
function GetCenterX() {
	let calc = GetStgFrameWidth / 2;
	return calc;
}

// Gets the centre of stage field
function GetCenterY() {
	let calc = GetStgFrameHeight / 2; 
	return calc; 
}

// Gets minimum X of stage field ( x = 0 )
function GetClipMinX() { 
	let calc = GetStgFrameWidth - GetStgFrameWidth;
	return calc; 
}

// Gets maximum X of stage field
function GetClipMaxX() { 
	let calc = GetStgFrameWidth;
	return calc; 
}

// Gets minimum Y of stage field
function GetClipMinY() { 
	let calc = GetStgFrameHeight - GetStgFrameHeight;
	return calc; 
} 

// Gets minimum Y of stage field
function GetClipMaxY() { 
	let calc = GetStgFrameHeight;
	return calc; 
} 

// Gets X position of boss
function GetEnemyX() { 
	let ex = ObjMove_GetX(bossObj);
	return ex;
}

// Gets Y position of boss
function GetEnemyY() { 
	let ey = ObjMove_GetY(bossObj);
	return ey;
}

// 0.12m personal transition for moving random in boundary based on flat speed.
task ObjMove_RandomPos(obj,x,y,v,top,left,bottom,right) {
	let maxRandomX = rand_int(top,bottom);
	let maxRandomY = rand_int(left,right);

	ObjMove_SetDestAtSpeed(obj,maxRandomX,maxRandomY,v);
}

// 0.12m personal transition for moving random in boundary based on weight.
task ObjMove_RandomPosWeight(obj,x,y,weight,frame,left,top,right,bottom) {

	let maxRandomX = rand_int(left,right);
	let maxRandomY = rand_int(top,bottom);

	let calcMoveX = ObjMove_GetX(obj) + maxRandomX;
	let calcMoveY = ObjMove_GetY(obj) + maxRandomY;
	
	if(calcMoveX >= right) { calcMoveX = right; }
	if(calcMoveX <= left) { calcMoveX = left; } 
	if(calcMoveY >= bottom) { calcMoveY = bottom; }
	if(calcMoveY <= top) { calcMoveY = top; } 	
	
	ObjMove_SetDestAtWeight(obj,maxRandomX,maxRandomY,weight,frame);	
}

// Old createshotA mimic, ID is NOT passed. Needs to be defined manually.
function CreateShotA(x,y,delay) {
	let oldShotAObj = CreateShotA2(x,y,0,0,0,0,26,delay);
	return oldShotAObj;
}

// Old SetShotDataA mimic, ID is passed once you have manually set it.
function SetShotDataA(id,t,v,dir,dirv,accel,maxv,type) { 
	ObjMove_AddPatternA3(id,t,v,dir,accel,dirv,maxv,type);
	return id;
}

// Old SetShotDataA mimic, it is to delete the shot after specified number of frames (t)
function DeleteShotA(id,t) {
	ObjShot_SetDeleteFrame(id,t);
	return id;
}

// Straight laser special
task CreateRegularStatic00(followObj,x,y,dir,maxLen,width,graphic,delay,lifetime,source,resist) {
	let obj = ObjShot_Create(OBJ_STRAIGHT_LASER);
	let lastX = 0;
	let lastY = 0;
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj,x,y);
	ObjMove_SetAngle(obj,dir);
	ObjStLaser_SetAngle(obj,dir);
	ObjShot_SetGraphic(obj,graphic);
	ObjShot_SetDelay(obj,delay);
	ObjLaser_SetLength(obj,maxLen);
	ObjLaser_SetRenderWidth(obj,width);
	ObjLaser_SetIntersectionWidth(obj,width);
	ObjStLaser_SetSource(obj,source);
	ObjShot_SetSpellResist(obj,resist);
	ObjShot_SetDeleteFrame(obj,lifetime);
	ObjLaser_SetInvalidLength(obj,0,0);
	
	while(!Obj_IsDeleted(obj)) { 
		ObjMove_SetPosition(obj,ObjMove_GetX(followObj)+32*cos(dir),ObjMove_GetY(followObj)+32*sin(dir));
		yield;
		lastX = ObjMove_GetX(followObj);
		lastY = ObjMove_GetY(followObj);
	}
	ObjMove_SetPosition(obj,lastX+32*cos(dir),lastY+32*sin(dir));
}

// Special movement code for laser object.
task ObjMove_SpecialLaserMove(obj,x,y,v,dir) {
	let vx = v*cos(dir);
	let vy = v*sin(dir);
	
	while(! Obj_IsDeleted(obj)) {
		ObjRender_SetPosition(obj,x,y,0);
		yield;
		
		x += vx;
		y += vy;
	}
}

// Special movement code, handles the growing of the laser.
task ObjMove_SpecialLaserGrowth(obj,maxLen,v) {
	let len = 0;
	let max = floor(maxLen / v);
	let i   = 0;
	
	while(!Obj_IsDeleted(obj)) {
		ObjLaser_SetLength(obj, -len);
		yield;
		if(i < max) {
			len += v;
			i++;
		} 
		else if(i == max) {
			ObjLaser_SetLength(obj, -maxLen);
			break;
		}
	}
}

// Quake cam 2D to use for certain boss effects.
task quakeCam2D(m,t) {
	let schudx = Get2DCameraX;
	let schudy = Get2DCameraY;
	loop(t) {
		Set2DCameraFocusX(rand(schudx-m,schudx+m));
		Set2DCameraFocusY(rand(schudy-m,schudy+m));
		yield;
	}
	Reset2DCamera;
}

// Quake cam 3D to use 3D stages
task quakeCam3D(m,t) {
	let oldCamX = GetCameraX;
	let oldCamY = GetCameraY;
	let oldCamZ = GetCameraZ;
	let azuSchud = GetCameraAzimuthAngle;
	let eleSchud = GetCameraElevationAngle;
	
	loop(t) {
		SetCameraFocusXYZ(rand(oldCamX-m,oldCamX+m),rand(oldCamY-m,oldCamX+m),rand(oldCamZ-m,oldCamX+m));
		SetCameraAzimuthAngle(rand(azuSchud-m,azuSchud+m));
		SetCameraElevationAngle(rand(eleSchud-m,eleSchud+m));		
		yield;
	}
	//SetCameraAzimuthAngle(azuSchud);
	//SetCameraElevationAngle(eleSchud);
	SetCameraFocusXYZ(oldCamX,oldCamY,oldCamZ);
}

