/**
 * 画面端で反射する弾を発射する
 * ※速度が大きい程、反射位置の誤差が大きくなる
 * 
 * @param {Integer} x         弾源x座標
 * @param {Integer} y         弾源y座標
 * @param {Integer} speed     速度
 * @param {Integer} angle     角度
 * @param {Integer} graph     画像
 * @param {Integer} delay     遅延フレーム数
 * @param {Array}   refflag   左・上・右・下で反射するか( 配列で入れる。1で反射 )
 * @param {Integer} refnumber 反射回数
 */
task ReflectShot( x, y, speed, angle, graph, delay, refflag, refnumber ){
	let refnum = refnumber;
	
	let obj = Obj_Create( OBJ_SHOT );
	Obj_SetPosition( obj, x, y );
	Obj_SetSpeed( obj, speed );
	Obj_SetAngle( obj, angle );
	ObjShot_SetGraphic( obj, graph );
	ObjShot_SetDelay( obj, delay );
	
	while( !Obj_BeDeleted( obj ) ){
		if( ( Obj_GetX( obj ) <= GetClipMinX() && refflag[ 0 ] == 1 && refnum > 0 ) || ( Obj_GetX( obj ) >= GetClipMaxX() && refflag[ 2 ] == 1 && refnum > 0 ) ){
			if( refnum > 1 ){
				Obj_SetAngle( obj, 180 - Obj_GetAngle( obj ) );
				refnum -= 1;
			}else{
				CreateShot01( Obj_GetX( obj ), Obj_GetY( obj ), speed, 180 - Obj_GetAngle( obj ), graph, 0 );
				Obj_Delete( obj );
			}
		}
		
		if( ( Obj_GetY( obj ) <= GetClipMinY() && refflag[ 1 ] == 1 && refnum > 0 ) || ( Obj_GetY( obj ) >= GetClipMaxY() && refflag[ 3 ] == 1 && refnum > 0 ) ){
			if( refnum > 1 ){
				Obj_SetAngle( obj, -Obj_GetAngle( obj ) );
				refnum -= 1;
			}else{
				CreateShot01( Obj_GetX( obj ), Obj_GetY( obj ), speed, -Obj_GetAngle( obj ), graph, 0 );
				Obj_Delete( obj );
			}
		}
		
		yield;
	}
}

/**
 * 画面端で反射するレーザーを発射する
 * ※速度が大きい程、反射位置の誤差が大きくなる
 * 
 * @param {Integer} x         弾源x座標
 * @param {Integer} y         弾源y座標
 * @param {Integer} speed     速度
 * @param {Integer} angle     角度
 * @param {Integer} lng       レーザーの長さ
 * @param {Integer} wid       レーザーの幅
 * @param {Integer} graph     画像
 * @param {Integer} delay     遅延フレーム数
 * @param {Array}   refflag   左・上・右・下で反射するか( 配列で入れる。1で反射 )
 * @param {Integer} refnumber 反射回数
 */
task RefrectLaser( x, y, speed, angle, lng, wid, graph, delay, refflag, refnumber ){
	let refnum = refnumber;
	
	let vLng = 0;
	
	let mx = speed * cos( angle );
	let my = speed * sin( angle );
	
	let vx = x;
	let vy = y;
	
	let obj = Obj_Create( OBJ_LASER );
	Obj_SetPosition( obj, x, y );
	Obj_SetSpeed( obj, speed );
	Obj_SetAngle( obj, angle );
	ObjShot_SetGraphic( obj, graph );
	ObjShot_SetDelay( obj, delay );
	
	ObjLaser_SetLength( obj, 0 );
	ObjLaser_SetWidth( obj, wid );
	ObjLaser_SetSource( obj, false );
	
	while( !Obj_BeDeleted( obj ) ){
		if( vLng < lng ){
			vLng += speed;
			ObjLaser_SetLength( obj, vLng );
		}else{
			vLng = lng;
			vx += mx;
			vy += my;
		}
		
		Obj_SetPosition( obj, vx, vy );
		
		if( ( ObjLaser_GetEndX( obj ) <= GetClipMinX() && refflag[ 0 ] == 1 && refnum > 0 ) || ( ObjLaser_GetEndX( obj ) >= GetClipMaxX() && refflag[ 2 ] == 1 && refnum > 0 ) ){
			RefrectLaser( ObjLaser_GetEndX( obj ), ObjLaser_GetEndY( obj ), speed, 180 - angle, lng, wid, graph, 0, refflag, refnumber - 1 );
			refnum = 0;
		}
		
		if( ( ObjLaser_GetEndY( obj ) <= GetClipMinY() && refflag[ 1 ] == 1 && refnum > 0 ) || ( ObjLaser_GetEndY( obj ) >= GetClipMaxY() && refflag[ 3 ] == 1 && refnum > 0 ) ){
			RefrectLaser( ObjLaser_GetEndX( obj ), ObjLaser_GetEndY( obj ), speed,      -angle, lng, wid, graph, 0, refflag, refnumber - 1 );
			refnum = 0;
		}
		
		yield;
	}
}

/**
 * 重力で加速する弾を発射する
 * ※角度、重力角度は絶対角度指定( SetShotDirectionTypeの状態には関係しない )
 * 
 * @param {Integer} x        弾源x座標
 * @param {Integer} y        弾源y座標
 * @param {Integer} speed    速度
 * @param {Integer} angle    角度
 * @param {Integer} graph    画像
 * @param {Integer} delay    遅延フレーム数
 * @param {Integer} grvspeed 重力加速度
 * @param {Integer} grvangle 重力角度
 * @param {Integer} maxspeed 最大速度
 */
function GravityShot( x, y, speed, angle, graph, delay, grvspeed, grvangle, maxspeed ){
	let xSpeed = speed * cos( angle );
	let ySpeed = speed * sin( angle );
	let accXSpeed = grvspeed * cos( grvangle );
	let accYSpeed = grvspeed * sin( grvangle );
	let maxXSpeed = [ maxspeed, -maxspeed ][ accXSpeed < 0 ];
	let maxYSpeed = [ maxspeed, -maxspeed ][ accYSpeed < 0 ];
	
	CreateShot12( x, y, xSpeed, ySpeed, accXSpeed, accYSpeed, maxXSpeed, maxYSpeed, graph, delay );
}

/**
 * 重力で加速する弾を発射する関数Obj版
 * ※角度、重力角度は絶対角度指定( SetShotDirectionTypeの状態には関係しない )
 * 
 * @param {Integer} x        弾源x座標
 * @param {Integer} y        弾源y座標
 * @param {Integer} speed    速度
 * @param {Integer} angle    角度
 * @param {Integer} graph    画像
 * @param {Integer} delay    遅延フレーム数
 * @param {Integer} grvspeed 重力加速度
 * @param {Integer} grvangle 重力角度
 * @param {Integer} maxspeed 最大速度
 * @return {Object} 作成したオブジェクトのid
 */
function GravityShotObj( x, y, speed, angle, graph, delay, gspeed, gangle, maxspeed ){
	let obj = Obj_Create( OBJ_SHOT );
	Obj_SetPosition( obj, x, y );
	Obj_SetSpeed( obj, speed );
	Obj_SetAngle( obj, angle );
	ObjShot_SetGraphic( obj, graph );
	ObjShot_SetDelay( obj, delay );
	
	ObjShot_SetGravity( obj, speed, angle, delay, gspeed, gangle, maxspeed );
	
	return obj;
}

/**
 * 対象のオブジェクト弾に重力加速属性を加える
 * 
 * @param {Object}  obj      対象のオブジェクト弾
 * @param {Integer} speed    速度
 * @param {Integer} angle    角度
 * @param {Integer} delay    遅延フレーム数
 * @param {Integer} grvspeed 重力加速度
 * @param {Integer} grvangle 重力角度
 * @param {Integer} maxspeed 最大速度
 */
task ObjShot_SetGravity( obj, speed, angle, delay, gspeed, gangle, maxspeed ){
	let ox = speed * cos( angle );
	let oy = speed * sin( angle );
	let vx = gspeed * cos( gangle );
	let vy = gspeed * sin( gangle );
	
	loop( delay ){
		yield;
	}
	
	while( !Obj_BeDeleted( obj ) ){
		ox += vx;
		oy += vy;
		
		speed = ( ox ^ 2 + oy ^ 2 ) ^ 0.5;
		
		if( speed > maxspeed ){
			speed = maxspeed;
		}
		
		angle = atan2( oy, ox );
		
		Obj_SetSpeed( obj, speed );
		Obj_SetAngle( obj, angle );
		
		yield;
	}
}
