//********************************//
//    (c) McKay + Dj Lukis.LT     //   Do NOT redistribute!
//********************************//

--All textures and sounds are (c) 2011 Mojang AB

--LAST EDITED 04.October.2011  20:48 [GMT+1]

--Minecraft Swep version 1.8.1 rev 5 (going with Minecraft version numbers now)
--CHANGELOG:
//- Disabled USE_MESH for release on garrysmod.org; still needs a lot of work
//- Added grass turning into dirt if lava is on top
//- Fixed snowy grass if snow layer is placed on top not working
//- Added minecraft_blocktypes.lua to make adding new blocks easier
//- Added minecraft_blockpanel.lua (modified version of proppanel)
//- Rewrote most of the UI code
//- Added water on lava special behaviour
//- Added water/lava <-> world collision
//- Fixed Viewmodel animation being dependent on the framerate (it still is, AAAARGHH)
//- Added intelligent placing of glass panes, iron bars, portals
//- Fixed lots of small bugs (can't remember which)
//- Added Water and lava physics (they spread now)
//- Added Viewmodel animations
//- Added intelligent blocks (testing with grass)
//- Added ice blocks turning to water blocks on kill
//- Made mc-explosion 20% cooler (added spherical particles)
//- Fixed mc_tnt and mc-ignite
//- Added TNT and cake
//- Fixed empty tooltips in wool block selection DFrames
//- Added test particle effect if a block is destroyed by damage
//- Fixed blocks overlapping (it's impossible now! except for double chests)
//- Added Minecraft sounds
//- Added OnRemove() and OnSpawn() calls to minecraft_block
//- Fixed props not colliding with blocks ; also fixed fucked up player <-> block collisions
//- Added ENT:PhysicsCollide() to minecraft_block, testing with cactus (takedamage() on touch)
//- Added auto block rotation (in minecraft_block/shared.lua under ENT:BlockInit())
//- Added minecraft_block entity
//- Fixed SpawnIcon tooltips staying onscreen (still happens)
//- Fixed viewmodel height for pistons (temp fix)
//- Added mc_viewmodel_... convars for position tweaking
//- Added custom undo message
//- Cleanup, added some comments, repositioned some variables, deleted unnecessary code parts
//- Fixed lava and water blocks not igniting/extinguishing stuff

--If you are reading this, you are awesome!

if ( CLIENT ) then
	SWEP.PrintName			= "Minecraft Block"
	SWEP.Slot				= 3
	SWEP.SlotPos			= 1
	SWEP.Author				= "McKay + Dj Lukis.LT"
	SWEP.WepSelectIcon		= surface.GetTextureID("VGUI/entities/minecraft_swep")
	SWEP.BounceWeaponIcon	= true
	SWEP.DrawAmmo			= false
	SWEP.DrawCrosshair		= true
end

if (SERVER) then
	AddCSLuaFile( "shared.lua" )

	SWEP.Weight			= 5
	SWEP.AutoSwitchTo	= false
	SWEP.AutoSwitchFrom	= false
end

SWEP.Category		= "Minecraft"
SWEP.Contact		= "mckay@gmx.at"
SWEP.Purpose		= "Sandboxception - we need to go deeper"
SWEP.Instructions	= "Right-click to place a block, left click to destroy a block, press RELOAD to select a block type!"
SWEP.ViewModel		= "models/MCModelPack/blocks/dirt.mdl"
SWEP.HoldType		= "Pistol"
SWEP.AdminSpawnable	= true
SWEP.Spawnable		= true

SWEP.WorldModel		= "models/MCModelPack/blocks/grass.mdl"

SWEP.Primary.ClipSize		= -1
SWEP.Primary.DefaultClip	= -1
SWEP.Primary.Automatic		= false
SWEP.Primary.Ammo			= "none"
SWEP.Secondary.ClipSize		= -1
SWEP.Secondary.DefaultClip	= -1
SWEP.Secondary.Automatic	= false
SWEP.Secondary.Ammo			= "none"
SWEP.base					= "weapon_base"
SWEP.Precache				= 1

function SWEP:Precache()
	util.PrecacheSound("minecraft/concrete_impact_hard3.wav")
	util.PrecacheSound("minecraft/concrete_impact_hard2.wav")
	util.PrecacheSound("minecraft/concrete_impact_hard1.wav")
	util.PrecacheSound("minecraft/block_break.wav")
	
	util.PrecacheSound("minecraft/cloth1.wav")
	util.PrecacheSound("minecraft/cloth2.wav")
	util.PrecacheSound("minecraft/cloth3.wav")
	util.PrecacheSound("minecraft/cloth4.wav")
	
	util.PrecacheSound("minecraft/door_open.wav")
	util.PrecacheSound("minecraft/door_close.wav")
	
	util.PrecacheSound("minecraft/glass_1.wav")
	util.PrecacheSound("minecraft/glass_2.wav")
	util.PrecacheSound("minecraft/glass_3.wav")
	
	util.PrecacheSound("minecraft/grass1.wav")
	util.PrecacheSound("minecraft/grass2.wav")
	util.PrecacheSound("minecraft/grass3.wav")
	util.PrecacheSound("minecraft/grass4.wav")
	
	util.PrecacheSound("minecraft/gravel1.wav")
	util.PrecacheSound("minecraft/gravel2.wav")
	util.PrecacheSound("minecraft/gravel3.wav")
	util.PrecacheSound("minecraft/gravel4.wav")
	
	util.PrecacheSound("minecraft/sand1.wav")
	util.PrecacheSound("minecraft/sand2.wav")
	util.PrecacheSound("minecraft/sand3.wav")
	util.PrecacheSound("minecraft/sand4.wav")
	
	util.PrecacheSound("minecraft/snow1.wav")
	util.PrecacheSound("minecraft/snow2.wav")
	util.PrecacheSound("minecraft/snow3.wav")
	util.PrecacheSound("minecraft/snow4.wav")
	
	util.PrecacheSound("minecraft/stone1.wav")
	util.PrecacheSound("minecraft/stone2.wav")
	util.PrecacheSound("minecraft/stone3.wav")
	util.PrecacheSound("minecraft/stone4.wav")
	
	util.PrecacheSound("minecraft/wood1.wav")
	util.PrecacheSound("minecraft/wood2.wav")
	util.PrecacheSound("minecraft/wood3.wav")
	util.PrecacheSound("minecraft/wood4.wav")
	return true  
end

//***************************************
//	Saving functions
//***************************************
//TODO: remove for gmod.org singleplayer version, only useful on toybox

local function SaveMaterial( Player, Entity, Data )
	Entity:SetMaterial( Data.MaterialOverride )	
	if ( SERVER ) then
		duplicator.StoreEntityModifier( Entity, "material", Data, Value )
	end
	return true
end
duplicator.RegisterEntityModifier( "material", SaveMaterial )

local function SaveKeyvalue( Player, Entity, Data )
	Entity:SetKeyValue( Data.Key, Data.Value )
	if (SERVER) then
		duplicator.StoreEntityModifier( Entity, "keyvalue", Data, Value )
		end
	return true
	end
duplicator.RegisterEntityModifier( "keyvalue", SaveKeyvalue )

local function SaveName( Player, Entity, Data )
	Entity:SetKeyValue( Data.Key, Data.Value )
	if (SERVER) then
		duplicator.StoreEntityModifier( Entity, "targetname", Data, Value )
		end
	return true
end
duplicator.RegisterEntityModifier( "targetname", SaveName )

local function SaveHealth( Player, Entity, Data )
	Entity:SetHealth( Data.HealthOverride )
	if (SERVER) then
		duplicator.StoreEntityModifier( Entity, "health", Data, Value )
	end
	return true
end
duplicator.RegisterEntityModifier( "health", SaveHealth )

local function SaveInvincibility( Player, Entity, Data )
	Entity:SetKeyValue( Data.Key, Data.Value)
	if (SERVER) then
		duplicator.StoreEntityModifier( Entity, "damagefilter", Data, Value )
	end
	return true
end
duplicator.RegisterEntityModifier( "damagefilter", SaveInvincibility )

//***************************************
//	Some variables
//***************************************

local BLOCKS_FORCE_SPAWN = false
local USE_MCENTITY = 1
local firstspawn = 0

local zpos = 0
local lastmat = 0
local vmcheck = 1
local IsWeapon = 1
local Blah = false
local Bleh = false
	
//***************************************
//	Viewmodel position and animation
//***************************************
SWEP.thepos = Vector(1,1,1)
SWEP.theang = Vector(1,1,1)
SWEP.backuppos = Vector(1,1,1)
SWEP.backupang = Vector(1,1,1):Angle()
SWEP.counter = 0
SWEP.backcheck = false
SWEP.doanim = false
SWEP.animbackup = false

function SWEP:GetViewModelPosition( pos, ang )

	//HACKHACK: use fixed values here, constantly calling GetConVar() every frame is expensive!!! also, temporary fix for pistons
	local tempz = GetConVar("mc_viewmodel_z"):GetInt()
	if (GetConVar("minecraft_blocktype"):GetInt() == 44) then
		tempz = -49
	end
	local Pos = Vector (GetConVar("mc_viewmodel_x"):GetInt(),GetConVar("mc_viewmodel_y"):GetInt(),tempz)
	//print("posx = "..tostring(pos.x).." posy = "..tostring(pos.y).." posz = "..tostring(pos.z))
	ang:RotateAroundAxis( ang:Right(), GetConVar("mc_viewmodel_rot_x"):GetInt() )
	ang:RotateAroundAxis( ang:Forward(), GetConVar("mc_viewmodel_rot_y"):GetInt() )
	ang:RotateAroundAxis( ang:Up(), GetConVar("mc_viewmodel_rot_z"):GetInt() )

	local Right	 = ang:Right()
	local Up		 = ang:Up()
	local Forward	 = ang:Forward()
	
	local posbackup = pos;
	local angbackup = ang

	pos = pos + Pos.x * Right
	pos = pos + Pos.y * Forward
	pos = pos + Pos.z * Up
	
	if (self.doanim) then
			ang:RotateAroundAxis( ang:Right(), self.theAng.x*self.counter)
			ang:RotateAroundAxis( ang:Forward(), self.theAng.y*self.counter)
			ang:RotateAroundAxis( ang:Up(), self.theAng.z*self.counter)
			
			pos = pos + self.thePos.x * ang:Right() * self.counter
			pos = pos + self.thePos.y * ang:Forward() * self.counter
			pos = pos + self.thePos.z * ang:Up() * self.counter
	else
		if (self.backuppos != posbackup || self.backupang != angbackup) then
			self.backuppos = posbackup
			self.backupang = angbackup
		end
	end
	return pos, ang
end

//***************************************
//	Reload pops up the menu
//***************************************

function SWEP:Reload()
	Bleh = true
	if (Blah == false) then
		Blah = true
		if (firstspawn == 0) then
			if (SERVER) then
				RunConsoleCommand("mc_menu"); //normal
			end
		end
		if (firstspawn == 1) then
			if (SERVER) then
				RunConsoleCommand("mc_firstinfo") //first time
				firstspawn = 0
			end
		end
	end
end

//***************************************
//	Think & material think
//***************************************

function SWEP:Think()  
	self:VMThink()
	self:MatThink() //HACKHACK: calling this function every think cycle is somewhat stupid, and pretty expensive (because of SetNetworkedVar)
	if (vmcheck == 1) then //only exec the viewmodel:SetModel function when m_iMat changes (and not every think) to save performance
		self:ViewmodelThink()
		vmcheck = 0
	end
	if (Bleh == false) then
		Blah = false
	end
	Bleh = false
	
	if (SERVER) then return end
	
	//the viewmodel animation
	if (GetConVar("mc_viewmodel_doanim"):GetBool()) then
		self.doanim = true
		self.backcheck = false;
		self.counter = 0;
		RunConsoleCommand("mc_viewmodel_doanim","0")
	end
	
	if (self.doanim || GetConVar("mc_viewmodel_animtest"):GetBool()) then
		//back anim
		if (self.backcheck == true) then																											   //wat
			self.thePos = - Vector(GetConVar("mc_viewmodel_dx"):GetInt(),GetConVar("mc_viewmodel_dy"):GetInt(),GetConVar("mc_viewmodel_dz"):GetInt()*(self.counter/(2-(self.counter/(2-self.counter)))));
			self.theAng = - Vector(GetConVar("mc_viewmodel_rot_dx"):GetInt(),GetConVar("mc_viewmodel_rot_dy"):GetInt(),GetConVar("mc_viewmodel_rot_dz"):GetInt())
			
			self.counter = self.counter - GetConVar("mc_viewmodel_animspeed_back"):GetFloat()
			//end
			if (self.counter < 0) then
				self.backcheck = false;
				self.counter = 0
				self.doanim = false
				self.animbackup = false
				RunConsoleCommand("mc_viewmodel_doanim","0")
				//if (GetConVar("minecraft_debug"):GetBool()) then print("animation stop!") end
			end
		end
		//forward anim
		if (self.counter <= 1 && !self.backcheck) then
			self.thePos = - Vector(GetConVar("mc_viewmodel_dx"):GetInt(),GetConVar("mc_viewmodel_dy"):GetInt(),GetConVar("mc_viewmodel_dz"):GetInt());
			self.theAng = - Vector(GetConVar("mc_viewmodel_rot_dx"):GetInt(),GetConVar("mc_viewmodel_rot_dy"):GetInt(),GetConVar("mc_viewmodel_rot_dz"):GetInt())
			
			self.counter = self.counter + GetConVar("mc_viewmodel_animspeed"):GetFloat()
		end
		//switch from forward to back
		if (self.counter > 1 && !self.backcheck) then
			if (!self.animbackup) then
				self.BackupPos = -self.backuppos
				self.BackupAng = -self.backupang
				self.animbackup = true
			end		
			self.backcheck = true
		end
	end
end

function SWEP:MatThink()
	self:SetNetworkedVar("m_iMat", GetConVar("minecraft_blocktype"):GetInt());
	self:SetNetworkedVar("m_iSkin", GetConVar("minecraft_blockSkin"):GetInt());	
end

function SWEP:ViewmodelThink()
	if (!ValidEntity(self:GetOwner())) then return end
	
	local VM = self:GetOwner():GetViewModel();
	if (!ValidEntity(VM)) then return end
	
	for i,c in ipairs( BlockTypes ) do
		if (BlockTypes[i].blockID == GetConVar("minecraft_blocktype"):GetInt()) then
			VM:SetModel(BlockTypes[i].model);
		end
	end
	VM:SetSkin( GetConVar("minecraft_blockskin"):GetInt() )
end

function SWEP:VMThink()
	if (lastmat != (self:GetMat())) then
		vmcheck = 1
	end
	if (lastskin != (self:GetSkn())) then
		vmcheck = 1
	end
	lastmat = self:GetMat()
	lastskin = self:GetSkn()
end
	
//***************************************
//	Networked variables
//***************************************

AccessorFuncNW(SWEP,"m_iMat","CurrentMat",0,FORCE_NUMBER);

function SWEP:GetMat()
	return self:GetNetworkedInt("m_iMat");
end
function SWEP:GetSkn()
	return self:GetNetworkedInt("m_iSkin");
end
function SWEP:SetMat( matnumber )
	self:SetNetworkedVar("m_iMat", matnumber)
end

//***************************************
//	Main attack functions
//***************************************

function SWEP:AttackAnim()
	RunConsoleCommand("mc_viewmodel_doanim","1")
end

function SWEP:SecondaryAttack()
	if (GetConVar("minecraft_swapattack"):GetInt() > 0) then
		self:MCPrimaryAttack()
	end
	if (GetConVar("minecraft_swapattack"):GetInt() < 1) then
		self:MCSecondaryAttack()
	end
end
function SWEP:PrimaryAttack()
	if (GetConVar("minecraft_swapattack"):GetInt() > 0) then
		self:MCSecondaryAttack()
	end
	if (GetConVar("minecraft_swapattack"):GetInt() < 1) then
		self:MCPrimaryAttack()
	end
end

//***************************************
//	MCSecondaryAttack (creates blocks)
//***************************************

function SWEP:MCSecondaryAttack()

	local tr = self.Owner:GetEyeTrace()
	local startpos = self.Owner:GetShootPos()
	local isBlock = false
	
	local tracedata = {}
	tracedata.start = startpos
	tracedata.endpos = tr.HitPos + tr.HitNormal * 20
	tracedata.filter = self.Owner
	
	local checktr = util.TraceLine(tracedata)
	if checktr.HitNonWorld then
		target = checktr.Entity
		if ( target ) then isBlock = true
		end
	end
	local checkent = 0
	local checkvec = Vector(0,0,0)
	if tr.HitNonWorld then
		checkent = tr.Entity
		checkvec = checkent:GetPos()
		if (GetConVar("minecraft_debug"):GetBool()) then print("checktr hit nonworld!") end
	end

	local SpawnPos = tr.HitPos + tr.HitNormal * 20
	
	local distvec = tr.HitPos - self.Owner:GetPos()
	local length = distvec:Length()
	
	if (GetConVar("minecraft_distancelimit"):GetInt() > 0) then
		if (length > GetConVar("minecraft_maxspawndist"):GetInt()) then
			isBlock = true
		end
	end
	
	// The rest is only done on the server
	if (!SERVER) then return end
	
	if ( isBlock == false && tr.HitWorld == false && (GetConVar("minecraft_spawntype"):GetInt() == 2 || GetConVar("minecraft_spawntype"):GetInt() == 1)) then
		
		//check wether we are placing on top, bottom, or the four sides
		local hitz = tr.HitPos.z
		local checkvecz = checkvec.z
		local hmc = hitz - checkvecz   //hmc should be about '16' when placing on top OR on bottom
		if (GetConVar("minecraft_debug"):GetBool()) then print("hmc = " .. tostring(hmc)) end
 
		if (hitz < 0) then
			hitz = - hitz
		end
		if (checkvecz <0) then
			checkvecz = - checkvecz
		end
		local hmc2 = hitz - checkvecz
		if (hmc2 < 0) then
			hmc2 = - hmc2
		end
		
		if (GetConVar("minecraft_debug"):GetBool()) then print("hmc2 = " .. tostring(hmc2)) end
		
		local toporbottom = 0
		if (hmc2 > 15.9 && hmc2 < 16.1) then // top OR bottom
			if (hmc < 0) then
				toporbottom = 2
				if (GetConVar("minecraft_debug"):GetBool()) then print("bottom = " .. tostring(toporbottom)) end 
			end
			if (hmc > 0) then
				toporbottom = 1
				if (GetConVar("minecraft_debug"):GetBool()) then print("top = " .. tostring(toporbottom)) end
			end
		end
		
		if (toporbottom == 0) then  //one of the four sides
			if (tr.HitPos.z > checkvec.z) then
				zpos = math.floor( SpawnPos.z / 36.5 ) * 36.5 + 0
				if (GetConVar("minecraft_debug"):GetBool()) then print("upper half") end
			end
			if (tr.HitPos.z < checkvec.z) then
				zpos = math.floor( SpawnPos.z / 36.5 ) * 36.5 + 0//36.5
				if (GetConVar("minecraft_debug"):GetBool()) then print("lower half") end
			end
		end
		
		if (toporbottom == 1) then //top
			zpos = math.floor( SpawnPos.z / 36.5 ) * 36.5 + 36.5
			if ((SpawnPos.z - zpos) < -1) then // bug!
				zpos = math.floor( SpawnPos.z / 36.5) * 36.5 + 0
			end
			if (GetConVar("minecraft_debug"):GetBool() == 1) then print("top->SpawnPos.z = " .. tostring(SpawnPos.z)) end
			if (GetConVar("minecraft_debug"):GetBool() == 1) then print("top->zpos = " .. tostring(zpos)) end
		end
		
		if (toporbottom == 2) then //bottom
			zpos = math.floor( SpawnPos.z / 36.5 ) * 36.5 + 0
			if ((SpawnPos.z - zpos) > 1) then // bug!
				zpos =math.floor( SpawnPos.z / 36.5 ) * 36.5 + 36.5
			end
			if (GetConVar("minecraft_debug"):GetBool() == 1) then print("bottom->SpawnPos.z = " .. tostring(SpawnPos.z)) end
			if (GetConVar("minecraft_debug"):GetBool() == 1) then print("bottom->zpos = " .. tostring(zpos)) end
		end
		
		if (GetConVar("minecraft_debug"):GetBool()) then print("isBlock == false!!, checkvec.z = " .. tostring(checkvec.z)) end
		if (GetConVar("minecraft_debug"):GetBool()) then print("HitPos.z = " .. tostring(tr.HitPos.z)) end
	end
	
	if ( isBlock == true) then //block is blocking the way
		if (GetConVar("minecraft_debug"):GetBool()) then print("isBlock is true!") end
	end
	if ( tr.HitWorld == true && isBlock == false && GetConVar("minecraft_spawntype"):GetInt() == 2) then  //no block nearby
		zpos = math.floor( SpawnPos.z / 36.5 ) * 36.5 + 0
		if (GetConVar("minecraft_debug"):GetBool()) then print("tr.HitWorld & isBlock = false") end
	end  
	
	if ( isBlock == false ) then  //pos is ok, block can be created
		
		//limit the blocktype convar
		if (GetConVar("minecraft_blocktype"):GetInt() > #BlockTypes) then
			RunConsoleCommand("minecraft_blocktype", #BlockTypes)
			print("nope.avi")
		end
		if (GetConVar("minecraft_blocktype"):GetInt() < 1) then
			print("why the f*ck should "..tostring(GetConVar("minecraft_blocktype"):GetInt()).." be a valid blocktype, seriously")
			RunConsoleCommand("minecraft_blocktype", "1")
		end
		
		local ent = 0
		local blockID = GetConVar("minecraft_blocktype"):GetInt()
		local typeID;
		for i,c in ipairs( BlockTypes ) do
			if (BlockTypes[i].blockID == GetConVar("minecraft_blocktype"):GetInt()) then
				typeID = i;
			end
		end

		//handle lava + water (they have their own spawn function)
		local mcblock = 1
		if (blockID != 41 && blockID != 42 && blockID != 81) then
			ent = ents.Create( "minecraft_block" )
			lavaorwater = 0
		else
			ent = ents.Create( "minecraft_block_waterized" )
			mcblock = 0
			local damping, density, buoyancy
			if (blockID == 41) then //water
				damping = 15
				density = 70
				buoyancy = 600
				lavaorwater = 0
				SpawnWaterizedBlock( ent, self:GetOwner(), damping, density, buoyancy, 1, blockID )
			end
			if (blockID == 42) then //lava
				damping = 40
				density = 90
				buoyancy = 300
				lavaorwater = 1
				SpawnWaterizedBlock( ent, self:GetOwner(), damping, density, buoyancy, 2, blockID )
			end
			if (blockID == 81) then //cobweb
				damping = 99
				density = 99
				buoyancy = 100
				lavaorwater = 1
				SpawnWaterizedBlock( ent, self:GetOwner(), damping, density, buoyancy, 3, blockID )
			end
		end
			
		//position the block according to a fixed grid which is relative to (0,0,0) in every map
		local xpos = math.floor( SpawnPos.x / 36.5 ) * 36.5 + 18.25
		local ypos = math.floor( SpawnPos.y / 36.5 ) * 36.5 + 18.25
		if (GetConVar("minecraft_spawntype"):GetInt() == 1) then
			zpos = math.floor( SpawnPos.z / 36.5 ) * 36.5 + 18.25
		end
        if (GetConVar("minecraft_spawntype"):GetInt() == 0) then
            zpos = SpawnPos.z
        end
		if (GetConVar("minecraft_debug"):GetBool()) then print("Block ("..tostring(xpos)..","..tostring(ypos)..","..tostring(zpos)..")") end
		
		//set the model, skin, some keyvalues, spawnflags
		ent:SetModel( BlockTypes[typeID].model )
		ent:SetSkin( GetConVar("minecraft_blockskin"):GetInt() )
		//HACKHACK: the piston model spawns lower than all other blocks
		if (GetConVar("minecraft_blocktype"):GetInt() == 44) then
			if (USE_MCENTITY == 0) then
				ent:SetPos( Vector( xpos, ypos, zpos + 28.5 ) )
			else
				ent:SetPos( Vector( xpos, ypos, zpos ) )
			end
		else
			ent:SetPos( Vector( xpos, ypos, zpos ) )
		end
		ent:PhysicsInitBox( SpawnPos + Vector( -18.25, -18.25, -18.25 ), SpawnPos + Vector(  18.25,  18.25,  18.25 ) )
		ent:SetKeyValue( "DisableShadows", "1" )
		ent:SetKeyValue( "targetname", "mcblock" )
		if (USE_MCENTITY == 0) then
			ent:SetKeyValue( "spawnflags", 8 ) //disable movement!
		end
		
		//finally, spawn the entity
		if (mcblock == 1 && USE_MCENTITY == 1) then
			if (SpawnMinecraftBlock( ent, tr.Entity, self:GetOwner(), GetConVar("minecraft_blocktype"):GetInt(), GetConVar( "minecraft_blockrotation" ):GetInt() ) != nil) then
				self:AttackAnim()
			end
		else
			ent:Spawn()
			self:AttackAnim()
		end

		//create the undo object
		undo.Create("MC Block")
			undo.AddEntity( nocl )
			undo.AddEntity( ent )
			undo.SetPlayer( self.Owner )
			undo.SetCustomUndoText( "Undone MC block" )
			undo.Finish()
	end
end

//***************************************
//	MCPrimaryAttack (deletes blocks)
//***************************************

function SWEP:MCPrimaryAttack()

	local tr = self.Owner:GetEyeTrace()
	local distvec = tr.HitPos - self.Owner:GetPos()
	local length = distvec:Length()
	
	if (!tr.Entity:IsValid()) then return end
	if (GetConVar("minecraft_deletemconly"):GetInt() > 0 && tr.Entity:GetName() != "mcblock") then return end
	if (SERVER && tr.Entity:GetName() != "mcblock" && GetConVar("minecraft_deletemconly"):GetInt() > 0) then return end

	if (length < GetConVar("minecraft_maxspawndist"):GetInt() || GetConVar("minecraft_distancelimit"):GetInt() == 0) then
		if tr.HitNonWorld then
			target = tr.Entity  
			if (target) then
				self:ShootEffects( self )

				local effectdata = EffectData()
				effectdata:SetOrigin( target:GetPos() )
				effectdata:SetNormal( tr.HitNormal )
				effectdata:SetMagnitude( 8 )
				effectdata:SetScale( 1 )
				effectdata:SetRadius( 16 )
				util.Effect( "GlassImpact", effectdata )
			end
		end

		// The rest is only done on the server
		if (!SERVER) then return end
	 
		local trace = self.Owner:GetEyeTrace();
		if( not trace.HitWorld ) then // if you hit an entity
			if (tr.Entity:GetClass() == "minecraft_block" || tr.Entity:GetClass() == "mc_tnt") then
				trace.Entity.health = -2; //change -2 to -1 to disable particle effects and sounds on block destroy
			end
			self:AttackAnim()
			trace.Entity:Remove()
		end
	end
end
	
//*******************************************
//	OnRemove - reset the viewmodel material
//*******************************************

function SWEP:OnRemove()
	if(ValidEntity(self:GetOwner())) then
		local VM = self:GetOwner():GetViewModel();
		//if not VM:IsValid() then return end
		if(ValidEntity(VM)) then
			VM:SetMaterial("");
		end
	end
	IsWeapon = 0
end

function SWEP:ShouldDropOnDie()
	return false
end

//*******************************************
//	Holster - reset the viewmodel material
//*******************************************

function SWEP:Holster()
	if(ValidEntity(self:GetOwner())) then
		local VM = self:GetOwner():GetViewModel();
		if(ValidEntity(VM)) then
			VM:SetMaterial("");
		end
	end
	IsWeapon = 0
	return true
end

//*******************************************
//	Deploy
//*******************************************

function SWEP:Deploy()
	//if (GetConVar("minecraft_debug"):GetBool() ) then print("block deploy()") end
	IsWeapon = 1
	self:ViewmodelThink()
	return true
end

//**********************************************
//	Remove all entities with the name "mcblock"
//**********************************************

function removeall()
	for k, v in pairs( ents.FindByName( "mcblock" ) ) do
		if ( v:IsValid() ) then
			if (SERVER) then
				v.Entity.health = -1
				v:Remove()
			end
		end
	end
end

//*******************************************
//	Remove all blocks of the selected type
//*******************************************

function removeselected()
	local selectedmodel;
	for i,c in ipairs( BlockTypes ) do
		if (BlockTypes[i].blockID == GetConVar("minecraft_blocktype"):GetInt()) then
			selectedmodel = string.lower( BlockTypes[i].model );
		end
	end
	local selectedskin = GetConVar( "minecraft_blockskin" ):GetInt()
	for k, v in pairs( ents.FindByName( "mcblock" ) ) do
		if ( v:IsValid() ) then
			if (SERVER) then
				if v:GetModel() == selectedmodel then
					if v:GetSkin() == selectedskin then
						v.Entity.health = -1
						v:Remove()
					end
				end
			end
		end
	end
end

//*******************************************
//	update ALL the blocks!
//*******************************************

function forceblockupdate()
	for k, v in pairs( ents.FindByClass( "minecraft_block*") ) do
		if ( v:IsValid() ) then
			if (SERVER) then
				v:SetNWBool("doUpdate",true)
			end
		end
	end
end

//*******************************************************
//	Spawn a waterized entity (used in MCSecondaryAttack)
//*******************************************************

function SpawnWaterizedBlock( ent, ply, damping, density, buoyancy, btype, blockID )
	if not ent:IsValid() then print("/)^3^\(\ ") return end
	ent:SetPlayer( ply )

	ent:SetDamping( damping )
	ent.damping = damping
	ent:SetDensity( density )
	ent.density = density
	ent:SetBuoyancy( buoyancy )
	ent.buoyancy = buoyancy
	
	ent:SetKeyValue( "DisableShadows", "1" )
	ent:SetKeyValue( "targetname", "mcblock" )
	
	if (btype == 1) then
		ent:SetNetworkedString( "water", "true" )
		ent:SetNetworkedString( "lava", "false" )
		ent.maxspread = GetConVar("minecraft_water_maxspread"):GetInt()
		ent:SetNetworkedInt("blockID",blockID)
		ent.parent = 1
		ent.dt.blockID = 41
	end
	if (btype == 2) then
		ent:SetNetworkedString( "lava", "true" )
		ent:SetNetworkedString( "water", "false" )
		ent.maxspread = GetConVar("minecraft_lava_maxspread"):GetInt()
		ent:SetNetworkedInt("blockID",blockID)
		ent.parent = 1
		ent.dt.blockID = 42
	end
	if (btype == 3) then
		ent:SetNetworkedString( "lava", "false" )
		ent:SetNetworkedString( "water", "false" )	
		ent:SetNetworkedInt("blockID",blockID)
		ent.maxspread = 0
		ent.parent = 0
	end
	
	ent:SetNetworkedBool("doUpdate",true)
	
	if (GetConVar("minecraft_debug"):GetBool() && GetConVar("minecraft_water_spread"):GetBool() && btype != 3) then ent:SetColor(255,0,0,255) end
	
	ent:Spawn()
	ent:PostSpawn()
	return ent
end

//*******************************************************
//	Spawn a minecraft block (used in MCSecondaryAttack)
//*******************************************************

function SpawnMinecraftBlock( ent, hitEntity, ply, blocktype, rotation )
	if not ent:IsValid() then print("dumb fabric") return end
	ent:SetPlayer( ply )
	
	ent:SetBlockID( blocktype )
	ent:SetRotation( rotation )
	ent:BlockInit( blocktype, hitEntity )
	
	if (!BLOCKS_FORCE_SPAWN) then
		local check = ent:CheckPos( blocktype )
		if (!check) then 
			if (GetConVar("minecraft_debug"):GetBool()) then print("[CheckPos()] blocks would overlap!") end
			ent:Remove() 
			return nil
		end
	
		//check for already existing blocks (to avoid overlapping)
		for k, v in pairs( ents.FindByClass( "minecraft_block" ) ) do
			if ( v:IsValid() ) then
				if ( v:GetPos() == ent:GetPos() && v != ent ) then
					if (GetConVar("minecraft_debug"):GetBool()) then print("[GetPos()] blocks would overlap!") end
					ent:Remove()
					return nil
				end
			end
		end
	end
	
	ent:SetNetworkedBool("doUpdate",true)
	
	if (GetConVar("minecraft_blockrotation_force"):GetBool()) then
		ent:SetAngles(Vector( 0, GetConVar( "minecraft_blockrotation" ):GetInt(), 0 ))
	end
	
	ent:OnSpawn( blocktype, hitEntity )
	ent:Spawn()
	ent:PostSpawn( blocktype )
	return ent
end

duplicator.RegisterEntityClass( "minecraft_block_waterized", SpawnWaterizedBlock, "damping", "density", "buoyancy", "waterorlava" )
duplicator.RegisterEntityClass( "minecraft_block", SpawnMinecraftBlock, "blocktype", "rotation" )

concommand.Add("minecraft_removeallblocks", removeall)
concommand.Add("minecraft_removeselectedblocks", removeselected)
concommand.Add("minecraft_forceblockupdate", forceblockupdate)