BBOX = {"LEFT","TOP","RIGHT","BOTTOM"}
for k,v in ipairs(BBOX)
	BBOX[v] = k
end

NPCF = {
	BLOCKING = 1, -- Solid NPC
	UNBLOCKED = 1<<0x1, -- Not blocked by NPC-blocking tile types (type 44)
	BLOCK_SHOTS = 1<<0x2, -- Bullets bounce off with a cutesy 'tink' sound
	NOCLIP = 1<<0x3, -- Ignores solid tiles
	TOPBOUNCE = 1<<0x4, -- If you jump on top of it, you bounce around!
	SHOOTABLE = 1<<0x5, -- Thing eats bullets!
	SOLID = 1<<0x6, -- Tile-like absolute solid.
	RIDE = 1<<0x7, -- No damage from the top or back of this object; You can ride it.
	TOUCH_EVENT = 1<<0x8, -- Call event when touched
	DEATH_EVENT = 1<<0x9, -- Call event when killed
	DROP_ITEMS = 1<<0xA, -- Drop exp, health, missiles, etc.
	IF_FLAG = 1<<0xB, -- Only appear if flag is set
	FLIP = 1<<0xC, -- Face the other way / other effects
	CHECK_EVENT = 1<<0xD, -- Call event when checked (down)
	IF_NOFLAG = 1<<0xE, -- Only appear if flag is NOT set
	SHOW_DAMAGE = 1<<0xF -- Show damage numbers
}
NPCF.SERVER_ONLY = NPCF.TOUCH_EVENT|NPCF.DEATH_EVENT|NPCF.DROP_ITEMS|NPCF.IF_FLAG|NPCF.CHECK_EVENT|NPCF.IF_NOFLAG -- These flags will never be sent from the server.

NPC = {}
local entry_size = 2+2+1+1+1+1+4+4+4+4 -- flags+health+sheet+death+pain+smoke+exp+damage+collision+display
local tbl = io.open("npc.tbl",IO.READ,ENDIAN.NATIVE) -- We're not forcing an endian here, so mac people can use their own or whatever.
tbl:seek(0,SEEK.END) -- Go to the end of the file
local NPCMAX = math.floor(tbl:tell()/entry_size)-1 -- Use the file's length to get the number of npcs it contains.
console.debug("Found "..NPCMAX.." object entries in the npc table.")

if CLIENT
	tbl:seek(4*(NPCMAX+1),SEEK.SET) -- Skip the first two fields
	for i = 0,NPCMAX
		NPC[i] = {}
		NPC[i].sheet = tbl:getnum(1,UNSIGNED)
	end
	for i = 0,NPCMAX
		NPC[i].death = tbl:getnum(1,UNSIGNED)
	end
	for i = 0,NPCMAX
		NPC[i].pain = tbl:getnum(1,UNSIGNED)
	end
	for i = 0,NPCMAX
		NPC[i].smoke = tbl:getnum(1,UNSIGNED)
	end
	tbl:seek(4*(NPCMAX+1),SEEK.CUR) -- skip exp
else
	tbl:seek(0,SEEK.SET) -- Go back to the beginning
	for i = 0,NPCMAX
		NPC[i] = {}
		NPC[i].flags = tbl:getnum(2,UNSIGNED)
	end
	for i = 0,NPCMAX
		NPC[i].health = tbl:getnum(2,UNSIGNED)
	end
	tbl:seek(4*(NPCMAX+1),SEEK.CUR) -- skip sheet, death, pain, smoke
	for i = 0,NPCMAX
		NPC[i].exp = tbl:getnum(4,UNSIGNED)
	end
end
for i = 0,NPCMAX
	NPC[i].damage = tbl:getnum(4,UNSIGNED)
end
for i = 0,NPCMAX
	NPC[i].collision = {tbl:getnum(1,SIGNED),tbl:getnum(1,SIGNED),tbl:getnum(1,SIGNED),tbl:getnum(1,SIGNED)}
end
if CLIENT
	for i = 0,NPCMAX
		NPC[i].display = {tbl:getnum(1,SIGNED),tbl:getnum(1,SIGNED),tbl:getnum(1,SIGNED),tbl:getnum(1,SIGNED)}
	end
end
tbl:close()

local function loadNpc(name)
	ENT = {}
	include("Npc/"..name..".lua")
	for k,v in pairs(ENT)
		NPC[ENT.id][k] = v
	end
	ENT = nil
end

local npclist = io.open("npclist.txt",IO.READ)
for line in npclist:lines()
	if line != "" loadNpc(line) end
end
npclist:close()

function NPC:think()
	local info = NPC[self.type]
	if CLIENT
		if info.anims and info.anims[self.anim] and info.anims[self.anim][self.frame][3] >= 0
			if self.ticks >= info.anims[self.anim][self.frame][3]
				self.frame = self.frame+1
				if not info.anims[self.anim][self.frame]
					self.frame = 1
				end
				self.ticks = 0
			else
				self.ticks = self.ticks + 1
			end
		end
	end
	self.flip = self.flags & NPCF.FLIP ~= 0
	if info.think
		info.think(self)
	end
	self.x = self.x + self.mx
	self.y = self.y + self.my
end

if CLIENT include "Client/npc.lua" else include "Server/npc.lua" end
