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