diff --git a/game/engines/default/engine/Actor.lua b/game/engines/default/engine/Actor.lua
index ed10ec2057b5ab6cae15e89ea88575c0a0cb2cb0..fdb6751bcca8641860d52ec4b759721075e92084 100644
--- a/game/engines/default/engine/Actor.lua
+++ b/game/engines/default/engine/Actor.lua
@@ -60,6 +60,17 @@ end
 function _M:setTarget(target)
 end
 
+--- Setup minimap color for this entity
+-- You may overload this method to customize your minimap
+function _M:setupMinimapInfo(mo, map)
+	if map.actor_player and not map.actor_player:canSee(self) then return end
+	local r = map.actor_player and map.actor_player:reactionToward(self) or -100
+	if r < 0 then mo:minimap(240, 0, 0)
+	elseif r > 0 then mo:minimap(0, 240, 0)
+	else mo:minimap(0, 0, 240)
+	end
+end
+
 --- Adds a particles emitter following the actor
 function _M:addParticles(ps)
 	self.__particles[ps] = true
diff --git a/game/engines/default/engine/Entity.lua b/game/engines/default/engine/Entity.lua
index cf959cef24fb59aa99726c4fbaa8b17a612fcc36..dee17fd7df41d8384612e593aa1cee9f8e960fec 100644
--- a/game/engines/default/engine/Entity.lua
+++ b/game/engines/default/engine/Entity.lua
@@ -156,6 +156,11 @@ function _M:changeUid(newuid)
 	__uids[self.uid] = self
 end
 
+--- Setup minimap color for this entity
+-- You may overload this method to customize your minimap
+function _M:setupMinimapInfo(mo, map)
+end
+
 --- Create the "map object" representing this entity
 -- Do not touch unless you *KNOW* what you are doing.<br/>
 -- You do *NOT* need this, this is used by the engine.Map class automatically.<br/>
diff --git a/game/engines/default/engine/Grid.lua b/game/engines/default/engine/Grid.lua
index a9478cc7a9e151e7d661960fd5ee6bbaa41012a5..bc36bb7a069c908b716062e5185963c9eb17dea8 100644
--- a/game/engines/default/engine/Grid.lua
+++ b/game/engines/default/engine/Grid.lua
@@ -34,3 +34,11 @@ function _M:init(t, no_default)
 	self.name = t.name
 	Entity.init(self, t, no_default)
 end
+
+--- Setup minimap color for this entity
+-- You may overload this method to customize your minimap
+function _M:setupMinimapInfo(mo, map)
+	if self:check("block_move") then mo:minimap(240, 240, 240)
+	else mo:minimap(0, 0, 0)
+	end
+end
diff --git a/game/engines/default/engine/Map.lua b/game/engines/default/engine/Map.lua
index 90cf0aed37ef8bdd6c9699a335251d31e387c372..636661b87546af673fb42632a681ce167f816f07 100644
--- a/game/engines/default/engine/Map.lua
+++ b/game/engines/default/engine/Map.lua
@@ -61,59 +61,6 @@ color_shown   = { 1, 1, 1, 1 }
 color_obscure = { 0.6, 0.6, 0.6, 1 }
 smooth_scroll = 0
 
--- The minimap data
-MM_FLOOR = 1
-MM_BLOCK = 2
-MM_OBJECT = 4
-MM_TRAP = 8
-MM_FRIEND = 16
-MM_NEUTRAL = 32
-MM_HOSTILE = 64
-MM_LEVEL_CHANGE = 128
-
-local s_floor = core.display.newSurface(4, 4)
-s_floor:erase(0, 0, 0, 255)
-local s_floor_gl = s_floor:glTexture()
-
-local s_block = core.display.newSurface(4, 4)
-s_block:erase(240, 240, 240, 255)
-local s_block_gl = s_block:glTexture()
-
-local s_level_change = core.display.newSurface(4, 4)
-s_level_change:erase(240, 0, 240, 255)
-local s_level_change_gl = s_level_change:glTexture()
-
-local s_hostile = core.display.newSurface(4, 4)
-s_hostile:erase(240, 0, 0, 255)
-local s_hostile_gl = s_hostile:glTexture()
-
-local s_friend = core.display.newSurface(4, 4)
-s_friend:erase(0, 240, 0, 255)
-local s_friend_gl = s_friend:glTexture()
-
-local s_neutral = core.display.newSurface(4, 4)
-s_neutral:erase(0, 0, 240, 255)
-local s_neutral_gl = s_neutral:glTexture()
-
-local s_object = core.display.newSurface(4, 4)
-s_object:erase(0, 0, 240, 255)
-local s_object_gl = s_object:glTexture()
-
-local s_trap = core.display.newSurface(4, 4)
-s_trap:erase(240, 240, 0, 255)
-local s_trap_gl = s_trap:glTexture()
-
-mm_blocks = {
-	[MM_FLOOR] = s_floor_gl,
-	[MM_BLOCK] = s_block_gl,
-	[MM_LEVEL_CHANGE] = s_level_change_gl,
-	[MM_HOSTILE] = s_hostile_gl,
-	[MM_FRIEND] = s_friend_gl,
-	[MM_NEUTRAL] = s_neutral_gl,
-	[MM_OBJECT] = s_object_gl,
-	[MM_TRAP] = s_trap_gl,
-}
-
 --- Sets the viewport size
 -- Static
 -- @param x screen coordinate where the map will be displayed (this has no impact on the real display). This is used to compute mouse clicks
@@ -238,16 +185,6 @@ function _M:makeCMap()
 	self._map = core.map.newMap(self.w, self.h, self.mx, self.my, self.viewport.mwidth, self.viewport.mheight, self.tile_w, self.tile_h, self.zdepth)
 	self._map:setObscure(unpack(self.color_obscure))
 	self._map:setShown(unpack(self.color_shown))
-	self._map:setupMiniMap(
-		mm_blocks[MM_FLOOR],
-		mm_blocks[MM_BLOCK],
-		mm_blocks[MM_OBJECT],
-		mm_blocks[MM_TRAP],
-		mm_blocks[MM_FRIEND],
-		mm_blocks[MM_NEUTRAL],
-		mm_blocks[MM_HOSTILE],
-		mm_blocks[MM_LEVEL_CHANGE]
-	)
 	self._fovcache =
 	{
 		block_sight = core.fov.newCache(self.w, self.h),
@@ -385,7 +322,6 @@ end
 -- This updates many things, from the C map object, the FOV caches, the minimap if it exists, ...
 function _M:updateMap(x, y)
 	-- Update minimap if any
-	local mm = MM_FLOOR
 	local mos = {}
 
 	if not self.updateMapDisplay then
@@ -402,40 +338,39 @@ function _M:updateMap(x, y)
 				self._fovcache.path_caches[ps]:set(x, y, g:check("block_move", x, y, ps, false, true))
 			end
 
-			mm = mm + (g:check("block_move") and MM_BLOCK or 0)
-			mm = mm + (g:check("change_level") and MM_LEVEL_CHANGE or 0)
 			g:getMapObjects(self.tiles, mos, 1)
+			g:setupMinimapInfo(g._mo, self)
 		end
 		if t then
 			-- Handles trap being known
 			if not self.actor_player or t:knownBy(self.actor_player) then
 				t:getMapObjects(self.tiles, mos, 4)
-				mm = mm + MM_TRAP
+				t:setupMinimapInfo(t._mo, self)
 			else
 				t = nil
 			end
 		end
 		if o then
 			o:getMapObjects(self.tiles, mos, 7)
+			o:setupMinimapInfo(o._mo, self)
 			if self.object_stack_count then
 				local mo = o:getMapStackMO(self, x, y)
 				if mo then mos[9] = mo end
 			end
-			mm = mm + MM_OBJECT
 		end
 		if a then
 			-- Handles invisibility and telepathy and other such things
 			if not self.actor_player or self.actor_player:canSee(a) then
-				local r = self.actor_player:reactionToward(a)
-				mm = mm + (r > 0 and MM_FRIEND or (r == 0 and MM_NEUTRAL or MM_HOSTILE))
 				a:getMapObjects(self.tiles, mos, 10)
+				a:setupMinimapInfo(a._mo, self)
 			end
 		end
 		if p then
 			p:getMapObjects(self.tiles, mos, 13)
+			p:setupMinimapInfo(p._mo, self)
 		end
 	else
-		mm = self:updateMapDisplay(x, y, mos)
+		self:updateMapDisplay(x, y, mos)
 	end
 
 	-- Update entities checker for this spot
@@ -453,7 +388,7 @@ function _M:updateMap(x, y)
 	self._check_entities_store[ce] = self._check_entities[x + y * self.w]
 
 	-- Cache the map objects in the C map
-	self._map:setGrid(x, y, mm, mos)
+	self._map:setGrid(x, y, mos)
 
 	-- Update FOV caches
 	if self:checkAllEntities(x, y, "block_sight", self.actor_player) then self._fovcache.block_sight:set(x, y, true)
diff --git a/game/engines/default/engine/Object.lua b/game/engines/default/engine/Object.lua
index 6e76b21a035989d9c7d0aed71d312e0d6dbbb2b2..4f5db794c488cdaab5fd7d975471f5150754eb34 100644
--- a/game/engines/default/engine/Object.lua
+++ b/game/engines/default/engine/Object.lua
@@ -66,6 +66,12 @@ function _M:canAct()
 	return false
 end
 
+--- Setup minimap color for this entity
+-- You may overload this method to customize your minimap
+function _M:setupMinimapInfo(mo, map)
+	mo:minimap(0, 0, 240)
+end
+
 --- Do something when its your turn
 -- For objects this mostly is to recharge them
 -- By default, does nothing at all
diff --git a/game/engines/default/engine/Trap.lua b/game/engines/default/engine/Trap.lua
index 962904d4045d9b63c9b9f7c53abd81deaba0dda5..60e5083659880787689fd05d8e6d9e1a15b3f970 100644
--- a/game/engines/default/engine/Trap.lua
+++ b/game/engines/default/engine/Trap.lua
@@ -52,6 +52,12 @@ function _M:loaded()
 	setmetatable(self.known_by, {__mode="k"})
 end
 
+--- Setup minimap color for this entity
+-- You may overload this method to customize your minimap
+function _M:setupMinimapInfo(mo, map)
+	mo:minimap(240, 240, 0)
+end
+
 --- Do we have enough energy
 function _M:enoughEnergy(val)
 	val = val or game.energy_to_act
diff --git a/game/modules/tome/data/talents/spells/ice.lua b/game/modules/tome/data/talents/spells/ice.lua
index e3733469196d6c119247a9227c4c193fa9c1f016..4264b4a178f810223414b7a9cc1fdc86c66c3347 100644
--- a/game/modules/tome/data/talents/spells/ice.lua
+++ b/game/modules/tome/data/talents/spells/ice.lua
@@ -60,6 +60,7 @@ newTalent{
 	points = 5,
 	mana = 25,
 	cooldown = 10,
+	requires_target = true,
 	tactical = { ATTACKAREA = 2, DISABLE = 1 },
 	range = function(self, t) return 1 + self:getTalentLevelRaw(t) end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 180) end,
@@ -87,6 +88,7 @@ newTalent{
 	cooldown = 15,
 	tactical = { ATTACKAREA = 2 },
 	range = 10,
+	requires_target = true,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 180) end,
 	getTargetCount = function(self, t) return math.ceil(self:getTalentLevel(t) + 2) end,
 	action = function(self, t)
diff --git a/game/modules/tome/data/talents/spells/storm.lua b/game/modules/tome/data/talents/spells/storm.lua
index af2dd9c0e840fa8eb479fa4d63469b16cf6c1a4a..1050746c3bffa11c440fde4d94b206227b93f2e8 100644
--- a/game/modules/tome/data/talents/spells/storm.lua
+++ b/game/modules/tome/data/talents/spells/storm.lua
@@ -26,6 +26,7 @@ newTalent{
 	cooldown = 8,
 	tactical = { ATTACKAREA = 2, DISABLE =1 },
 	direct_hit = true,
+	requires_target = true,
 	range = function(self, t) return math.floor(2 + self:getTalentLevel(t) * 0.7) end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 28, 170) end,
 	action = function(self, t)
@@ -63,6 +64,7 @@ newTalent{
 	cooldown = 3,
 	tactical = { ATTACK = 2 },
 	range = 10,
+	requires_target = true,
 	reflectable = true,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 200) end,
 	action = function(self, t)
diff --git a/game/modules/tome/data/talents/spells/wildfire.lua b/game/modules/tome/data/talents/spells/wildfire.lua
index 1b95ac8c0419895a5aa2f06ccd189d09dd8b76ee..50c4c01c6b5cbac8f9368a1989c326ede9ee21f5 100644
--- a/game/modules/tome/data/talents/spells/wildfire.lua
+++ b/game/modules/tome/data/talents/spells/wildfire.lua
@@ -26,6 +26,7 @@ newTalent{
 	cooldown = 5,
 	tactical = { ATTACKAREA = 2, DISABLE = 2, ESCAPE = 2 },
 	direct_hit = true,
+	requires_target = true,
 	range = function(self, t) return 1 + self:getTalentLevelRaw(t) end,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 28, 180) end,
 	action = function(self, t)
@@ -51,6 +52,7 @@ newTalent{
 	cooldown = 16,
 	tactical = { ATTACKAREA = 2 },
 	range = 10,
+	requires_target = true,
 	getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 240) end,
 	getTargetCount = function(self, t) return math.ceil(self:getTalentLevel(t) + 2) end,
 	action = function(self, t)
diff --git a/src/core_lua.c b/src/core_lua.c
index bc0480a37ee48648dcf7ab2298da2bf04ae38248..02873e60cac01ba01d82ce230459c2190b8ca1af 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -532,16 +532,21 @@ static int gl_draw_quad(lua_State *L)
 	else
 		tglBindTexture(GL_TEXTURE_2D, 0);
 
-	tglColor4f(r, g, b, a);
-
 	GLfloat texcoords[2*4] = {
 		0, 0,
 		0, 1,
 		1, 1,
 		1, 0,
 	};
-
+	GLfloat colors[4*4] = {
+		r, g, b, a,
+		r, g, b, a,
+		r, g, b, a,
+		r, g, b, a,
+	};
+	glColorPointer(4, GL_FLOAT, 0, colors);
 	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+
 	GLfloat vertices[2*4] = {
 		x, y,
 		x, y + h,
@@ -549,9 +554,8 @@ static int gl_draw_quad(lua_State *L)
 		x + w, y,
 	};
 	glVertexPointer(2, GL_FLOAT, 0, vertices);
-	glDrawArrays(GL_QUADS, 0, 4);
 
-	tglColor4f(1, 1, 1, 1);
+	glDrawArrays(GL_QUADS, 0, 4);
 	return 0;
 }
 
@@ -738,7 +742,23 @@ static int sdl_surface_toscreen(lua_State *L)
 		float g = luaL_checknumber(L, 5);
 		float b = luaL_checknumber(L, 6);
 		float a = luaL_checknumber(L, 7);
-		tglColor4f(r, g, b, a);
+		GLfloat colors[4*4] = {
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
+	}
+	else
+	{
+		GLfloat colors[4*4] = {
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
 	}
 
 	GLuint t;
@@ -751,8 +771,6 @@ static int sdl_surface_toscreen(lua_State *L)
 
 	glDeleteTextures(1, &t);
 
-	if (lua_isnumber(L, 4)) tglColor4f(1, 1, 1, 1);
-
 	return 0;
 }
 
@@ -768,7 +786,23 @@ static int sdl_surface_toscreen_with_texture(lua_State *L)
 		float g = luaL_checknumber(L, 6);
 		float b = luaL_checknumber(L, 7);
 		float a = luaL_checknumber(L, 8);
-		tglColor4f(r, g, b, a);
+		GLfloat colors[4*4] = {
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
+	}
+	else
+	{
+		GLfloat colors[4*4] = {
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
 	}
 
 	tglBindTexture(GL_TEXTURE_2D, *t);
@@ -776,8 +810,6 @@ static int sdl_surface_toscreen_with_texture(lua_State *L)
 	copy_surface_to_texture(*s);
 	draw_textured_quad(x,y,(*s)->w,(*s)->h);
 
-	if (lua_isnumber(L, 5)) tglColor4f(1, 1, 1, 1);
-
 	return 0;
 }
 
@@ -862,7 +894,23 @@ static int sdl_texture_toscreen(lua_State *L)
 		float g = luaL_checknumber(L, 7);
 		float b = luaL_checknumber(L, 8);
 		float a = luaL_checknumber(L, 9);
-		tglColor4f(r, g, b, a);
+		GLfloat colors[4*4] = {
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
+	}
+	else
+	{
+		GLfloat colors[4*4] = {
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
 	}
 
 	tglBindTexture(GL_TEXTURE_2D, *t);
@@ -883,8 +931,6 @@ static int sdl_texture_toscreen(lua_State *L)
 	};
 	glVertexPointer(2, GL_FLOAT, 0, vertices);
 	glDrawArrays(GL_QUADS, 0, 4);
-
-	if (lua_isnumber(L, 6)) tglColor4f(1, 1, 1, 1);
 	return 0;
 }
 
@@ -903,7 +949,23 @@ static int sdl_texture_toscreen_full(lua_State *L)
 		float g = luaL_checknumber(L, 10);
 		float b = luaL_checknumber(L, 11);
 		float a = luaL_checknumber(L, 12);
-		tglColor4f(r, g, b, a);
+		GLfloat colors[4*4] = {
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
+	}
+	else
+	{
+		GLfloat colors[4*4] = {
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
 	}
 
 	tglBindTexture(GL_TEXTURE_2D, *t);
@@ -926,8 +988,6 @@ static int sdl_texture_toscreen_full(lua_State *L)
 	};
 	glVertexPointer(2, GL_FLOAT, 0, vertices);
 	glDrawArrays(GL_QUADS, 0, 4);
-
-	if (lua_isnumber(L, 8)) tglColor4f(1, 1, 1, 1);
 	return 0;
 }
 
@@ -990,6 +1050,7 @@ static int sdl_texture_outline(lua_State *L)
 	float g = luaL_checknumber(L, 7);
 	float b = luaL_checknumber(L, 8);
 	float a = luaL_checknumber(L, 9);
+	int i;
 
 	// Setup our FBO
 	// WARNING: this is a static, only one FBO is ever made, and never deleted, for some reasons
@@ -1029,34 +1090,39 @@ static int sdl_texture_outline(lua_State *L)
 	glClear(GL_COLOR_BUFFER_BIT);
 	glLoadIdentity();
 
+	/* Render to buffer: shadow */
+	glBindTexture(GL_TEXTURE_2D, *t);
+
 	GLfloat texcoords[2*4] = {
 		0, 0,
 		1, 0,
 		1, 1,
 		0, 1,
 	};
-
-	glBindTexture(GL_TEXTURE_2D, *t);
-	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
 	GLfloat vertices[2*4] = {
 		x,   y,
 		w+x, y,
 		w+x, h+y,
 		x,   h+y,
 	};
-
-	/* Render to buffer: shadow */
-	tglColor4f(r, g, b, a);
+	GLfloat colors[4*4] = {
+		r, g, b, a,
+		r, g, b, a,
+		r, g, b, a,
+		r, g, b, a,
+	};
+	glColorPointer(4, GL_FLOAT, 0, colors);
 	glVertexPointer(2, GL_FLOAT, 0, vertices);
+	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+
 	glDrawArrays(GL_QUADS, 0, 4);
 
 	/* Render to buffer: original */
-	tglColor4f(1, 1, 1, 1);
+	for (i = 0; i < 4*4; i++) colors[i] = 1;
 	vertices[0] = 0; vertices[1] = 0;
 	vertices[2] = w; vertices[3] = 0;
 	vertices[4] = w; vertices[5] = h;
 	vertices[6] = 0; vertices[7] = h;
-	glVertexPointer(2, GL_FLOAT, 0, vertices);
 	glDrawArrays(GL_QUADS, 0, 4);
 
 	// Unbind texture from FBO and then unbind FBO
@@ -1265,7 +1331,23 @@ static int gl_fbo_toscreen(lua_State *L)
 		g = luaL_checknumber(L, 8);
 		b = luaL_checknumber(L, 9);
 		a = luaL_checknumber(L, 10);
-		tglColor4f(r, g, b, a);
+		GLfloat colors[4*4] = {
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+			r, g, b, a,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
+	}
+	else
+	{
+		GLfloat colors[4*4] = {
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+		};
+		glColorPointer(4, GL_FLOAT, 0, colors);
 	}
 	if (lua_isuserdata(L, 6))
 	{
@@ -1295,7 +1377,6 @@ static int gl_fbo_toscreen(lua_State *L)
 	glDrawArrays(GL_QUADS, 0, 4);
 
 	if (lua_isuserdata(L, 6)) glUseProgramObjectARB(0);
-	if (lua_isnumber(L, 7)) tglColor4f(1, 1, 1, 1);
 	glEnable(GL_BLEND);
 	return 0;
 }
diff --git a/src/main.c b/src/main.c
index 2727f187fbb13448842e1c9ead8063b9fa6d453f..37582045311574fd5b7ab5192024e78771329b0d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -299,14 +299,20 @@ void call_draw(int nb_keyframes)
 			1, 1,
 			0, 1,
 		};
+		GLfloat colors[4*4] = {
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+			1, 1, 1, 1,
+		};
 
 		glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+		glColorPointer(4, GL_FLOAT, 0, colors);
 
 		int x = mousex + mouse_cursor_ox;
 		int y = mousey + mouse_cursor_oy;
 		int down = SDL_GetMouseState(NULL, NULL);
 		tglBindTexture(GL_TEXTURE_2D, down ? mouse_cursor_down_tex : mouse_cursor_tex);
-		tglColor4f(1, 1, 1, 1);
 
 		GLfloat vertices[2*4] = {
 			x, y,
@@ -485,9 +491,6 @@ void setupDisplayTimer(int fps)
 /* general OpenGL initialization function */
 int initGL()
 {
-	/* Enable smooth shading */
-//	glShadeModel( GL_SMOOTH );
-
 	/* Set the background black */
 	tglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
 
@@ -496,19 +499,13 @@ int initGL()
 
 	/* The Type Of Depth Test To Do */
 	glDepthFunc(GL_LEQUAL);
-//	glDepthFunc(GL_LESS);
-
-	/* Really Nice Perspective Calculations */
-	//	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
 
 	glEnable(GL_BLEND);
 	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-//	glDisable(GL_DEPTH_TEST);
-	tglColor4f(1.0f,1.0f,1.0f,1.0f);
-//	glAlphaFunc(GL_GREATER,0.1f);
 
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glEnableClientState(GL_COLOR_ARRAY);
 
 	return( TRUE );
 }
@@ -547,9 +544,6 @@ int resizeWindow(int width, int height)
 	/* Reset The View */
 	glLoadIdentity( );
 
-//	glEnable(GL_ALPHA_TEST);
-//	tglColor4f(1.0f,1.0f,1.0f,1.0f);
-
 	return( TRUE );
 }
 
diff --git a/src/map.c b/src/map.c
index 6dbc5252cc8bff54ae49b454f41812578f31d74d..ebf299092c4f28f1390d17ca25fa5dd83aace157 100644
--- a/src/map.c
+++ b/src/map.c
@@ -51,6 +51,10 @@ static int map_object_new(lua_State *L)
 
 	obj->move_max = 0;
 
+	obj->mm_r = -1;
+	obj->mm_g = -1;
+	obj->mm_b = -1;
+
 	obj->valid = TRUE;
 	obj->dx = luaL_checknumber(L, 6);
 	obj->dy = luaL_checknumber(L, 7);
@@ -133,6 +137,18 @@ static int map_object_tint(lua_State *L)
 	return 0;
 }
 
+static int map_object_minimap(lua_State *L)
+{
+	map_object *obj = (map_object*)auxiliar_checkclass(L, "core{mapobj}", 1);
+	float r = luaL_checknumber(L, 2);
+	float g = luaL_checknumber(L, 3);
+	float b = luaL_checknumber(L, 4);
+	obj->mm_r = r / 255;
+	obj->mm_g = g / 255;
+	obj->mm_b = b / 255;
+	return 0;
+}
+
 static int map_object_print(lua_State *L)
 {
 	map_object *obj = (map_object*)auxiliar_checkclass(L, "core{mapobj}", 1);
@@ -248,20 +264,23 @@ static int map_objects_toscreen(lua_State *L)
 	int w = luaL_checknumber(L, 3);
 	int h = luaL_checknumber(L, 4);
 
-	GLfloat vertices[3*4] = {
-		0, 0, -96,
-		0, 0, -96,
-		0, 0, -96,
-		0, 0, -96,
-	};
+	GLfloat vertices[3*4];
 	GLfloat texcoords[2*4] = {
 		0, 0,
 		1, 0,
 		1, 1,
 		0, 1,
 	};
+	GLfloat colors[4*4] = {
+		1, 1, 1, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1,
+	};
 
 	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+	glColorPointer(4, GL_FLOAT, 0, colors);
+	glVertexPointer(3, GL_FLOAT, 0, vertices);
 
 	/***************************************************
 	 * Render
@@ -271,8 +290,6 @@ static int map_objects_toscreen(lua_State *L)
 	{
 		map_object *m = (map_object*)auxiliar_checkclass(L, "core{mapobj}", moid);
 
-		tglColor4f(1, 1, 1, 1);
-
 		int z;
 		if (m->shader) useShader(m->shader, 1, 1, 1, 1, 1, 1, 1, 1);
 		for (z = (!shaders_active) ? 0 : (m->nb_textures - 1); z >= 0; z--)
@@ -287,7 +304,6 @@ static int map_objects_toscreen(lua_State *L)
 		vertices[3] = w + dx; vertices[4] = dy; vertices[5] = dz;
 		vertices[6] = w + dx; vertices[7] = h + dy; vertices[8] = dz;
 		vertices[9] = dx; vertices[10] = h + dy; vertices[11] = dz;
-		glVertexPointer(3, GL_FLOAT, 0, vertices);
 		glDrawArrays(GL_QUADS, 0, 4);
 
 		if (m->shader) glUseProgramObjectARB(0);
@@ -344,20 +360,23 @@ static int map_objects_display(lua_State *L)
 	CHECKGL(glClear(GL_COLOR_BUFFER_BIT));
 	CHECKGL(glLoadIdentity());
 
-	GLfloat vertices[3*4] = {
-		0, 0, -96,
-		0, 0, -96,
-		0, 0, -96,
-		0, 0, -96,
-	};
+	GLfloat vertices[3*4];
 	GLfloat texcoords[2*4] = {
 		0, 0,
 		1, 0,
 		1, 1,
 		0, 1,
 	};
+	GLfloat colors[4*4] = {
+		1, 1, 1, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1,
+	};
 
 	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+	glColorPointer(4, GL_FLOAT, 0, colors);
+	glVertexPointer(3, GL_FLOAT, 0, vertices);
 
 	/***************************************************
 	 * Render to buffer
@@ -367,8 +386,6 @@ static int map_objects_display(lua_State *L)
 	{
 		map_object *m = (map_object*)auxiliar_checkclass(L, "core{mapobj}", moid);
 
-		tglColor4f(1, 1, 1, 1);
-
 		int z;
 		if (m->shader) useShader(m->shader, 1, 1, 1, 1, 1, 1, 1, 1);
 		for (z = (!shaders_active) ? 0 : (m->nb_textures - 1); z >= 0; z--)
@@ -383,7 +400,6 @@ static int map_objects_display(lua_State *L)
 		vertices[3] = w + dx; vertices[4] = dy; vertices[5] = dz;
 		vertices[6] = w + dx; vertices[7] = h + dy; vertices[8] = dz;
 		vertices[9] = dx; vertices[10] = h + dy; vertices[11] = dz;
-		glVertexPointer(3, GL_FLOAT, 0, vertices);
 		glDrawArrays(GL_QUADS, 0, 4);
 
 		if (m->shader) glUseProgramObjectARB(0);
@@ -419,15 +435,7 @@ static int map_objects_display(lua_State *L)
 }
 
 
-// Minimap defines
-#define MM_FLOOR 1
-#define MM_BLOCK 2
-#define MM_OBJECT 4
-#define MM_TRAP 8
-#define MM_FRIEND 16
-#define MM_NEUTRAL 32
-#define MM_HOSTILE 64
-#define MM_LEVEL_CHANGE 128
+#define QUADS_PER_BATCH 500
 
 static int map_new(lua_State *L)
 {
@@ -449,9 +457,12 @@ static int map_new(lua_State *L)
 	map->shown_r = map->shown_g = map->shown_b = 1;
 	map->shown_a = 1;
 
-	map->mm_floor = map->mm_block = map->mm_object = map->mm_trap = map->mm_friend = map->mm_neutral = map->mm_hostile = map->mm_level_change = 0;
 	map->minimap_gridsize = 4;
 
+	map->vertices = calloc(2*4*QUADS_PER_BATCH, sizeof(GLfloat)); // 2 coords, 4 vertices per particles
+	map->colors = calloc(4*4*QUADS_PER_BATCH, sizeof(GLfloat)); // 4 color data, 4 vertices per particles
+	map->texcoords = calloc(2*4*QUADS_PER_BATCH, sizeof(GLfloat));
+
 	map->w = w;
 	map->h = h;
 	map->zdepth = zdepth;
@@ -475,7 +486,7 @@ static int map_new(lua_State *L)
 	map->my = my;
 	map->mwidth = mwidth;
 	map->mheight = mheight;
-	map->grids= calloc(w, sizeof(map_object***));
+	map->grids = calloc(w, sizeof(map_object***));
 	map->grids_seens = calloc(w, sizeof(float*));
 	map->grids_remembers = calloc(w, sizeof(bool*));
 	map->grids_lites = calloc(w, sizeof(bool*));
@@ -516,6 +527,10 @@ static int map_free(lua_State *L)
 	free(map->grids_lites);
 	free(map->minimap);
 
+	free(map->colors);
+	free(map->texcoords);
+	free(map->vertices);
+
 	luaL_unref(L, LUA_REGISTRYINDEX, map->mo_list_ref);
 
 	lua_pushnumber(L, 1);
@@ -572,36 +587,12 @@ static int map_set_minimap_gridsize(lua_State *L)
 	return 0;
 }
 
-static int map_set_minimap(lua_State *L)
-{
-	map_type *map = (map_type*)auxiliar_checkclass(L, "core{map}", 1);
-	GLuint *floor  = lua_isnil(L, 2) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 2);
-	GLuint *block  = lua_isnil(L, 3) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 3);
-	GLuint *object = lua_isnil(L, 4) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 4);
-	GLuint *trap   = lua_isnil(L, 5) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 5);
-	GLuint *frien  = lua_isnil(L, 6) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 6);
-	GLuint *neutral =lua_isnil(L, 7) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 7);
-	GLuint *hostile =lua_isnil(L, 8) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 8);
-	GLuint *lev     =lua_isnil(L, 9) ? NULL : (GLuint*)auxiliar_checkclass(L, "gl{texture}", 9);
-
-	map->mm_floor = *floor;
-	map->mm_block = *block;
-	map->mm_object = *object;
-	map->mm_trap = *trap;
-	map->mm_friend = *frien;
-	map->mm_neutral = *neutral;
-	map->mm_hostile = *hostile;
-	map->mm_level_change = *lev;
-	return 0;
-}
-
 static int map_set_grid(lua_State *L)
 {
 	map_type *map = (map_type*)auxiliar_checkclass(L, "core{map}", 1);
 	int x = luaL_checknumber(L, 2);
 	int y = luaL_checknumber(L, 3);
 	if (x < 0 || y < 0 || x >= map->w || y >= map->h) return 0;
-	unsigned char mm = lua_tonumber(L, 4);
 
 	// Get the mo list
 	lua_rawgeti(L, LUA_REGISTRYINDEX, map->mo_list_ref);
@@ -615,18 +606,18 @@ static int map_set_grid(lua_State *L)
 		{
 			lua_pushnumber(L, (long long)map->grids[x][y][i]);
 			lua_pushnil(L);
-			lua_settable(L, 6); // Access the list of all mos for the map
+			lua_settable(L, 5); // Access the list of all mos for the map
 		}
 
 		lua_pushnumber(L, i + 1);
-		lua_gettable(L, 5); // Access the table of mos for this spot
+		lua_gettable(L, 4); // Access the table of mos for this spot
 		map->grids[x][y][i] = lua_isnoneornil(L, -1) ? NULL : (map_object*)auxiliar_checkclass(L, "core{mapobj}", -1);
 
 		// Set the object in the mo list
 		// We use the pointer value directly as an index
 		lua_pushnumber(L, (long)map->grids[x][y][i]);
 		lua_pushvalue(L, -2);
-		lua_settable(L, 6); // Access the list of all mos for the map
+		lua_settable(L, 5); // Access the list of all mos for the map
 
 		// Remove the mo and get the next
 		lua_pop(L, 1);
@@ -634,8 +625,6 @@ static int map_set_grid(lua_State *L)
 
 	// Pop the mo list
 	lua_pop(L, 1);
-
-	map->minimap[x][y] = mm;
 	return 0;
 }
 
@@ -740,19 +729,38 @@ static int map_set_scroll(lua_State *L)
 	return 0;
 }
 
-#define DO_QUAD(dx, dy, zoom) {\
-	vertices[0] = (dx); vertices[1] = (dy); \
-	vertices[3] = map->tile_w * (zoom) + (dx); vertices[4] = (dy); \
-	vertices[6] = map->tile_w * (zoom) + (dx); vertices[7] = map->tile_h * (zoom) + (dy); \
-	vertices[9] = (dx); vertices[10] = map->tile_h * (zoom) + (dy); \
-	glVertexPointer(3, GL_FLOAT, 0, vertices); \
-	glDrawArrays(GL_QUADS, 0, 4); \
-	}
+#define DO_QUAD(dx, dy, zoom, r, g, b, a) {\
+	vertices[(*vert_idx)] = (dx); vertices[(*vert_idx)+1] = (dy); \
+	vertices[(*vert_idx)+2] = map->tile_w * (zoom) + (dx); vertices[(*vert_idx)+3] = (dy); \
+	vertices[(*vert_idx)+4] = map->tile_w * (zoom) + (dx); vertices[(*vert_idx)+5] = map->tile_h * (zoom) + (dy); \
+	vertices[(*vert_idx)+6] = (dx); vertices[(*vert_idx)+7] = map->tile_h * (zoom) + (dy); \
+	\
+	texcoords[(*vert_idx)] = 0; texcoords[(*vert_idx)+1] = 0; \
+	texcoords[(*vert_idx)+2] = map->tex_tile_w; texcoords[(*vert_idx)+3] = 0; \
+	texcoords[(*vert_idx)+4] = map->tex_tile_w; texcoords[(*vert_idx)+5] = map->tex_tile_h; \
+	texcoords[(*vert_idx)+6] = 0; texcoords[(*vert_idx)+7] = map->tex_tile_h; \
+	\
+	colors[(*col_idx)] = r; colors[(*col_idx)+1] = g; colors[(*col_idx)+2] = b; colors[(*col_idx)+3] = (a); \
+	colors[(*col_idx)+4] = r; colors[(*col_idx)+5] = g; colors[(*col_idx)+6] = b; colors[(*col_idx)+7] = (a); \
+	colors[(*col_idx)+8] = r; colors[(*col_idx)+9] = g; colors[(*col_idx)+10] = b; colors[(*col_idx)+11] = (a); \
+	colors[(*col_idx)+12] = r; colors[(*col_idx)+13] = g; colors[(*col_idx)+14] = b; colors[(*col_idx)+15] = (a); \
+	\
+	(*vert_idx) += 8; \
+	(*col_idx) += 16; \
+	if ((*vert_idx) >= 8*QUADS_PER_BATCH) {\
+		glDrawArrays(GL_QUADS, 0, (*vert_idx) / 2); \
+		(*vert_idx) = 0; \
+		(*col_idx) = 0; \
+	} \
+}
 
-inline void display_map_quad(map_type *map, int dx, int dy, float dz, map_object *m, int i, int j, float a, float seen, int nb_keyframes) ALWAYS_INLINE;
-void display_map_quad(map_type *map, int dx, int dy, float dz, map_object *m, int i, int j, float a, float seen, int nb_keyframes)
+inline void display_map_quad(GLuint *cur_tex, int *vert_idx, int *col_idx, map_type *map, int dx, int dy, float dz, map_object *m, int i, int j, float a, float seen, int nb_keyframes) ALWAYS_INLINE;
+void display_map_quad(GLuint *cur_tex, int *vert_idx, int *col_idx, map_type *map, int dx, int dy, float dz, map_object *m, int i, int j, float a, float seen, int nb_keyframes)
 {
 	float r, g, b;
+	GLfloat *vertices = map->vertices;
+	GLfloat *colors = map->colors;
+	GLfloat *texcoords = map->texcoords;
 
 	/********************************************************
 	 ** Select the color to use
@@ -783,27 +791,33 @@ void display_map_quad(map_type *map, int dx, int dy, float dz, map_object *m, in
 		}
 	}
 
+	/* Reset vertices&all buffers, we are changing texture/shader */
+	if ((*cur_tex != m->textures[0]) || m->shader || (m->nb_textures > 1))
+	{
+		/* Draw remaining ones */
+		if (vert_idx) glDrawArrays(GL_QUADS, 0, (*vert_idx) / 2);
+		/* Reset */
+		(*vert_idx) = 0;
+		(*col_idx) = 0;
+	}
+	if (*cur_tex != m->textures[0])
+	{
+		glBindTexture(GL_TEXTURE_2D, m->textures[0]);
+		*cur_tex = m->textures[0];
+	}
+
 	/********************************************************
 	 ** Setup all textures we need
 	 ********************************************************/
 	a = (a > 1) ? 1 : ((a < 0) ? 0 : a);
 	int z;
 	if (m->shader) useShader(m->shader, i, j, map->tile_w, map->tile_h, r, g, b, a);
-	for (z = (!shaders_active) ? 0 : (m->nb_textures - 1); z >= 0; z--)
+	for (z = (!shaders_active) ? 0 : (m->nb_textures - 1); z > 0; z--)
 	{
 		if (multitexture_active && shaders_active) tglActiveTexture(GL_TEXTURE0+z);
 		tglBindTexture(m->textures_is3d[z] ? GL_TEXTURE_3D : GL_TEXTURE_2D, m->textures[z]);
 	}
-
-	/********************************************************
-	 ** Make up the arrays to push
-	 ********************************************************/
-	GLfloat vertices[3*4] = {
-		0, 0, 0,
-		0, 0, 0,
-		0, 0, 0,
-		0, 0, 0,
-	};
+	if (m->nb_textures && multitexture_active && shaders_active) tglActiveTexture(GL_TEXTURE0); // Switch back to default texture unit
 
 	/********************************************************
 	 ** Compute/display movement and motion blur
@@ -832,8 +846,7 @@ void display_map_quad(map_type *map, int dx, int dy, float dz, map_object *m, in
 					{
 						animdx = map->tile_w * (adx * step / (float)m->move_max - adx);
 						animdy = map->tile_h * (ady * step / (float)m->move_max - ady);
-						tglColor4f(r, g, b, a * 2 / (3 + z));
-						DO_QUAD(dx + m->dx * map->tile_w + animdx, dy + m->dy * map->tile_h + animdy, m->scale);
+						DO_QUAD(dx + m->dx * map->tile_w + animdx, dy + m->dy * map->tile_h + animdy, m->scale, r, g, b, a * 2 / (3 + z));
 					}
 				}
 			}
@@ -847,12 +860,20 @@ void display_map_quad(map_type *map, int dx, int dy, float dz, map_object *m, in
 	/********************************************************
 	 ** Display the entity
 	 ********************************************************/
-	tglColor4f(r, g, b, a);
-	DO_QUAD(dx + m->dx * map->tile_w + animdx, dy + m->dy * map->tile_h + animdy, m->scale);
+	DO_QUAD(dx + m->dx * map->tile_w + animdx, dy + m->dy * map->tile_h + animdy, m->scale, r, g, b, a);
 
 	/********************************************************
 	 ** Cleanup
 	 ********************************************************/
+	if (m->shader || m->nb_textures)
+	{
+		/* Draw remaining ones */
+		if (vert_idx) glDrawArrays(GL_QUADS, 0, (*vert_idx) / 2);
+		/* Reset */
+		(*vert_idx) = 0;
+		(*col_idx) = 0;
+		*cur_tex = 0;
+	}
 	if (m->shader) glUseProgramObjectARB(0);
 	m->display_last = DL_TRUE;
 }
@@ -866,17 +887,19 @@ static int map_to_screen(lua_State *L)
 	int y = luaL_checknumber(L, 3);
 	int nb_keyframes = luaL_checknumber(L, 4);
 	int i = 0, j = 0, z = 0;
+	int vert_idx = 0;
+	int col_idx = 0;
+	GLuint cur_tex = 0;
 
 	/* Enables Depth Testing */
 	glEnable(GL_DEPTH_TEST);
 
-	GLfloat texcoords[2*4] = {
-		0, 0,
-		map->tex_tile_w, 0,
-		map->tex_tile_w, map->tex_tile_h,
-		0, map->tex_tile_h,
-	};
+	GLfloat *vertices = map->vertices;
+	GLfloat *colors = map->colors;
+	GLfloat *texcoords = map->texcoords;
 	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+	glVertexPointer(2, GL_FLOAT, 0, vertices);
+	glColorPointer(4, GL_FLOAT, 0, colors);
 
 	// Smooth scrolling
 	float animdx = 0, animdy = 0;
@@ -923,17 +946,20 @@ static int map_to_screen(lua_State *L)
 				{
 					if (map->grids_seens[i][j])
 					{
-						display_map_quad(map, dx, dy, z, mo, i, j, map->shown_a, map->grids_seens[i][j], nb_keyframes);
+						display_map_quad(&cur_tex, &vert_idx, &col_idx, map, dx, dy, z, mo, i, j, map->shown_a, map->grids_seens[i][j], nb_keyframes);
 					}
 					else
 					{
-						display_map_quad(map, dx, dy, z, mo, i, j, map->obscure_a, 0, nb_keyframes);
+						display_map_quad(&cur_tex, &vert_idx, &col_idx, map, dx, dy, z, mo, i, j, map->obscure_a, 0, nb_keyframes);
 					}
 				}
 			}
 		}
 	}
 
+	/* Display any leftovers */
+	if (vert_idx) glDrawArrays(GL_QUADS, 0, vert_idx / 2);
+
 	// "Decay" displayed status for all mos
 	lua_rawgeti(L, LUA_REGISTRYINDEX, map->mo_list_ref);
 	lua_pushnil(L);
@@ -945,24 +971,12 @@ static int map_to_screen(lua_State *L)
 		lua_pop(L, 1); // Remove value, keep key for next iteration
 	}
 
-	// Restore normal display
-	tglColor4f(1, 1, 1, 1);
-
 	/* Disables Depth Testing, we do not need it for the rest of the display */
 	glDisable(GL_DEPTH_TEST);
 
 	return 0;
 }
 
-#define DO_MINIQUAD(dx, dy) {\
-	vertices[0] = (dx); vertices[1] = (dy); \
-	vertices[3] = map->minimap_gridsize + (dx); vertices[4] = (dy); \
-	vertices[6] = map->minimap_gridsize + (dx); vertices[7] = map->minimap_gridsize + (dy); \
-	vertices[9] = (dx); vertices[10] = map->minimap_gridsize + (dy); \
-	glVertexPointer(3, GL_FLOAT, 0, vertices); \
-	glDrawArrays(GL_QUADS, 0, 4); \
-	}
-
 static int minimap_to_screen(lua_State *L)
 {
 	map_type *map = (map_type*)auxiliar_checkclass(L, "core{map}", 1);
@@ -973,102 +987,76 @@ static int minimap_to_screen(lua_State *L)
 	int mdw = luaL_checknumber(L, 6);
 	int mdh = luaL_checknumber(L, 7);
 	float transp = luaL_checknumber(L, 8);
-	int i = 0, j = 0;
-	GLfloat vertices[3*4] = {
-		0, 0, -96,
-		0, 0, -96,
-		0, 0, -96,
-		0, 0, -96,
-	};
-
-	GLfloat texcoords[2*4] = {
-		0, 0,
-		map->tex_tile_w, 0,
-		map->tex_tile_w, map->tex_tile_h,
-		0, map->tex_tile_h,
-	};
+	int z = 0, i = 0, j = 0;
+	int vert_idx = 0;
+	int col_idx = 0;
+	GLfloat r, g, b, a;
+
+	GLfloat *vertices = map->vertices;
+	GLfloat *colors = map->colors;
+	GLfloat *texcoords = map->texcoords;
 	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+	glVertexPointer(2, GL_FLOAT, 0, vertices);
+	glColorPointer(4, GL_FLOAT, 0, colors);
+
+	tglBindTexture(GL_TEXTURE_2D, 0);
 
-	for (i = mdx; i < mdx + mdw; i++)
+	// Always display some more of the map to make sure we always see it all
+	for (z = 0; z < map->zdepth; z++)
 	{
-		for (j = mdy; j < mdy + mdh; j++)
+		for (i = mdx; i < mdx + mdw; i++)
 		{
-			if ((i < 0) || (j < 0) || (i >= map->w) || (j >= map->h)) continue;
+			for (j = mdy; j < mdy + mdh; j++)
+			{
+				if ((i < 0) || (j < 0) || (i >= map->w) || (j >= map->h)) continue;
 
-			int dx = x + (i - mdx) * map->minimap_gridsize;
-			int dy = y + (j - mdy) * map->minimap_gridsize;
+				int dx = x + (i - mdx) * map->minimap_gridsize;
+				int dy = y + (j - mdy) * map->minimap_gridsize;
+				map_object *mo = map->grids[i][j][z];
+				if (!mo || mo->mm_r < 0) continue;
 
-			if (map->grids_seens[i][j] || map->grids_remembers[i][j])
-			{
-				if (map->grids_seens[i][j])
-				{
-					tglColor4f(map->shown_r, map->shown_g, map->shown_b, map->shown_a * transp);
-					if ((map->minimap[i][j] & MM_LEVEL_CHANGE) && map->mm_level_change)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_level_change);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_HOSTILE) && map->mm_hostile)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_hostile);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_NEUTRAL) && map->mm_neutral)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_neutral);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_FRIEND) && map->mm_friend)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_friend);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_TRAP) && map->mm_trap)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_trap);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_OBJECT) && map->mm_object)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_object);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_BLOCK) && map->mm_block)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_block);
-						DO_MINIQUAD(dx, dy);
-					}
-					else if ((map->minimap[i][j] & MM_FLOOR) && map->mm_floor)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_floor);
-						DO_MINIQUAD(dx, dy);
-					}
-				}
-				else
+				if ((mo->on_seen && map->grids_seens[i][j]) || (mo->on_remember && map->grids_remembers[i][j]) || mo->on_unknown)
 				{
-					tglColor4f(map->obscure_r, map->obscure_g, map->obscure_b, map->obscure_a * transp);
-					if ((map->minimap[i][j] & MM_LEVEL_CHANGE) && map->mm_level_change)
+					if (map->grids_seens[i][j])
 					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_level_change);
-						DO_MINIQUAD(dx, dy);
+						r = mo->mm_r; g = mo->mm_g; b = mo->mm_b; a = transp;
+						colors[col_idx] = r; colors[col_idx+1] = g; colors[col_idx+2] = b; colors[col_idx+3] = (a);
+						colors[col_idx+4] = r; colors[col_idx+5] = g; colors[col_idx+6] = b; colors[col_idx+7] = (a);
+						colors[col_idx+8] = r; colors[col_idx+9] = g; colors[col_idx+10] = b; colors[col_idx+11] = (a);
+						colors[col_idx+12] = r; colors[col_idx+13] = g; colors[col_idx+14] = b; colors[col_idx+15] = (a);
 					}
-					else if ((map->minimap[i][j] & MM_BLOCK) && map->mm_block)
+					else
 					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_block);
-						DO_MINIQUAD(dx, dy);
+						r = mo->mm_r * 0.6; g = mo->mm_g * 0.6; b = mo->mm_b * 0.6; a = transp * 0.6;
+						colors[col_idx] = r; colors[col_idx+1] = g; colors[col_idx+2] = b; colors[col_idx+3] = (a);
+						colors[col_idx+4] = r; colors[col_idx+5] = g; colors[col_idx+6] = b; colors[col_idx+7] = (a);
+						colors[col_idx+8] = r; colors[col_idx+9] = g; colors[col_idx+10] = b; colors[col_idx+11] = (a);
+						colors[col_idx+12] = r; colors[col_idx+13] = g; colors[col_idx+14] = b; colors[col_idx+15] = (a);
 					}
-					else if ((map->minimap[i][j] & MM_FLOOR) && map->mm_floor)
-					{
-						tglBindTexture(GL_TEXTURE_2D, map->mm_floor);
-						DO_MINIQUAD(dx, dy);
+
+					vertices[vert_idx] = (dx); vertices[vert_idx+1] = (dy);
+					vertices[vert_idx+2] = map->minimap_gridsize + (dx); vertices[vert_idx+3] = (dy);
+					vertices[vert_idx+4] = map->minimap_gridsize + (dx); vertices[vert_idx+5] = map->minimap_gridsize + (dy);
+					vertices[vert_idx+6] = (dx); vertices[vert_idx+7] = map->minimap_gridsize + (dy);
+
+					texcoords[vert_idx] = 0; texcoords[vert_idx+1] = 0;
+					texcoords[vert_idx+2] = map->tex_tile_w; texcoords[vert_idx+3] = 0;
+					texcoords[vert_idx+4] = map->tex_tile_w; texcoords[vert_idx+5] = map->tex_tile_h;
+					texcoords[vert_idx+6] = 0; texcoords[vert_idx+7] = map->tex_tile_h;
+
+					vert_idx += 8;
+					col_idx += 16;
+					if (vert_idx >= 8*QUADS_PER_BATCH) {
+						glDrawArrays(GL_QUADS, 0, vert_idx / 2);
+						vert_idx = 0;
+						col_idx = 0;
 					}
 				}
 			}
 		}
 	}
+	if (vert_idx) glDrawArrays(GL_QUADS, 0, vert_idx / 2);
 
-	// Restore normal display
-	tglColor4f(1, 1, 1, 1);
 	return 0;
 }
 
@@ -1098,7 +1086,6 @@ static const struct luaL_reg map_reg[] =
 	{"setScroll", map_set_scroll},
 	{"toScreen", map_to_screen},
 	{"toScreenMiniMap", minimap_to_screen},
-	{"setupMiniMap", map_set_minimap},
 	{"setupMiniMapGridSize", map_set_minimap_gridsize},
 	{NULL, NULL},
 };
@@ -1113,6 +1100,7 @@ static const struct luaL_reg map_object_reg[] =
 	{"invalidate", map_object_invalid},
 	{"isValid", map_object_is_valid},
 	{"onSeen", map_object_on_seen},
+	{"minimap", map_object_minimap},
 	{"resetMoveAnim", map_object_reset_move_anim},
 	{"setMoveAnim", map_object_set_move_anim},
 	{"getMoveAnim", map_object_get_move_anim},
diff --git a/src/map.h b/src/map.h
index aaf07c2dc772f447466f2e394c59f1abfc9ebc7d..32a340a377ef95bcf34023c094ad6ea264c9d62b 100644
--- a/src/map.h
+++ b/src/map.h
@@ -34,6 +34,9 @@ typedef struct {
 	float tint_r;
 	float tint_g;
 	float tint_b;
+	float mm_r;
+	float mm_g;
+	float mm_b;
 	bool on_seen;
 	bool on_remember;
 	bool on_unknown;
@@ -50,7 +53,10 @@ typedef struct {
 	bool **grids_remembers;
 	bool **grids_lites;
 	unsigned char **minimap;
-	GLuint mm_floor, mm_block, mm_object, mm_trap, mm_friend, mm_neutral, mm_hostile, mm_level_change;
+
+	GLfloat *vertices;
+	GLfloat *colors;
+	GLfloat *texcoords;
 
 	int mo_list_ref;
 
diff --git a/src/particles.c b/src/particles.c
index 9e0c1a371334ff1fc55a962f5fdb789c4d9aa2a2..efd56eed6b026c2837e87fa69b849a4922ad445c 100644
--- a/src/particles.c
+++ b/src/particles.c
@@ -32,6 +32,7 @@
 #define rng(x, y) (x + rand_div(1 + y - x))
 
 #define PARTICLE_ETERNAL 999999
+#define PARTICLES_PER_ARRAY 1000
 
 static void getinitfield(lua_State *L, const char *key, int *min, int *max)
 {
@@ -82,6 +83,11 @@ static int particles_new(lua_State *L)
 	ps->texture_ref = t_ref;
 	ps->no_stop = no_stop;
 
+	int batch = (nb < PARTICLES_PER_ARRAY) ? nb : PARTICLES_PER_ARRAY;
+	ps->vertices = calloc(2*4*batch, sizeof(GLfloat)); // 2 coords, 4 vertices per particles
+	ps->colors = calloc(4*4*batch, sizeof(GLfloat)); // 4 color data, 4 vertices per particles
+	ps->texcoords = calloc(2*4*batch, sizeof(GLshort));
+
 	ps->particles = calloc(nb, sizeof(particle_type));
 
 //	printf("Making particle emitter with %d particles\n", ps->nb);
@@ -143,6 +149,9 @@ static int particles_free(lua_State *L)
 {
 	particles_type *ps = (particles_type*)auxiliar_checkclass(L, "core{particles}", 1);
 
+	free(ps->texcoords);
+	free(ps->vertices);
+	free(ps->colors);
 	free(ps->particles);
 	luaL_unref(L, LUA_REGISTRYINDEX, ps->texture_ref);
 	if (ps->generator_ref) luaL_unref(L, LUA_REGISTRYINDEX, ps->generator_ref);
@@ -264,7 +273,6 @@ static int particles_emit(lua_State *L)
 	return 0;
 }
 
-
 static int particles_to_screen(lua_State *L)
 {
 	particles_type *ps = (particles_type*)auxiliar_checkclass(L, "core{particles}", 1);
@@ -276,21 +284,15 @@ static int particles_to_screen(lua_State *L)
 	int w = 0;
 	int i, j;
 	bool alive = FALSE;
-	GLfloat vertices[3*4] = {
-		0, 0, -97,
-		0, 0, -97,
-		0, 0, -97,
-		0, 0, -97,
-	};
-	GLshort texcoords[2*4] = {
-		0, 0,
-		1, 0,
-		1, 1,
-		0, 1,
-	};
+	int vert_idx = 0, col_idx = 0;
+	GLfloat *vertices = ps->vertices;
+	GLfloat *colors = ps->colors;
+	GLshort *texcoords = ps->texcoords;
 
 	glBindTexture(GL_TEXTURE_2D, ps->texture);
 	glTexCoordPointer(2, GL_SHORT, 0, texcoords);
+	glColorPointer(4, GL_FLOAT, 0, colors);
+	glVertexPointer(2, GL_FLOAT, 0, vertices);
 
 	for (w = 0; w < ps->nb; w++)
 	{
@@ -307,52 +309,69 @@ static int particles_to_screen(lua_State *L)
 					i = x + p->x * zoom - p->size / 2;
 					j = y + p->y * zoom - p->size / 2;
 
-					vertices[0] = i; vertices[1] = j;
-					vertices[3] = p->size + i; vertices[4] = j;
-					vertices[6] = p->size + i; vertices[7] = p->size + j;
-					vertices[9] = i; vertices[10] = p->size + j;
+					vertices[vert_idx] = i; vertices[vert_idx+1] = j;
+					vertices[vert_idx+2] = p->size + i; vertices[vert_idx+3] = j;
+					vertices[vert_idx+4] = p->size + i; vertices[vert_idx+5] = p->size + j;
+					vertices[vert_idx+6] = i; vertices[vert_idx+7] = p->size + j;
 				}
 				else
 				{
 					if ((p->ox <= p->x) && (p->oy <= p->y))
 					{
-						vertices[0] = 0 + x + p->ox * zoom; vertices[1] = 0 + y + p->oy * zoom;
-						vertices[3] = p->size + x + p->x * zoom; vertices[4] = 0 + y + p->y * zoom;
-						vertices[6] = p->size + x + p->x * zoom; vertices[7] = p->size + y + p->y * zoom;
-						vertices[9] = 0 + x + p->x * zoom; vertices[10] = p->size + y + p->y * zoom;
+						vertices[vert_idx+0] = 0 + x + p->ox * zoom; vertices[vert_idx+1] = 0 + y + p->oy * zoom;
+						vertices[vert_idx+2] = p->size + x + p->x * zoom; vertices[vert_idx+3] = 0 + y + p->y * zoom;
+						vertices[vert_idx+4] = p->size + x + p->x * zoom; vertices[vert_idx+5] = p->size + y + p->y * zoom;
+						vertices[vert_idx+6] = 0 + x + p->x * zoom; vertices[vert_idx+7] = p->size + y + p->y * zoom;
 					}
 					else if ((p->ox <= p->x) && (p->oy > p->y))
 					{
-						vertices[0] = 0 + x + p->x * zoom; vertices[1] = 0 + y + p->y * zoom;
-						vertices[3] = p->size + x + p->x * zoom; vertices[4] = 0 + y + p->y * zoom;
-						vertices[6] = p->size + x + p->x * zoom; vertices[7] = p->size + y + p->y * zoom;
-						vertices[9] = 0 + x + p->ox * zoom; vertices[10] = p->size + y + p->oy * zoom;
+						vertices[vert_idx+0] = 0 + x + p->x * zoom; vertices[vert_idx+1] = 0 + y + p->y * zoom;
+						vertices[vert_idx+2] = p->size + x + p->x * zoom; vertices[vert_idx+3] = 0 + y + p->y * zoom;
+						vertices[vert_idx+4] = p->size + x + p->x * zoom; vertices[vert_idx+5] = p->size + y + p->y * zoom;
+						vertices[vert_idx+6] = 0 + x + p->ox * zoom; vertices[vert_idx+7] = p->size + y + p->oy * zoom;
 					}
 					else if ((p->ox > p->x) && (p->oy <= p->y))
 					{
-						vertices[0] = 0 + x + p->x * zoom; vertices[1] = 0 + y + p->y * zoom;
-						vertices[3] = p->size + x + p->ox * zoom; vertices[4] = 0 + y + p->oy * zoom;
-						vertices[6] = p->size + x + p->x * zoom; vertices[7] = p->size + y + p->y * zoom;
-						vertices[9] = 0 + x + p->x * zoom; vertices[10] = p->size + y + p->y * zoom;
+						vertices[vert_idx+0] = 0 + x + p->x * zoom; vertices[vert_idx+1] = 0 + y + p->y * zoom;
+						vertices[vert_idx+2] = p->size + x + p->ox * zoom; vertices[vert_idx+3] = 0 + y + p->oy * zoom;
+						vertices[vert_idx+4] = p->size + x + p->x * zoom; vertices[vert_idx+5] = p->size + y + p->y * zoom;
+						vertices[vert_idx+6] = 0 + x + p->x * zoom; vertices[vert_idx+7] = p->size + y + p->y * zoom;
 					}
 					else if ((p->ox > p->x) && (p->oy > p->y))
 					{
-						vertices[0] = 0 + x + p->x * zoom; vertices[1] = 0 + y + p->y * zoom;
-						vertices[3] = p->size + x + p->x * zoom; vertices[4] = 0 + y + p->y * zoom;
-						vertices[6] = p->size + x + p->ox * zoom; vertices[7] = p->size + y + p->oy * zoom;
-						vertices[9] = 0 + x + p->x * zoom; vertices[10] = p->size + y + p->y * zoom;
+						vertices[vert_idx+0] = 0 + x + p->x * zoom; vertices[vert_idx+1] = 0 + y + p->y * zoom;
+						vertices[vert_idx+2] = p->size + x + p->x * zoom; vertices[vert_idx+3] = 0 + y + p->y * zoom;
+						vertices[vert_idx+4] = p->size + x + p->ox * zoom; vertices[vert_idx+5] = p->size + y + p->oy * zoom;
+						vertices[vert_idx+6] = 0 + x + p->x * zoom; vertices[vert_idx+7] = p->size + y + p->y * zoom;
 					}
 				}
 
-				tglColor4f(p->r, p->g, p->b, p->a);
-				glVertexPointer(3, GL_FLOAT, 0, vertices);
-				glDrawArrays(GL_QUADS, 0, 4);
+				/* Setup texture coords */
+				texcoords[vert_idx] = 0; texcoords[vert_idx+1] = 0;
+				texcoords[vert_idx+2] = 1; texcoords[vert_idx+3] = 0;
+				texcoords[vert_idx+4] = 1; texcoords[vert_idx+5] = 1;
+				texcoords[vert_idx+6] = 0; texcoords[vert_idx+7] = 1;
+
+				/* Setup color */
+				colors[col_idx] = p->r; colors[col_idx+1] = p->g; colors[col_idx+2] = p->b; colors[col_idx+3] = p->a;
+				colors[col_idx+4] = p->r; colors[col_idx+5] = p->g; colors[col_idx+6] = p->b; colors[col_idx+7] = p->a;
+				colors[col_idx+8] = p->r; colors[col_idx+9] = p->g; colors[col_idx+10] = p->b; colors[col_idx+11] = p->a;
+				colors[col_idx+12] = p->r; colors[col_idx+13] = p->g; colors[col_idx+14] = p->b; colors[col_idx+15] = p->a;
+
+				/* Draw if over PARTICLES_PER_ARRAY particles */
+				vert_idx += 8;
+				col_idx += 16;
+				if (vert_idx >= 2*4*PARTICLES_PER_ARRAY) {
+					// Draw them all in one fell swoop
+					glDrawArrays(GL_QUADS, 0, vert_idx / 2);
+					vert_idx = 0;
+					col_idx = 0;
+				}
 			}
 		}
 	}
-
-	// Restore normal display
-	tglColor4f(1, 1, 1, 1);
+	// Draw them all in one fell swoop
+	if (vert_idx) glDrawArrays(GL_QUADS, 0, vert_idx / 2);
 
 	lua_pushboolean(L, alive || ps->no_stop);
 	return 1;
@@ -409,9 +428,6 @@ static int particles_update(lua_State *L)
 		}
 	}
 
-	// Restore normal display
-	tglColor4f(1, 1, 1, 1);
-
 	lua_pushboolean(L, alive || ps->no_stop);
 	return 1;
 }
diff --git a/src/particles.h b/src/particles.h
index 595364f7131ec402fdb95a0be5c3a43ff922fd05..0b354f6308f7fe364323ee5e738691ba7699cbfa 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -42,6 +42,10 @@ typedef struct {
 	int density;
 	bool no_stop;
 
+	GLfloat *vertices;
+	GLfloat *colors;
+	GLshort *texcoords;
+
 	int base;
 
 	int angle_min, anglev_min, anglea_min;