
Building = inherited("Building", SimEntity)

Network.registerClass(Building)

Building.variables = {
	sync = {"health"},
	new = {"map", "team", "x", "y", "health"},
}
Building.structure = {
	sync = {"f"},
	new = {"e", "e", "f", "f", "f"},
}



function Building:new(map, team, x, y, health)
	local b = instance(self, map, team, x, y, health)
	return b
end

function Building:onNew(map, team, x, y, health)
	self.map = map
	self.team = team
	self.owner = team
	self.x = x
	self.health = health
	self.maxHealth = health
	self.y = y
	self.time = 0
	team:addEnt(self)
	team:addBuilding(self)
end

function Building:getStepFrequency()
	return APP.tickTime*3
end

function Building:isAlive()
	return not self.dead
end

function Building:getHealthPercent()
	return self.health/self.maxHealth
end

function Building:addSpeed()
end

function Building:canLaunch()
	return false
end

function Building:getCharge()
	return nil
end

function Building:isBackground()
	return self:isActive()
end

function Building:wantsResource(res)
	return false
end

function Building:canBeHurtBy(ent)
	return self:getOwner() ~= ent:getOwner()
end


function Building:onFakeEvent(e)
	if e == "remove" then
		for i=1,math.random(5,12) do
			local fx = Fx:new(FX_TYPES.smoke, self.map, self.x+math.randomGaussian()*self:getEffectRadius()+math.randomGaussian()*350, self.y+math.randomGaussian()*self:getEffectRadius()+math.randomGaussian()*350, math.randomGaussian()*850, math.randomGaussian()*850)
			fx:setDelay((i-1)*0.01*math.random())
			fx:setScale(3)
		end
		for i=1,math.random(5,12) do
			local fx = Fx:new(FX_TYPES.explosion, self.map, self.x+math.randomGaussian()*self:getEffectWidth(), self.y-self:getEffectHeight()*math.random(), math.randomGaussian()*850, math.randomGaussian()*850)
			fx:setDelay((i-1)*0.05*math.random())
			fx:setScale(4)
		end
	end
end

function Building:getEffectWidth()
	if self.getRadius then
		return self:getRadius()*0.5
	else
		return self:getWidth()*0.5
	end
end

function Building:getEffectHeight()
	if self.getRadius then
		return self:getRadius()*0.5
	elseif self.getHeight then
		return self:getHeight()*0.5
	else
		return 50
	end
end


function Building:isBuilding()
	return true
end

function Building:getRenderRadius()
	if self.getRadius then
		return self:getRadius()
	else
		return self:getWidth()
	end
end

function Building:getEffectRadius()
	return self:getWidth()*0.5
end

function Building:getOwner()
	return self.owner
end

function Building:hurt(h)
	self.health = math.max(0,self.health -h)
	self:onHurt(h)
end

function Building:onHurt()

end

function Building:onCollided(normal, impulse, torque)
	local impulseDamage = impulse/self:getMass()
	if impulseDamage > 1 then
		local damage = impulseDamage - 1
		self:hurt(damage)
	end
end

function Building:getHealthWidth()
	return self:getWidth()
end

function Building:renderHealthBar(x,y,scale, angle, a, r, g, b)
	if not self:isAlive() then
		if math.cos(self.time*math.pi*2) > 0 then
			video.renderHealthBar(self:getHealthPercent(), x, y + 60*scale, self:getHealthWidth(), 15, scale, 128, 200, 0, 0)
		end
	else
		video.renderHealthBar(self:getHealthPercent(), x, y + 60*scale, self:getHealthWidth(), 15, scale, 128, 0, 200, 0)
	end
end

function Building:getMass()
	return 100
end

function Building:onHit(ent, angle, impulse, counterImpulse)
	--if impulse > 10 then
	ent:onCollided(angle+math.pi, counterImpulse*0.1, 0)
	--end
end	

function Building:placeIntoMap()
	if self:isActive() then
		self.map:flattenAt(self.x,self.y,self:getWidth()*1.2)
		self.map:addEnt(self)
	else
		self.y = self.map:findLowestTerrain(self.x,self.y,self:getWidth())
		self.map:addBackground(self)
	end
end

function Building:remove()
	self.team:removeEnt(self)
	self.team:removeBuilding(self)
	if self:isActive() then
		self.map:removeEnt(self)
	else
		self.map:removeBackground(self)
	end
end

function Building:canSpawnShip()
	return false
end

function Building:getWidth()
	return 32
end

function Building:onDestroy()

end

function Building:step(time)
	if self.health <= 0 then
		self.health = 0
		if not self.dead then
			self.dead = true
			self:onDestroy()
		end
	end

	if self.dead and self.health >= self.maxHealth then
		self.dead = false
	end
end

function Building:renderAt(x,y,scale,angle,a,r,g,b)
	video.renderSpriteState(SPRITES.square, x, y, scale/8, angle, a, r, g, b)
end



Nexus = inherited("Nexus", Building)

Network.registerClass(Nexus)

Nexus.variables = {
	sync = {"health"},
	new = {"map", "team", "x", "y", "var"},
}
Nexus.structure = {
	sync = {"f"},
	new = {"e", "e", "f", "f", "i"},
}

Nexus.spriteNames = {
	mojans1 = "mojans_buildingA",
	mojans2 = "mojans_buildingB",
	mojans3 = "mojans_buildingC",
	daisies1 = "daisys_buildingA",
	daisies2 = "daisys_buildingB",
	daisies3 = "daisys_buildingC",
}

function Nexus:new(map, team, x, y, var)
	local b = instance(self, map, team, x, y, 5)
	b.var = var
	b:placeIntoMap()
	return b
end

function Nexus:step(time)
	self:super().step(self, time)
end

function Nexus:getWidth()
	return 1000
end

function Nexus:isActive()
	return false
end

function Nexus:getMass()
	return 1000
end

function Nexus:renderAt(x,y,scale,angle,a,r,g,b)
	video.renderSpriteState(self.sprites[self.team.name..self.var], x, y, scale, angle, a, r*0.8, g*0.6, b*0.4)
end



MissileSilo = inherited("MissileSilo", Building)

Network.registerClass(MissileSilo)

MissileSilo.variables = {
	sync = {"launchProgress", "dead", "launching"},
	new = {"map", "team", "x", "y"},
}
MissileSilo.structure = {
	sync = {"f", "b", "b"},
	new = {"e", "e", "f", "f"},
}

MissileSilo.interpolation = {
	launching = INTERPOLATORS.bool,
}


MissileSilo.handling = {
	launching = function(self, from, to)
		if from ~= to and to then
			sound.playSound("indicatorWarningE", 1, 0, 1)
		end
	end,
}


MissileSilo.spriteNames = {
	main = "silo",
}

function MissileSilo:new(map, team, x, y)
	local b = instance(self, map, team, x, y, 2000)
	b:placeIntoMap()
	b.launchProgress = 0
	b.time = 0
	return b
end

function MissileSilo:step(time)
	self:super().step(self, time)
	if self:isAlive() then
		if self.launching then
			self.launchProgress = self.launchProgress + time/1
			if self.launchProgress >= 1 then
				self:launch()
			end
		end
	else
		self.launching = false
	end
	if self.health < self.maxHealth then
		self.health = math.min(self.maxHealth,self.health + time*15)
	end

	self.time = self.time + time
end

function MissileSilo:fakeStep(time)
	self.time = self.time + time
end

function MissileSilo:getWidth()
	return 600
end

function MissileSilo:canLaunch()
	return true
end

function MissileSilo:getHealthWidth()
	return self:getWidth()*0.5
end

function MissileSilo:attemptLaunch()
	if self:isAlive() then
		for index, build in pairs(self.team.buildings) do
			if build.parent == self then
				if not build:isActive() or build:getCharge() < 1 then
					return
				end
			end
		end
	end
	self.launching = true
end

function MissileSilo:launch()
	if self:isAlive() then
		for index, build in pairs(self.team.buildings) do
			if build.parent == self then
				if build:getCharge() >= 1 then
					build.charge = 0
				else
					self.launching = false
					return
				end
			end
		end
		self.map.sim:create(Missile, self.map, self.team, self.x ,self.y+200,-math.pi*0.5, 0,0,0, MISSILE_TYPES.nuke)
	end
	self.launching = false
end

function MissileSilo:getMass()
	return 500
end


function MissileSilo:isActive()
	return true
end

function MissileSilo:renderAt(x,y,scale,angle,a,r,g,b)
	if not self:isAlive() then
		r = r*0.5
		g = g*0.5
		b = b*0.5
	end
	video.renderSpriteState(self.sprites.main, x, y, scale, angle, a, r*0.8, g*0.8, b*0.8)
end


function MissileSilo:renderHudAt(x,y,scale,angle,a,r,g,b)
	self:renderHealthBar(x,y,scale,angle,a,r,g,b)
end



Battery = inherited("Battery", Building)

Network.registerClass(Battery)

Battery.variables = {
	sync = {"health", "charge", "dead"},
	new = {"map", "team", "x", "y"},
}
Battery.structure = {
	sync = {"f", "f", "b"},
	new = {"e", "e", "f", "f"},
}

Battery.interpolation = {
	dead = INTERPOLATORS.bool,
}

Battery.spriteNames = {
	main = "battery",
	light = "battery_indicatorOn",
}

function Battery:new(map, team, x, y)
	local b = instance(self, map, team, x, y, 250)
	b.charge = 0
	b.time = 0
	b:placeIntoMap()
	return b
end

function Battery:isCharged()
	return self.charge >= 1
end

function Battery:step(time)
	self:super().step(self, time)
	if self.health < self.maxHealth then
		self.health = math.min(self.maxHealth,self.health + time*10)
	end
end

function Battery:fakeStep(time)
	self.time = self.time + time
end

function Battery:getWidth()
	return 140
end

function Battery:getMass()
	return 200
end

function Battery:wantsResource(res)
	return self.charge < 1 and self:isAlive()
end

function Battery:onDestroy()
	if self.charge > 0 then
		for i=1,math.ceil(self.charge*4) do
			local ang = -math.random()*math.pi*0.2 - math.pi*0.4
			local speed = math.random()*2000 + 2000
			self.map.sim:create(Resource, self.map, self.map, self.x , self.y - self:getHeight()*1.5, math.cos(ang)*speed, math.sin(ang)*speed, RESOURCE_TYPES.plutonium)
		end
		self.charge = 0
	end
end

function Battery:getCharge()
	return self.charge
end

function Battery:addResource(res)
	if self:isAlive() and self.charge < 1 then
		self.charge = math.clamp(self.charge +1, 0, 1)
		self.parent:attemptLaunch()
		return true
	else
		return false
	end
end

function Battery:isTarget()
	return self:isAlive()
end

function Battery:getHeight()
	return 220
end

function Battery:isActive()
	return true
end

function Battery:renderAt(x,y,scale,angle,a,r,g,b)
	if not self:isAlive() then
		r = r*0.5
		g = g*0.5
		b = b*0.5
	end
	video.renderSpriteState(self.sprites.main, x, y, scale, angle, a, r, g, b)
	for i=0,3 do
		local amt = math.clamp(self.charge*4 - i, 0, 1)
		local dist = (i*37 + 29)
		local rx, ry = x + math.cos(angle-math.pi*0.5)*dist*scale, y + math.sin(angle-math.pi*0.5)*dist*scale
		video.renderSpriteState(self.sprites.light, rx, ry, scale, angle, 255*amt, 255, 255, 255)
	end
end


function Battery:renderHudAt(x,y,scale,angle,a,r,g,b)
	self:renderHealthBar(x,y,scale,angle,a,r,g,b)
end


StarPort = inherited("StarPort", Building)

Network.registerClass(StarPort)

StarPort.variables = {
	sync = {"health"},
	new = {"map", "team", "x", "y"},
}
StarPort.structure = {
	sync = {"f"},
	new = {"e", "e", "f", "f"},
}

StarPort.spriteNames = {
	mojans = "mojans_landingPad",
	daisies = "daisys_landingPad",
}


function StarPort:new(map, team, x, y)
	local b = instance(self, map, team, x, y, 2000)
	b:placeIntoMap()
	return b
end

function StarPort:getWidth()
	return 700
end

function StarPort:getHeight()
	if self.team.name == "mojans" then
		return 67
	else
		return 107
	end
end

function StarPort:getMass()
	return 1000
end

function StarPort:onDestroy()
	self:remove()
end

function StarPort:canSpawnShip()
	return true
end

function StarPort:isTarget()
	return true
end

function StarPort:isActive()
	return true
end

function StarPort:step(time)
	self:super().step(self, time)
end

function StarPort:renderAt(x,y,scale,angle,a,r,g,b)
	video.renderSpriteState(self.sprites[self.team.name], x, y, scale, angle, a, r, g, b)
end

function StarPort:renderHudAt(x,y,scale,angle,a,r,g,b)
	self:renderHealthBar(x,y,scale,angle,a,r,g,b)
end


ShieldGenerator = inherited("ShieldGenerator", Building)

Network.registerClass(ShieldGenerator)

ShieldGenerator.variables = {
	sync = {"health"},
	new = {"map", "team", "x", "y"},
}
ShieldGenerator.structure = {
	sync = {"f"},
	new = {"e", "e", "f", "f"},
}

ShieldGenerator.spriteNames = {
	main = "battery",
	light = "battery_indicatorOn",
}


function ShieldGenerator:new(map, team, x, y)
	local b = instance(self, map, team, x, y, 400)
	b.baseSprite = video.createSpriteState("shieldGen_base", "../ingameGFX.dat")
	b.onSprite = video.createSpriteState("shieldGen_on", "../ingameGFX.dat")	
	b:placeIntoMap()
	return b
end

function ShieldGenerator:getWidth()
	return 150
end

function ShieldGenerator:isActive()
	return false
end


function ShieldGenerator:getMass()
	return 500
end



function ShieldGenerator:step(time)
	self:super().step(self, time)
end

function ShieldGenerator:fakeStep(time)
	video.updateSpriteState(self.baseSprite, time)
	video.updateSpriteState(self.onSprite, time)
end

function ShieldGenerator:renderAt(x,y,scale,angle,a,r,g,b)
	video.renderSpriteState(self.baseSprite, x, y, scale, angle, a, r, g, b)
	video.renderSpriteState(self.onSprite, x, y, scale, angle, a, 255, 255, 255)
end



Shield = inherited("Shield", Building)

Network.registerClass(Shield)

Shield.variables = {
	sync = {"health","flash", "dead",},
	new = {"map", "team", "x", "y", "radius"},
}
Shield.structure = {
	sync = {"f","f", "b"},
	new = {"e", "e", "f", "f", "f"},
}

Shield.spriteNames = {
	mojansmain = "shield",
	daisiesmain = "shield2",
}

Shield.interpolation = {
	dead = INTERPOLATORS.bool,
}


function Shield:new(map, team, x, y, radius)
	local b = instance(self, map, team, x, y, 5000)
	b.radius = radius
	b.flash = 0
	b:placeIntoMap()
	return b
end

function Shield:getRadius()
	return self.radius
end

function Shield:canCollideWith(ent)
	return self:isAlive()
end

function Shield:onHurt(h)
	self.flash = math.min(1,h/25)
end

function Shield:isBackground()
	return true
end

function Shield:getHealthWidth()
	return self:getRadius()*0.25
end

function Shield:isTarget()
	return self:isAlive()
end

function Shield:getEffectRadius()
	return self:getRadius()
end

function Shield:isProtective()
	return self:isAlive()
end

function Shield:isActive()
	return true
end

function Shield:getMass()
	return 500
end

function Shield:step(time)
	self:super().step(self, time)
	if self.flash > 0 then
		self.flash = math.max(self.flash - time)
	end
end

function Shield:fakeStep(time)
	video.updateSpriteState(self.baseSprite, time)
	video.updateSpriteState(self.onSprite, time)
end

function Shield:onFakeEvent(e)

end

function Shield:renderAt(x,y,scale,angle,a,r,g,b)
	if self:isAlive() then
		local col = self.team:def().shieldColor
		video.renderSpriteState(self.sprites[self.team.name.."main"], x, y, scale/922*self.radius*2, angle, a*0.25 + 0.75*a*self:getHealthPercent(), 255,255,255)
		if self.flash > 0 then
			local fl = math.pow(self.flash,2)
			video.renderSpriteState(self.sprites[self.team.name.."main"], x, y, scale/922*self.radius*2, angle, fl*a*self:getHealthPercent(), 255,255,255)
		end
	end
end
