-- $LastChangedDate: 2009-06-14 19:47:44 -0500 (Sun, 14 Jun 2009) $
-- Library of Lua objects to interface with simulator.
-- This extends and supplements what C++ exports to Lua.
-- See module.txt for documentation and pitfalls.
-- Notes: Use Vec3() instead of tables (XX=0).

---------------------
-- sim definitions --
---------------------

sim.LANDING_GEAR_UP   = false
sim.LANDING_GEAR_DOWN = true

sim.COLLISION_NONE  = 0  -- Object::eCollision
sim.COLLISION       = 1
sim.COLLISION_FATAL = 2

----------------
-- ModelCache --
----------------

sim.ModelCache = {
	LOAD_SHARED = 0,
	LOAD_COPY = 1,
}

-------------
-- Control --
-------------

-- Defines which way to rotate player according to control input.
sim.Control.rollLeftDir  =  1
sim.Control.rollRightDir = -1
sim.Control.pitchUpDir   =  1
sim.Control.pitchDownDir = -1
sim.Control.yawLeftDir   =  1
sim.Control.yawRightDir  = -1

------------
-- Object --
------------

-- Helper to place an Object without interference from physics/collision.
function sim.BeginPlacement( craft )
	local placement = { enablePhysics = sim.Physics:IfEnabled(),
						enableCollision = craft:IfCollidable() }

    sim.Physics:Enable( false )  -- disable physics
	craft:SetCollidable( false )  -- disable collision-detection

	return placement
end

function sim.EndPlacement( craft, placement )
	sim.Physics:Enable( placement.enablePhysics )  -- restore physics
	-- Keep collisions disabled in step mode.
	if ( not sim.argvMap["-step"] ) then
		craft:SetCollidable( placement.enableCollision )  -- restore collision-detecton
	end
end

-- Schedule a 3D Object for deletion (ok if object was already freed/zombified).
-- Example: For self.object : sim.ZombifyObject( self, "object" )
-- Similar to lib:DESTROY()
function sim.ZombifyObject( t, objectMember )
	local object = t[objectMember]
	if ( object ) then
		sim.SceneGraph:DetachObject( object )  -- remove from scene-graph
		object:Zombify()                       -- schedule for deletion
		t[objectMember] = nil                  -- release Lua table's reference to it
	end
end

-----------
-- Craft --
-----------

sim.Craft = { }
sim.Craft.eState_PARKED  = 0
sim.Craft.eState_TAKEOFF = 1
sim.Craft.eState_FLYING  = 2
sim.Craft.eState_LANDING = 3
sim.Craft.eState_CRASHED = 4

--------------
-- Aircraft --
--------------

-- Aircraft::eType enums.
sim.Aircraft.type_Spitfire     = 0
sim.Aircraft.type_Corsair      = 1
sim.Aircraft.type_P51          = 2
sim.Aircraft.type_F82          = 3
sim.Aircraft.type_F86          = 4
sim.Aircraft.type_A4           = 5
sim.Aircraft.type_F14          = 6
sim.Aircraft.type_F15          = 7
sim.Aircraft.type_F16          = 8
sim.Aircraft.type_F18          = 9
sim.Aircraft.type_SR71         = 10
sim.Aircraft.type_Mirage2000   = 11
sim.Aircraft.type_SU37         = 12
sim.Aircraft.type_SpaceShuttle = 13
-- (special case aircraft that cannot be selected by user)
sim.Aircraft.type_Sikorsky     = 14

-- Map cmdline args to C++ enums.
sim.Aircraft.typeArgMap = {
	["-spitfire"]   = sim.Aircraft.type_Spitfire,
	["-corsair"]    = sim.Aircraft.type_Corsair,
	["-f4u"]        = sim.Aircraft.type_Corsair,  -- alias
	["-p51"]        = sim.Aircraft.type_P51,
	["-f82"]        = sim.Aircraft.type_F82,
	["-f86"]        = sim.Aircraft.type_F86,
	["-a4"]         = sim.Aircraft.type_A4,
	["-f14"]        = sim.Aircraft.type_F14,
	["-f15"]        = sim.Aircraft.type_F15,
	["-f16"]        = sim.Aircraft.type_F16,
	["-f18"]        = sim.Aircraft.type_F18,
	["-sr71"]       = sim.Aircraft.type_SR71,
	["-mirage"]     = sim.Aircraft.type_Mirage2000,
	["-su37"]       = sim.Aircraft.type_SU37,
	["-shuttle"]    = sim.Aircraft.type_SpaceShuttle,
}

sim.Aircraft.longNameTypeMap = {
	["Spitfire"]          = sim.Aircraft.type_Spitfire,
	["F4U Corsair"]       = sim.Aircraft.type_Corsair,
	["P-51 Mustang"]      = sim.Aircraft.type_P51,
	["F-82 Twin Mustang"] = sim.Aircraft.type_F82,
	["F-86 Sabre"]        = sim.Aircraft.type_F86,
	["A-4 Skyhawk"]       = sim.Aircraft.type_A4,
	["F-14 Tomcat"]       = sim.Aircraft.type_F14,
	["F-15 Eagle"]        = sim.Aircraft.type_F15,
	["F-16 Falcon"]       = sim.Aircraft.type_F16,
	["F-18 Hornet"]       = sim.Aircraft.type_F18,
	["SR-71 Blackbird"]   = sim.Aircraft.type_SR71,
	["Mirage 2000"]       = sim.Aircraft.type_Mirage2000,
	["SU-37 Flanker"]     = sim.Aircraft.type_SU37,
	["Space Shuttle"]     = sim.Aircraft.type_SpaceShuttle,
}

sim.Aircraft.names = {
	[sim.Aircraft.type_Spitfire]     = "Spitfire",
	[sim.Aircraft.type_Corsair]      = "F4U",
	[sim.Aircraft.type_P51]          = "P51",
	[sim.Aircraft.type_F82]          = "F82",
	[sim.Aircraft.type_F86]          = "F86",
	[sim.Aircraft.type_A4]           = "A4",
	[sim.Aircraft.type_F14]          = "F14",
	[sim.Aircraft.type_F15]          = "F15",
	[sim.Aircraft.type_F16]          = "F16",
	[sim.Aircraft.type_F18]          = "F18",
	[sim.Aircraft.type_SR71]         = "SR71",
	[sim.Aircraft.type_Mirage2000]   = "Mirage",
	[sim.Aircraft.type_SU37]         = "SU37",
	[sim.Aircraft.type_SpaceShuttle] = "Space Shuttle",
}

-- Compute KPH.
function sim.AircraftComputeSpeedKPH( aircraft )
	return sim.Physics.Speed2KPH( aircraft:GetPhysics():ComputeSpeed() )
end

-------------
-- Carrier --
-------------

-- Parking slots for aircraft on carrier.
-- In meters, relative to carrier.
sim.Carrier.slots = {
	Vec3( -3.0, -197.0, 21.75 ),  -- takeoff slot 1 (rear deck)
	Vec3(  3.0, -177.0, 21.75 ),  -- takeoff slot 2 (rear deck)
	Vec3(  7.0,  -27.5, 21.75 ),  -- takeoff slot 3 (front deck)
	Vec3( 14.0, -120.0, 21.75 ),
	Vec3( 12.0, -100.0, 21.75 ),
	Vec3(  7.0,  -80.0, 21.75 ),
	Vec3(  4.0,  -60.0, 21.75 ),
}
sim.Carrier.takeoffSlotCnt = 3

-----------
-- Sound --
-----------

sim.Sound.PLAY_ONCE = false
sim.Sound.PLAY_LOOP = true
sim.Sound.DEFAULT_VOLUME = 1.0

----------
-- Misc --
----------

-- (abbrevation) Meters to world coordinates.
Meters2Sim = sim.World.Meters2Sim  -- function
M2W        = sim.World.Meters2Sim
Sim2Meters = sim.World.Sim2Meters  -- function
W2M        = sim.World.Sim2Meters

------------------------------------
-- Handler for DestroyObjectEvent --
------------------------------------

-- This is a special-case of the C++ core calling a Lua function.
-- Because of reference-counts, an Object to be destroyed (zombie)
-- must be broadcast so that all of its holders will release references to it.

function sim.HandleDestroyObject( objectPtr )
	-- This will propagate the event to all Actors.
	Game:HandleDestroyObject( objectPtr )

	-- Force releasing C++ objects.
	collectgarbage()

	return 0
end

-- Return true if two references both refer to the same C++ 3D Object.
function sim.IfIdenticalObject( obj1, obj2 )
	if ( obj1 == nil or obj2 == nil ) then
		return false
	else
		-- Convert either/both args to raw pointers.
		if ( type(obj1) == "userdata" ) then  -- is userdata if binding to C++ Object
			obj1 = obj1:GetRawPtr()           -- returns raw ptr of C++ Object as a Lua number
		end
		if ( type(obj2) == "userdata" ) then
			obj2 = obj2:GetRawPtr()
		end
		-- Compare raw pointers.
		return obj1 == obj2
	end
end
