//********************************//
//     Minecraft Block Entity     //
//			 (c) McKay			  //
//********************************//

AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include( 'shared.lua')

//Accessor Funcs
function ENT:SetPlayer( ply )
    self.Owner = ply
end

function ENT:GetPlayer( )
    return self.Owner
end

function ENT:GetBlockID( )
	return self.dt.blockID
end

function ENT:SetRotation( rotation )
	self.dt.rotation = rotation
end

function ENT:SetBlockID( ID )
	self.dt.blockID = ID
end

//***************************************
//	Serverside init
//***************************************

function ENT:Initialize()
	//remove hook
	hook.Add( "OnRemove", "blockremove", OnRemove )
	self:CallOnRemove("blockremove",OnRemove)
    //Basic stuff
    self:PhysicsInit( SOLID_VPHYSICS )
	self:SetMoveType(MOVETYPE_VPHYSICS)
	self:SetSolid( SOLID_VPHYSICS )   
	// Wake the physics object up
	local phys = self.Entity:GetPhysicsObject()
	if (phys:IsValid()) then
		phys:EnableMotion( false ) //freeze the block
		phys:Wake()
	end
end

//***************************************
//	OnTakeDamage
//***************************************

function ENT:OnTakeDamage( dmginfo )
	// React physically when shot/getting blown
	self.Entity:TakePhysicsDamage( dmginfo )
	
	if (self.health <= 0) then return end;
	self.health = self.health - dmginfo:GetDamage();
	if (self.health <= 0) then
		self:Remove();
	end
end

//***************************************
//	OnSpawn - sounds and health values
//***************************************

function ENT:OnSpawn( ID, hitEntity )
	self.spawned = true
	if (GetConVar("minecraft_blockhealth"):GetInt() > 0) then
		self.health = GetConVar("minecraft_blockhealth"):GetInt()
	else
		self.health = -1
	end
	if (debuginfo == 2) then print("OnSpawn() with ID = " .. tostring(ID)) end
	
	//assign custom health values to all blocks
	if (GetConVar("minecraft_blockhealth_auto"):GetInt() == 1) then
		//ice and snow blocks
		if (ID == 40 || ID == 17) then
			self.health = 5;
		end
		//all metal blocks never break (+bedrock,+fire)
		if (ID == 37 || ID == 63 || ID == 14 || ID == 73 || ID == 74 || ID == 75 || ID == 76 || ID == 69) then
			self.health = -1;
		end
		//obsidian
		if (ID == 13) then
			self.health = 500;
		end
		//TODO: add more
	end
	
	if (!GetConVar("minecraft_disablesounds"):GetBool()) then
		local hasSound = false;
	
		//grass
		if (ID == 38 || ID == 70 || ID == 39) then
			local grass = { Sound("minecraft/grass1.wav"),Sound("minecraft/grass2.wav"),Sound("minecraft/grass3.wav"),Sound("minecraft/grass4.wav") }
			self:EmitSound( table.Random( grass ) )
			hasSound = true;
		end
		
		//stone
		if (ID == 7 || ID == 8 || ID == 9 || ID == 10 || ID == 11 || ID == 12 || ID == 13 || ID == 14 || ID == 15
			|| ID == 16 || ID == 19 || ID == 23 || ID == 24 || ID == 44 || ID == 45 || ID == 46 || ID == 48 || ID == 50
			|| ID == 51 || ID == 52 || ID == 57 || ID == 63 || ID == 68 || ID == 21 || ID == 22 || ID == 40 || ID == 61 || ID == 53
			|| ID == 57 || ID == 58 || ID == 49) then
			
			local stone = { Sound("minecraft/stone1.wav"),Sound("minecraft/stone2.wav"),Sound("minecraft/stone3.wav"),Sound("minecraft/stone4.wav") }
			self:EmitSound( table.Random( stone ) )
			hasSound = true;
		end
		
		//wood
		if (ID == 25 || ID == 26 || ID == 27 || ID == 28 || ID == 29 || ID == 30 || ID == 31 || ID == 47 || ID == 54
			|| ID == 65 || ID == 66 || ID == 67 || ID == 77 || ID == 78 || ID == 62 || ID == 64 || ID == 55 || ID == 34
			|| ID == 32  || ID == 72) then
			
			local wood = { Sound("minecraft/wood1.wav"),Sound("minecraft/wood2.wav"),Sound("minecraft/wood3.wav"),Sound("minecraft/wood4.wav") }
			self:EmitSound( table.Random( wood ) )
			hasSound = true;
		end
		
		//gravel
		if (ID == 1 || ID == 2 || ID == 3 || ID == 4) then
			local gravel = { Sound("minecraft/gravel1.wav"),Sound("minecraft/gravel2.wav"),Sound("minecraft/gravel3.wav"),Sound("minecraft/gravel4.wav") }
			self:EmitSound( table.Random( gravel ) )
			hasSound = true;
		end
		
		//snow
		if (ID == 5 || ID == 17 || ID == 56) then
			local snow = { Sound("minecraft/snow1.wav"),Sound("minecraft/snow2.wav"),Sound("minecraft/snow3.wav"),Sound("minecraft/snow4.wav") }
			self:EmitSound( table.Random( snow ) )
			hasSound = true;
		end
		
		//cloth
		if (ID == 79 || ID == 80) then
			local cloth = { Sound("minecraft/cloth1.wav"),Sound("minecraft/cloth2.wav"),Sound("minecraft/cloth3.wav"),Sound("minecraft/cloth4.wav") }
			self:EmitSound( table.Random( cloth ) )
			hasSound = true;
		end
		
		//sand
		if (ID == 6 || ID == 20) then
			local sand = { Sound("minecraft/sand1.wav"),Sound("minecraft/sand2.wav"),Sound("minecraft/sand3.wav"),Sound("minecraft/sand4.wav") }
			self:EmitSound( table.Random( sand ) )
			hasSound = true;
		end
		
		if (hasSound == false) then
			if (GetConVar("minecraft_debug"):GetBool()) then print("blocks with ID = " .. tostring(ID) .. " have no spawn sounds implemented!!!") end
		end
	end
end

//***************************************
//	PostSpawn - update nearby blocks
//***************************************

function ENT:PostSpawn ( ID )
	//notify all nearby blocks to update themselves
	//i think it's more efficient to update the blocks on spawn instead of every Think() cycle?
	//even though we are calling the function 6 times.. (idk)
	local t1 = self:GetNearbyBlock( 1 );
	local t2 = self:GetNearbyBlock( 2 );
	local t3 = self:GetNearbyBlock( 3 );
	local t4 = self:GetNearbyBlock( 4 );
	local t5 = self:GetNearbyBlock( 5 );
	local t6 = self:GetNearbyBlock( 6 );
	
	if (t1 != nil) then
		if (t1:IsValid()) then
			t1:SetNetworkedBool("doUpdate", true);
		end
	end
	if (t2 != nil) then
		if (t2:IsValid()) then
			t2:SetNetworkedBool("doUpdate", true);
		end
	end
	if (t3 != nil) then
		if (t3:IsValid()) then
			t3:SetNetworkedBool("doUpdate", true);
		end
	end
	if (t4 != nil) then
		if (t4:IsValid()) then
			t4:SetNetworkedBool("doUpdate", true);
		end
	end
	if (t5 != nil) then
		if (t5:IsValid()) then
			t5:SetNetworkedBool("doUpdate", true);
		end
	end
	if (t6 != nil) then
		if (t6:IsValid()) then
			t6:SetNetworkedBool("doUpdate", true);
		end
	end
end

//***********************************************
//	OnRemove - sounds, particles and other stuff
//***********************************************

function OnRemove( entity )
	if (entity.spawned == false) then return end
	local ID = entity.dt.blockID;
	if (GetConVar("minecraft_debug"):GetBool()) then print("block with ID = " .. tostring(ID) .. " removed!") end
	
	//test: spawn a water block if an ice block breaks
	if (ID == 40) then
		if (entity.health <= 0 && entity.health != -1 && entity.health != -2) then //if we were killed by taking damage
			if (GetConVar("minecraft_debug"):GetBool()) then print("spawning water block in place of ice block...") end
			local ent = ents.Create( "minecraft_block_waterized" )
			
			ent:SetModel( "models/MCModelPack/blocks/water.mdl" )
			ent:PhysicsInitBox( entity:GetPos() + Vector( -18.25, -18.25, -18.25 ), entity:GetPos() + Vector(  18.25,  18.25,  18.25 ) )
			ent:SetKeyValue( "DisableShadows", "1" )
			ent:SetKeyValue( "targetname", "mcblock" )
			ent:SetPos( entity:GetPos() )
			ent:SetPlayer( entity:GetOwner() )
		
			ent:SetDamping( 15 )
			ent.damping = 15
			ent:SetDensity( 70 )
			ent.density = 70
			ent:SetBuoyancy( 600 )
			ent.buoyancy = 600
		
			ent:SetNetworkedString( "water", "true" )
			ent:SetNetworkedString( "lava", "false" )
		
			ent.parent = 1
			ent.maxspread = GetConVar("minecraft_water_maxspread"):GetInt()
			ent:SetNWInt("blockID",41)
			ent:SetNetworkedBool("doUpdate",true)
			if (GetConVar("minecraft_debug"):GetBool()) then ent:SetColor(255,0,0,255) end
			ent:Spawn()
		end
	end
	
	if (!GetConVar("minecraft_disablesounds"):GetBool() && entity.health <= 0 && entity.health != -1) then
		local hasSound = false;
	
		//grass
		if (ID == 38 || ID == 70 || ID == 39 || ID == 2) then
			local grass = { Sound("minecraft/grass1.wav"),Sound("minecraft/grass2.wav"),Sound("minecraft/grass3.wav"),Sound("minecraft/grass4.wav") }
			entity:EmitSound( table.Random( grass ), 511, math.random(60,100) )
			hasSound = true;
		end
		
		//stone
		if (ID == 7 || ID == 8 || ID == 9 || ID == 10 || ID == 11 || ID == 12 || ID == 13 || ID == 14 || ID == 15
			|| ID == 16 || ID == 19 || ID == 23 || ID == 24 || ID == 44 || ID == 45 || ID == 46 || ID == 48 || ID == 50
			|| ID == 51 || ID == 52 || ID == 53 || ID == 57 || ID == 58 || ID == 63 || ID == 68 || ID == 34 || ID == 49) then
			
			local stone = { Sound("minecraft/stone1.wav"),Sound("minecraft/stone2.wav"),Sound("minecraft/stone3.wav"),Sound("minecraft/stone4.wav") }
			entity:EmitSound( table.Random( stone ), 511, math.random(60,100) )
			hasSound = true;
		end
		
		//wood
		if (ID == 25 || ID == 26 || ID == 27 || ID == 28 || ID == 29 || ID == 30 || ID == 31 || ID == 47 || ID == 54
			|| ID == 62 || ID == 64 || ID == 65 || ID == 66 || ID == 67 || ID == 77 || ID == 78 || ID == 55 || ID == 32
			|| ID == 72) then
			
			local wood = { Sound("minecraft/wood1.wav"),Sound("minecraft/wood2.wav"),Sound("minecraft/wood3.wav"),Sound("minecraft/wood4.wav") }
			entity:EmitSound( table.Random( wood ), 511, math.random(60,100) )
			hasSound = true;
		end
		
		//gravel
		if (ID == 1 || ID == 3 || ID == 4) then
			local gravel = { Sound("minecraft/gravel1.wav"),Sound("minecraft/gravel2.wav"),Sound("minecraft/gravel3.wav"),Sound("minecraft/gravel4.wav") }
			entity:EmitSound( table.Random( gravel ), 511, math.random(60,100) )
			hasSound = true;
		end
		
		//snow
		if (ID == 5 || ID == 17 || ID == 56) then
			local snow = { Sound("minecraft/snow1.wav"),Sound("minecraft/snow2.wav"),Sound("minecraft/snow3.wav"),Sound("minecraft/snow4.wav") }
			entity:EmitSound( table.Random( snow ) )
			hasSound = true;
		end
		
		//cloth
		if (ID == 79 || ID == 80) then
			local cloth = { Sound("minecraft/cloth1.wav"),Sound("minecraft/cloth2.wav"),Sound("minecraft/cloth3.wav"),Sound("minecraft/cloth4.wav") }
			entity:EmitSound( table.Random( cloth ), 511, math.random(60,100) )
			hasSound = true;
		end
		
		//sand
		if (ID == 6 || ID == 20) then
			local sand = { Sound("minecraft/sand1.wav"),Sound("minecraft/sand2.wav"),Sound("minecraft/sand3.wav"),Sound("minecraft/sand4.wav") }
			entity:EmitSound( table.Random( sand ) )
			hasSound = true;
		end		
		
		//glass
		if (ID == 21 || ID == 22 || ID == 40 || ID == 61) then
			local glass = { Sound("minecraft/glass_1.wav"),Sound("minecraft/glass_2.wav"),Sound("minecraft/glass_3.wav") }
			entity:EmitSound( table.Random( glass ) )
			hasSound = true;
		end
		
		if (hasSound == false) then
			if (GetConVar("minecraft_debug"):GetBool()) then print("blocks with ID = " .. tostring(ID) .. " have no remove sounds implemented!!!") end
		end
	end
	
	
	//test particle effect (if a block is destroyed by force)
	if (entity.health <= 0 && entity.health != -1 && GetConVar("minecraft_particles"):GetBool()) then
		local effect = EffectData();
		local pos = entity:GetPos();
		local min,max = entity:WorldSpaceAABB();
		local zadd = math.abs(min.z - max.z)/2
		pos.z = pos.z + zadd;
		effect:SetOrigin( pos );
		effect:SetNormal( Vector(0,0,1) );
		util.Effect( "MCMagic", effect );
	end
	
	
	//update all nearby blocks
	local t1 = entity:GetNearbyBlock( 1 );
	local t2 = entity:GetNearbyBlock( 2 );
	local t3 = entity:GetNearbyBlock( 3 );
	local t4 = entity:GetNearbyBlock( 4 );
	local t5 = entity:GetNearbyBlock( 5 );
	local t6 = entity:GetNearbyBlock( 6 );
	
	if (t1 != nil) then
		if (t1:IsValid()) then
			t1:SetNetworkedBool("doUpdate", true);
			//remove torches if their base block is removed
			//HACKHACK: when deleting other blocks nearby, torches may also get removed
			//HACKHACK: I'm too lazy to fix that now
			if (ID != 65 && ID != 66 && ID != 67 && ID != 68) then
			local ID2 = t1:GetBlockID()
			if (ID2 == 65 || ID2 == 66 || ID2 == 67 || ID2 == 68) then
				t1.Entity.health = -2
				t1:Remove()
			end
			end
		end
	end
	if (t2 != nil) then
		if (t2:IsValid()) then
			t2:SetNetworkedBool("doUpdate", true);
		end
	end
	if (t3 != nil) then
		if (t3:IsValid()) then
			t3:SetNetworkedBool("doUpdate", true);
			if (ID != 65 && ID != 66 && ID != 67 && ID != 68) then
			local ID2 = t3:GetBlockID()
			if (ID2 == 65 || ID2 == 66 || ID2 == 67 || ID2 == 68) then
				t3.Entity.health = -2
				t3:Remove()
			end
			end
		end
	end
	if (t4 != nil) then
		if (t4:IsValid()) then
			t4:SetNetworkedBool("doUpdate", true);
			if (ID != 65 && ID != 66 && ID != 67 && ID != 68) then
			local ID2 = t4:GetBlockID()
			if (ID2 == 65 || ID2 == 66 || ID2 == 67 || ID2 == 68) then
				t4.Entity.health = -2
				t4:Remove()
			end
			end
		end
	end
	if (t5 != nil) then
		if (t5:IsValid()) then
			t5:SetNetworkedBool("doUpdate", true);
			if (ID != 65 && ID != 66 && ID != 67 && ID != 68) then
			local ID2 = t5:GetBlockID()
			if (ID2 == 65 || ID2 == 66 || ID2 == 67 || ID2 == 68) then
				t5.Entity.health = -2
				t5:Remove()
			end
			end
		end
	end
	if (t6 != nil) then
		if (t6:IsValid()) then
			t6:SetNetworkedBool("doUpdate", true);
			if (ID != 65 && ID != 66 && ID != 67 && ID != 68) then
			local ID2 = t6:GetBlockID()
			if (ID2 == 65 || ID2 == 66 || ID2 == 67 || ID2 == 68) then
				t6.Entity.health = -2
				t6:Remove()
			end
			end
		end
	end
end

