From 3a5e5432d24e96c5f2e853ca3f2d3878228fe5a2 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Sun, 23 Jan 2011 00:17:44 +0000
Subject: [PATCH] New race: Yeeks - look out for some new ruins on the map

git-svn-id: http://svn.net-core.org/repos/t-engine4@2467 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/modules/tome/class/Actor.lua             |   2 +
 game/modules/tome/class/Game.lua              |   3 +-
 game/modules/tome/data/autolevel_schemes.lua  |   4 +
 game/modules/tome/data/birth/races/yeek.lua   |   6 +-
 game/modules/tome/data/chats/yeek-wayist.lua  |  69 +++++++++++
 .../data/general/objects/boss-artifacts.lua   |  25 ++++
 .../data/general/objects/world-artifacts.lua  |   4 +-
 .../data/gfx/particles/breath_fire_navier.lua |   5 +-
 .../data/maps/zones/halfling-ruins-last.lua   |   6 +-
 .../tome/data/talents/divine/star-fury.lua    |   2 +-
 .../tome/data/talents/psionic/focus.lua       |   2 +-
 game/modules/tome/data/texts/unlock-yeek.lua  |  34 ++++++
 .../data/zones/crypt-kryl-feijan/npcs.lua     |   2 +-
 .../tome/data/zones/halfling-ruins/npcs.lua   | 111 ++++++++++++++++++
 ideas/DLCs.ods                                | Bin 9949 -> 10015 bytes
 src/particles_gas.c                           |  69 ++++++++---
 16 files changed, 313 insertions(+), 31 deletions(-)
 create mode 100644 game/modules/tome/data/chats/yeek-wayist.lua
 create mode 100644 game/modules/tome/data/texts/unlock-yeek.lua

diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index a147ec61da..844a95f417 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -348,6 +348,8 @@ function _M:act()
 
 	if self.on_act then self:on_act() end
 
+	if self.never_act then return false end
+
 	return true
 end
 
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 2c8b8b3dcb..e518c67bc1 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -762,8 +762,7 @@ function _M:setupCommands()
 			self.nicer_tiles:replaceAll(self.level)
 		end end,
 		[{"_g","ctrl"}] = function() if config.settings.cheat then
---			self.nicer_tiles:postProcessLevelTiles(self.level)
-		game.level.map:particleEmitter(self.player.x, self.player.y, 1, "breath_fire_navier")
+			self.nicer_tiles:postProcessLevelTiles(self.level)
 		end end,
 	}
 
diff --git a/game/modules/tome/data/autolevel_schemes.lua b/game/modules/tome/data/autolevel_schemes.lua
index 6801ffeb54..86ad1a62e5 100644
--- a/game/modules/tome/data/autolevel_schemes.lua
+++ b/game/modules/tome/data/autolevel_schemes.lua
@@ -54,6 +54,10 @@ Autolevel:registerScheme{ name = "warriormage", levelup = function(self)
 	self:learnStats{ self.STAT_MAG, self.STAT_MAG, self.STAT_WIL, self.STAT_STR, self.STAT_STR, self.STAT_DEX }
 end}
 
+Autolevel:registerScheme{ name = "roguemage", levelup = function(self)
+	self:learnStats{ self.STAT_CUN, self.STAT_DEX, self.STAT_CUN, self.STAT_MAG }
+end}
+
 Autolevel:registerScheme{ name = "dexmage", levelup = function(self)
 	self:learnStats{ self.STAT_MAG, self.STAT_MAG, self.STAT_DEX, self.STAT_DEX }
 end}
diff --git a/game/modules/tome/data/birth/races/yeek.lua b/game/modules/tome/data/birth/races/yeek.lua
index 3e58512e64..8133d5e207 100644
--- a/game/modules/tome/data/birth/races/yeek.lua
+++ b/game/modules/tome/data/birth/races/yeek.lua
@@ -67,15 +67,17 @@ newBirthDescriptor
 		"#GOLD#Stat modifiers:",
 		"#LIGHT_BLUE# * -3 Strength, -2 Dexterity, -5 Constitution",
 		"#LIGHT_BLUE# * +0 Magic, +6 Willpower, +4 Cunning",
-		"#GOLD#Life per level:#LIGHT_BLUE# 8",
+		"#GOLD#Life per level:#LIGHT_BLUE# 7",
 		"#GOLD#Experience penalty:#LIGHT_BLUE# -15%",
+		"#GOLD#Confusion resistance:#LIGHT_BLUE# 35%",
 	},
 	inc_stats = { str=-3, con=-5, cun=4, wil=6, mag=0, dex=-2 },
 	talents = {
 		[ActorTalents.T_YEEK_WILL]=1,
 	},
 	copy = {
-		life_rating=8,
+		life_rating=7,
+		confusion_immune = 0.35,
 		max_air = 200,
 	},
 	experience = 0.85,
diff --git a/game/modules/tome/data/chats/yeek-wayist.lua b/game/modules/tome/data/chats/yeek-wayist.lua
new file mode 100644
index 0000000000..9fa02f6f88
--- /dev/null
+++ b/game/modules/tome/data/chats/yeek-wayist.lua
@@ -0,0 +1,69 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newChat{ id="welcome",
+	text = [[#LIGHT_GREEN#*Before you stands a creature about as tall as a halfling, covered in small white fur and with a disproportionate head.
+You also notice he does not wield its greatsword, it seems to float in the air - bound to his will.*#WHITE#
+Why did you save me stranger? You are not of the Way.]],
+	answers = {
+		{"So I could rip your throat myself!", action=function(npc, player) npc:checkAngered(player, false, -200) end},
+		{"Well, you seemed to need help.", jump="kindness"},
+	}
+}
+
+newChat{ id="kindness",
+	text = [[#LIGHT_GREEN#*The greatsword floats to a less aggresive stance. He seems surprised.*#WHITE#
+Then, on behalf of the Way, I thank you.]],
+	answers = {
+		{"What is the way, and what are you?", jump="what"},
+	}
+}
+
+newChat{ id="what",
+	text = [[The Way is enlightenment, peace and protection. I am a Yeek, I come through this tunnel to explore this part of the world that was closed to us for centuries.]],
+	answers = {
+		{"Can you tell me more about the way?", jump="way", action=function(npc, player)
+			player.combat_mentalresist = player.combat_mentalresist + 15
+			player:attr("confusion_immune", 0.10)
+			game.logPlayer(player, "The contact with the Wayist mind has improved your mental shields. (+15 mental save, +10%% confusion resistance)")
+		end},
+		{"So you will wander the land alone?", jump="done"},
+	}
+}
+
+newChat{ id="done",
+	text = [[I am never alone, I have the Way.]],
+	answers = {
+		{"Farewell then.", action=function(npc, player) npc:disappear() end},
+	}
+}
+
+newChat{ id="way",
+	text = [[I can not, but I may show you a glimpse.
+#LIGHT_GREEN#*He leans toward you. Your mind is suddenly filled with feelings of peace and happiness.*#WHITE#
+This is the way.]],
+	answers = {
+		{"Thank you for this vision. Farewell my friend.", action=function(npc, player)
+			npc:disappear()
+			game:setAllowedBuild("yeek", true)
+		end},
+	}
+}
+
+return "welcome"
diff --git a/game/modules/tome/data/general/objects/boss-artifacts.lua b/game/modules/tome/data/general/objects/boss-artifacts.lua
index 2f91b0b9dd..ced3f9fd5f 100644
--- a/game/modules/tome/data/general/objects/boss-artifacts.lua
+++ b/game/modules/tome/data/general/objects/boss-artifacts.lua
@@ -229,6 +229,31 @@ newEntity{ base = "BASE_RING",
 	},
 }
 
+newEntity{ base = "BASE_RING",
+	define_as = "NIGHT_SONG", rarity=false,
+	name = "Nightsong", unique=true, image="object/artifact/nightsong.png",
+	desc = [[A pitch black ring, unadorned. It seems as though tendrils of darkness crept upon it.]],
+	unided_name = "obsidian ring",
+	level_range = {15, 23},
+	rarity = 250,
+	cost = 500,
+	material_level = 4,
+	wielder = {
+		max_stamina = 25,
+		combat_def = 6,
+		fatigue = -7,
+		inc_stats = { [Stats.STAT_CUN] = 6 },
+		combat_mentalresist = 13,
+		talent_cd_reduction={
+			[Talents.T_SHADOWSTEP]=1,
+		},
+		inc_damage={ [DamageType.PHYSICAL] = 5, },
+	},
+
+	max_power = 50, power_regen = 1,
+	use_talent = { id = Talents.T_DARK_TENDRILS, level=2, power = 40 },
+}
+
 newEntity{ base = "BASE_HELM",
 	define_as = "HELM_OF_GARKUL",
 	unided_name = "tribal helm",
diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua
index 50d164a7a3..0bdc904611 100644
--- a/game/modules/tome/data/general/objects/world-artifacts.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua
@@ -685,7 +685,7 @@ local activate_pair = function(moon, star, who)
 	star.paired._special1 = {who, "lite", who:addTemporaryValue("lite", 1)}
 	star.paired._special2 = {star, "combat", star:addTemporaryValue("combat", {melee_project={[DamageType.RANDOM_BLINDPHYSICAL]=3}})}
 	star.paired._special3 = {who, "inc_damage", who:addTemporaryValue("inc_damage", {[DamageType.LIGHT]=10}) }
-	game.log("The two blades glow brightly as they are brought close together.")
+	game.logPlayer(who, "The two blades glow brightly as they are brought close together.")
 end
 
 local deactivate_pair = function(moon, star, who)
@@ -698,7 +698,7 @@ local deactivate_pair = function(moon, star, who)
 	end
 	moon.paired = nil
 	star.paired = nil
-	game.log("The light from the two blades fades as they are separated.")
+	game.logPlayer(who, "The light from the two blades fades as they are separated.")
 end
 
 newEntity{ base = "BASE_KNIFE", define_as = "ART_PAIR_MOON",
diff --git a/game/modules/tome/data/gfx/particles/breath_fire_navier.lua b/game/modules/tome/data/gfx/particles/breath_fire_navier.lua
index 7c816a6c06..4d042532b0 100644
--- a/game/modules/tome/data/gfx/particles/breath_fire_navier.lua
+++ b/game/modules/tome/data/gfx/particles/breath_fire_navier.lua
@@ -24,7 +24,7 @@ generator = function()
 	if nb < 10 then
 		nb = nb + 1
 		return {
---[[
+
 			{ sx = 3, sy = 29, dx = 3, dy = -3 },
 			{ sx = 3, sy = 30, dx = 3, dy = 0 },
 			{ sx = 3, sy = 31, dx = 3, dy = 3 },
@@ -32,7 +32,7 @@ generator = function()
 			{ sx = 4, sy = 29, dx = 3, dy = -3 },
 			{ sx = 4, sy = 30, dx = 3, dy = 0 },
 			{ sx = 4, sy = 31, dx = 3, dy = 3 },
-]]
+--[[
 			{ sx = 29, sy = 29, dx = -3, dy = -3 },
 			{ sx = 31, sy = 29, dx =  3, dy = -3 },
 			{ sx = 29, sy = 31, dx = -3, dy =  3 },
@@ -42,6 +42,7 @@ generator = function()
 			{ sx = 30, sy = 31, dx =  0, dy =  3 },
 			{ sx = 29, sy = 30, dx = -3, dy =  0 },
 			{ sx = 31, sy = 30, dx =  3, dy =  0 },
+--]]
 		}
 	else return {}
 	end
diff --git a/game/modules/tome/data/maps/zones/halfling-ruins-last.lua b/game/modules/tome/data/maps/zones/halfling-ruins-last.lua
index 2346716b2b..9af02369c5 100644
--- a/game/modules/tome/data/maps/zones/halfling-ruins-last.lua
+++ b/game/modules/tome/data/maps/zones/halfling-ruins-last.lua
@@ -116,9 +116,9 @@ return {
 [[                                                  ]],
 [[#########################+########################]],
 [[##..............................................##]],
-[[#................................................#]],
-[[#..............Z................Y...............>#]],
-[[#................................................#]],
+[[#........................Z.......................#]],
+[[#...............................................>#]],
+[[#........................Y.......................#]],
 [[##..............................................##]],
 [[##################################################]]
 }
diff --git a/game/modules/tome/data/talents/divine/star-fury.lua b/game/modules/tome/data/talents/divine/star-fury.lua
index d542d33220..1c19afb59a 100644
--- a/game/modules/tome/data/talents/divine/star-fury.lua
+++ b/game/modules/tome/data/talents/divine/star-fury.lua
@@ -86,7 +86,7 @@ newTalent{
 		return true
 	end,
 	info = function(self, t)
-		local damage = t.getDuration(self, t)
+		local damage = t.getDamage(self, t)
 		local damageonspot = t.getDamageOnSpot(self, t)
 		local duration = t.getDuration(self, t)
 		return ([[Invokes a blast of shadows dealing %0.2f darkness damage and leaving a field that does %0.2f darkness damage per turn for %d turns.
diff --git a/game/modules/tome/data/talents/psionic/focus.lua b/game/modules/tome/data/talents/psionic/focus.lua
index 09d44cb98c..9ecb450747 100644
--- a/game/modules/tome/data/talents/psionic/focus.lua
+++ b/game/modules/tome/data/talents/psionic/focus.lua
@@ -104,7 +104,7 @@ newTalent{
 		return self:combatTalentIntervalDamage(t, "wil", 21, 281)*(1 + 0.3*gem_level)
 	end,
 	action = function(self, t)
-		--local gem_level = getGemLevel(self)
+		local gem_level = getGemLevel(self)
 		--local dam = (20 + self:getTalentLevel(t) * self:getWil(40))*(1 + 0.3*gem_level)
 		local dam = t.getDamage(self, t)
 		local tgts = {}
diff --git a/game/modules/tome/data/texts/unlock-yeek.lua b/game/modules/tome/data/texts/unlock-yeek.lua
new file mode 100644
index 0000000000..c708e20e45
--- /dev/null
+++ b/game/modules/tome/data/texts/unlock-yeek.lua
@@ -0,0 +1,34 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+return "New Race: #LIGHT_GREEN#Yeek",
+[[
+Yeeks are a mysterious race of small humanoids native to the tropical island of Rel.
+Their body is covered with white fur and their disproportionate head gives them a ridiculous look, yet they are a cunning and willful race.
+Although they are now nearly unheard of in Maj'Eyal, they spent many centuries as secret slaves to the halfling nation of Nargol.
+They gained their freedom during the Age of Pyre and have since then followed 'The Way' - a unity of minds enforced by their powerful psionics.
+
+You have helped a yeek wayist and can now create a new character with the #LIGHT_GREEN#Yeek race#WHITE#.
+
+Race features:#YELLOW#
+- Mental domination racial power
+- Confusion resistance
+- Fast leveling
+- Frail body#WHITE#
+]]
diff --git a/game/modules/tome/data/zones/crypt-kryl-feijan/npcs.lua b/game/modules/tome/data/zones/crypt-kryl-feijan/npcs.lua
index 258a789c51..e027c1d451 100644
--- a/game/modules/tome/data/zones/crypt-kryl-feijan/npcs.lua
+++ b/game/modules/tome/data/zones/crypt-kryl-feijan/npcs.lua
@@ -74,7 +74,7 @@ newEntity{ define_as = "MELINDA",
 	name = "Melinda",
 	type = "humanoid", subtype = "human", female=true,
 	display = "@", color=colors.LIGHT_BLUE,
-	desc = [[A female Human with twisted sigils scored into her naked flesh. Her wrists and ankles are sore and hurt by ropes and chains. You can discern great beauty beyond the stains of blood covering her skin.]],
+	desc = [[A female human with twisted sigils scored into her naked flesh. Her wrists and ankles are sore and hurt by ropes and chains. You can discern great beauty beyond the stains of blood covering her skin.]],
 	autolevel = "tank",
 	ai = "summoned", ai_real = "move_dmap", ai_state = { ai_target="target_player", talent_in=4, },
 	stats = { str=8, dex=7, mag=8, con=12 },
diff --git a/game/modules/tome/data/zones/halfling-ruins/npcs.lua b/game/modules/tome/data/zones/halfling-ruins/npcs.lua
index 5cc40455c7..cec0fad62a 100644
--- a/game/modules/tome/data/zones/halfling-ruins/npcs.lua
+++ b/game/modules/tome/data/zones/halfling-ruins/npcs.lua
@@ -23,3 +23,114 @@ load("/data/general/npcs/bone-giant.lua", rarity(8))
 
 local Talents = require("engine.interface.ActorTalents")
 
+newEntity{ define_as="SUBJECT_Z",
+	name = "Subject Z", color=colors.VIOLET, display = "p",
+	desc = "This seems to be the 'subject Z' the notes spoke about. He looks human, but this can not be, he would be about five thousands years old!",
+	type = "humanoid", subtype = "human",
+	level_range = {10, nil}, exp_worth = 2,
+	rank = 4,
+	autolevel = "roguemage",
+	max_life = 100, life_rating = 14,
+	combat_armor = 0, combat_def = 15,
+	open_door = 1,
+	never_act = true,
+
+	ai = "tactical", ai_state = { talent_in=1, ai_move="move_astar", },
+
+	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1, QUIVER=1, FINGER=1 },
+
+	see_invisible = 20,
+
+	resolvers.equip{
+		{type="weapon", subtype="dagger", autoreq=true, ego_chance=100},
+		{type="weapon", subtype="dagger", autoreq=true, ego_chance=100},
+		{type="armor", subtype="light", autoreq=true, ego_chance=100},
+		{defined="NIGHT_SONG", random_art_replace={chance=65}, autoreq=true},
+	},
+
+	resolvers.talents{
+		[Talents.T_DUAL_WEAPON_DEFENSE]=3,
+		[Talents.T_DUAL_WEAPON_TRAINING]=3,
+		[Talents.T_FLURRY]=3,
+		[Talents.T_DIRTY_FIGHTING]=3,
+		[Talents.T_LETHALITY]=3,
+		[Talents.T_WEAPON_COMBAT]=2,
+		[Talents.T_KNIFE_MASTERY]=6,
+		[Talents.T_SHADOW_COMBAT]=5,
+		[Talents.T_SHADOWSTEP]=1,
+		[Talents.T_PHASE_DOOR]=3,
+		[Talents.T_SECOND_WIND]=4,
+		[Talents.T_DARK_TENDRILS]=2,
+	},
+	resolvers.inscriptions(1, {"manasurge rune"}),
+	resolvers.inscriptions(1, "infusion"),
+
+	resolvers.sustains_at_birth(),
+
+	seen_by = function(self, who)
+		if not game.party:hasMember(who) then return end
+		self.seen_by = nil
+		self.never_act = nil
+
+		local wayist = nil
+		for uid, e in pairs(game.level.entities) do if e.define_as == "YEEK_WAYIST" then wayist = e break end end
+		if not wayist then return end
+		wayist.never_act = nil
+
+		wayist:setTarget(self)
+		self:setTarget(wayist)
+		wayist:doEmote("Sacrifice for the Way!", 60)
+	end,
+
+	on_die = function(self, who)
+		local wayist = nil
+		for uid, e in pairs(game.level.entities) do if e.define_as == "YEEK_WAYIST" then wayist = e break end end
+		if not wayist then return end
+
+		local p = game.party:findMember{main=true}
+		-- Yeeks really, really, really, hate halflings
+		if p.descriptor.race == "Halfling" then
+			wayist:doEmote("Halfling?! DIE!!!!!", 70)
+			wayist:checkAngered(p, false, -200)
+		else
+			wayist:doEmote("You.. saved me?", 70)
+			wayist.can_talk = "yeek-wayist"
+		end
+	end,
+}
+
+newEntity{ define_as="YEEK_WAYIST",
+	name = "Yeek Wayist", color=colors.VIOLET, display = "y",
+	desc = "This seems to be the 'subject Z' the notes spoke about. He looks human, but this can not be, he would be about five thousands years old!",
+	type = "humanoid", subtype = "yeek",
+	level_range = {10, nil},
+	rank = 3,
+	autolevel = "wildcaster",
+	max_life = 100, life_rating = 8,
+	faction = "the-way",
+	combat_armor = 0, combat_def = 0,
+	psi_regen = 5,
+	open_door = 1,
+	never_act = true,
+
+	ai = "tactical", ai_state = { talent_in=1, ai_move="move_astar", },
+
+	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1, PSIONIC_FOCUS=1 },
+
+	resolvers.equip{
+		{type="weapon", subtype="greatsword", autoreq=true},
+	},
+
+	resolvers.talents{
+		[Talents.T_KINETIC_SHIELD]=3,
+		[Talents.T_MINDHOOK]=1,
+		[Talents.T_PYROKINESIS]=3,
+		[Talents.T_MINDLASH]=2,
+		[Talents.T_REACH]=4,
+		[Talents.T_CHARGED_AURA]=2,
+		[Talents.T_TELEKINETIC_SMASH]=2,
+	},
+	resolvers.inscriptions(1, "infusion"),
+
+	resolvers.sustains_at_birth(),
+}
diff --git a/ideas/DLCs.ods b/ideas/DLCs.ods
index 57dfeffa4b93cb462c6cbe1a352455c3794f05ae..ea4e54edd314e4e1feb2cff486d2f0a662656cb8 100644
GIT binary patch
delta 6885
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
F{{!57qk8}V

delta 6851
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

diff --git a/src/particles_gas.c b/src/particles_gas.c
index d0e4b36df7..c010bf7cb9 100644
--- a/src/particles_gas.c
+++ b/src/particles_gas.c
@@ -357,15 +357,16 @@ static int gas_to_screen(lua_State *L)
 	float zoom = luaL_checknumber(L, 5);
 	int w = 0;
 	int i, j, dx, dy;
-	bool alive = FALSE;
+	int vert_idx = 0, col_idx = 0;
 
-	glBindTexture(GL_TEXTURE_2D, gz->texture);
-
-	if (gz->last_tick == -1) gz->last_tick = ((float)SDL_GetTicks()) / 1000.0f - 1;
+	GLfloat vertices[2*4*1000];
+	GLfloat colors[4*4*1000];
+	GLshort texcoords[2*4*1000];
 
-	float now = ((float)SDL_GetTicks()) / 1000.0f;
-	update(gz, now - gz->last_tick);
-	gz->last_tick = now;
+	glBindTexture(GL_TEXTURE_2D, gz->texture);
+	glTexCoordPointer(2, GL_SHORT, 0, texcoords);
+	glColorPointer(4, GL_FLOAT, 0, colors);
+	glVertexPointer(2, GL_FLOAT, 0, vertices);
 
 	for (dx=0; dx <= gz->n; dx++)
 	{
@@ -375,22 +376,55 @@ static int gas_to_screen(lua_State *L)
 			coef = CLAMP(0.0f, 1.0f, coef);
 			if (coef > 0.1)
 			{
-				tglColor4f(coef, 0, 0, coef);
-
-				glBegin(GL_QUADS);
 				i = x + dx * 4;
 				j = y + dy * 4;
-				glTexCoord2f(0,0); glVertex3f(0 + i,	0 + j,		-97);
-				glTexCoord2f(1,0); glVertex3f(10 + i,	0 + j,		-97);
-				glTexCoord2f(1,1); glVertex3f(10 + i,	10 + j,		-97);
-				glTexCoord2f(0,1); glVertex3f(0 + i,	10 + j,		-97);
-				glEnd();
+
+				vertices[vert_idx+0] = i; vertices[vert_idx+1] = j;
+				vertices[vert_idx+2] = i + 10; vertices[vert_idx+3] = j;
+				vertices[vert_idx+4] = i + 10; vertices[vert_idx+5] = j + 10;
+				vertices[vert_idx+6] = i; vertices[vert_idx+7] = j + 10;
+
+				/* 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] = coef; colors[col_idx+1] = 0; colors[col_idx+2] = 0; colors[col_idx+3] = coef;
+				colors[col_idx+4] = coef; colors[col_idx+5] = 0; colors[col_idx+6] = 0; colors[col_idx+7] = coef;
+				colors[col_idx+8] = coef; colors[col_idx+9] = 0; colors[col_idx+10] = 0; colors[col_idx+11] = coef;
+				colors[col_idx+12] = coef; colors[col_idx+13] = 0; colors[col_idx+14] = 0; colors[col_idx+15] = coef;
+
+				/* Draw if over PARTICLES_PER_ARRAY particles */
+				vert_idx += 8;
+				col_idx += 16;
+				if (vert_idx >= 2*4*1000) {
+					// 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, 1);
+	return 1;
+}
+
+static int gas_update(lua_State *L)
+{
+	gaszone_type *gz = (gaszone_type*)auxiliar_checkclass(L, "core{gas}", 1);
+
+	if (gz->last_tick == -1) gz->last_tick = ((float)SDL_GetTicks()) / 1000.0f - 1;
+
+	float now = ((float)SDL_GetTicks()) / 1000.0f;
+	update(gz, now - gz->last_tick);
+	gz->last_tick = now;
 
 	lua_pushboolean(L, 1);
 	return 1;
@@ -407,6 +441,7 @@ static const struct luaL_reg gas_reg[] =
 	{"__gc", gas_free},
 	{"close", gas_free},
 	{"emit", gas_emit},
+	{"update", gas_update},
 	{"toScreen", gas_to_screen},
 	{NULL, NULL},
 };
-- 
GitLab