From 95d58a8cbe317b037d47d008dc2cd36a50831497 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Mon, 30 Nov 2009 21:41:25 +0000
Subject: [PATCH] lasting spell effects noxious cloud

git-svn-id: http://svn.net-core.org/repos/t-engine4@77 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engine/GameTurnBased.lua                 |  6 ++
 game/engine/Map.lua                           | 80 +++++++++++++++++++
 game/engine/utils.lua                         | 32 ++++++++
 game/modules/tome/class/Actor.lua             |  2 +-
 game/modules/tome/class/Game.lua              | 13 +++
 game/modules/tome/data/talents.lua            | 34 ++++++++
 .../tome/data/zones/ancient_ruins/npcs.lua    |  2 +
 7 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/game/engine/GameTurnBased.lua b/game/engine/GameTurnBased.lua
index cd306a55c9..99fb985a2d 100644
--- a/game/engine/GameTurnBased.lua
+++ b/game/engine/GameTurnBased.lua
@@ -23,6 +23,12 @@ function _M:tick()
 		while not self.paused do
 			engine.GameEnergyBased.tick(self)
 			self.turn = self.turn + 1
+			self:onTurn()
 		end
 	end
 end
+
+--- Called every game turns
+-- Does nothing, you can override it
+function _M:onTurn()
+end
diff --git a/game/engine/Map.lua b/game/engine/Map.lua
index 2f15216e88..c54cfac867 100644
--- a/game/engine/Map.lua
+++ b/game/engine/Map.lua
@@ -2,6 +2,7 @@ require "engine.class"
 local Entity = require "engine.Entity"
 local Tiles = require "engine.Tiles"
 local Faction = require "engine.Faction"
+local DamageType = require "engine.DamageType"
 
 --- Represents a level map, handles display and various low level map work
 module(..., package.seeall, class.make)
@@ -55,6 +56,7 @@ function _M:init(w, h)
 	self.lites = {}
 	self.seens = {}
 	self.remembers = {}
+	self.effects = {}
 	for i = 0, w * h - 1 do self.map[i] = {} end
 
 	self:loaded()
@@ -223,6 +225,9 @@ function _M:display()
 		end end
 ]]
 	end
+
+	self:displayEffects()
+
 	return self.surface
 end
 
@@ -345,3 +350,78 @@ function _M:isBound(x, y)
 	if x < 0 or x >= self.w or y < 0 or y >= self.h then return false end
 	return true
 end
+
+--- Adds a zone (temporary) effect
+-- @param src the source actor
+-- @param x the epicenter coords
+-- @param y the epicenter coords
+-- @param duration the number of turns to persist
+-- @param damtype the DamageType to apply
+-- @param radius the radius of the effect
+-- @param dir the numpad direction of the effect, 5 for a ball effect
+-- @param overlay a simple display entity to draw upon the map
+function _M:addEffect(src, x, y, duration, damtype, dam, radius, dir, angle, overlay, update_fct)
+	table.insert(self.effects, {
+		src=src, x=x, y=y, duration=duration, damtype=damtype, dam=dam, radius=radius, dir=dir, angle=angle, overlay=overlay,
+		update_fct=update_fct,
+	})
+	self.changed = true
+end
+
+--- Display the overlay effects, called by self:display()
+function _M:displayEffects()
+	for i, e in ipairs(self.effects) do
+		local grids
+		local s = self.tiles:get(e.overlay.display, e.overlay.color_r, e.overlay.color_g, e.overlay.color_b, e.overlay.color_br, e.overlay.color_bg, e.overlay.color_bb, e.overlay.image)
+		s:alpha(e.alpha or 150)
+
+		-- Handle balls
+		if e.dir == 5 then
+			grids = core.fov.circle_grids(e.x, e.y, e.radius, true)
+		-- Handle beams
+		else
+			grids = core.fov.beam_grids(e.x, e.y, e.radius, e.dir, e.angle, true)
+		end
+
+		-- Now display each grids
+		for lx, ys in pairs(grids) do
+			for ly, _ in pairs(ys) do
+				if self.seens(lx, ly) then
+					self.surface:merge(s, (lx - self.mx) * self.tile_w, (ly - self.my) * self.tile_h)
+				end
+			end
+		end
+	end
+end
+
+--- Process the overlay effects, call it from your tick function
+function _M:processEffects()
+	local todel = {}
+	for i, e in ipairs(self.effects) do
+		local grids
+
+		-- Handle balls
+		if e.dir == 5 then
+			grids = core.fov.circle_grids(e.x, e.y, e.radius, true)
+		-- Handle beams
+		else
+			grids = core.fov.beam_grids(e.x, e.y, e.radius, e.dir, e.angle, true)
+		end
+
+		-- Now display each grids
+		for lx, ys in pairs(grids) do
+			for ly, _ in pairs(ys) do
+				DamageType:get(e.damtype).projector(e.src, lx, ly, e.damtype, e.dam)
+			end
+		end
+
+		e.duration = e.duration - 1
+		if e.duration <= 0 then
+			table.insert(todel, i)
+		elseif e.update_fct then
+			e:update_fct()
+		end
+	end
+
+	for i = #todel, 1, -1 do table.remove(self.effects, todel[i]) end
+end
diff --git a/game/engine/utils.lua b/game/engine/utils.lua
index bbd907b119..4424fa0d97 100644
--- a/game/engine/utils.lua
+++ b/game/engine/utils.lua
@@ -199,3 +199,35 @@ function util.bound(i, min, max)
 	elseif i > max then i = max end
 	return i
 end
+
+function core.fov.circle_grids(x, y, radius, block)
+	local grids = {}
+	core.fov.calc_circle(x, y, radius, function(self, lx, ly)
+		if not grids[lx] then grids[lx] = {} end
+		grids[lx][ly] = true
+
+		if block and game.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_move") then return true end
+	end, function()end, self)
+
+	-- point of origin
+	if not grids[x] then grids[x] = {} end
+	grids[x][y] = true
+
+	return grids
+end
+
+function core.fov.beam_grids(x, y, radius, dir, angle, block)
+	local grids = {}
+	core.fov.calc_beam(x, y, radius, dir, angle, function(self, lx, ly)
+		if not grids[lx] then grids[lx] = {} end
+		grids[lx][ly] = true
+
+		if block and game.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_move") then return true end
+	end, function()end, self)
+
+	-- point of origin
+	if not grids[x] then grids[x] = {} end
+	grids[x][y] = true
+
+	return grids
+end
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 64410f97ac..df1c665e0c 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -81,7 +81,7 @@ function _M:levelup()
 	-- Healp up on new level
 	self.life = self.max_life
 	self.mana = self.max_mana
-	self.stamina = self.man_stamina
+	self.stamina = self.max_stamina
 
 	-- Auto levelup ?
 	if self.autolevel then
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 269233a3e7..3cc4c9c29f 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -124,6 +124,16 @@ function _M:tick()
 	-- Fun stuff: this can make the game realtime, although callit it in display() will make it work better
 	-- (since display is on a set FPS while tick() ticks as much as possible
 	-- engine.GameEnergyBased.tick(self)
+end
+
+--- Called every game turns
+-- Does nothing, you can override it
+function _M:onTurn()
+	-- The following happens only every 10 game turns (once for every turn of 1 mod speed actors)
+	if self.turn % 10 ~= 0 then return end
+
+	-- Process overlay effects
+	self.level.map:processEffects()
 
 	if not self.day_of_year or self.day_of_year ~= self.calendar:getDayOfYear(self.turn) then
 		self.log(self.calendar:getTimeDate(self.turn))
@@ -259,6 +269,9 @@ function _M:setupCommands()
 		_a = function()
 			self.player:useTalent(ActorTalents.T_FIREFLASH)
 		end,
+		_e = function()
+			self.player:useTalent(ActorTalents.T_NOXIOUS_CLOUD)
+		end,
 		_z = function()
 			self.player:useTalent(ActorTalents.T_BLINK)
 		end,
diff --git a/game/modules/tome/data/talents.lua b/game/modules/tome/data/talents.lua
index 2653cd67d2..e1bf6104d9 100644
--- a/game/modules/tome/data/talents.lua
+++ b/game/modules/tome/data/talents.lua
@@ -147,3 +147,37 @@ newTalent{
 		The radius (%d) of the target area decreases with Magic stat]]):format(5 - self:getMag(4))
 	end,
 }
+
+
+newTalent{
+	name = "Noxious Cloud",
+	type = {"spell/earth",1},
+	mana = 45,
+	cooldown = 8,
+	tactical = {
+		ATTACKAREA = 10,
+	},
+	action = function(self)
+		local duration = 5 + self:getMag(10)
+		local radius = 3
+		local t = {type="ball", range=15, radius=math.min(6, 3 + self:getMag(6))}
+		local x, y = self:getTarget(t)
+		if not x or not y then return nil end
+		x, y = game.target:pointAtRange(self.x, self.y, x, y, 15)
+		-- Add a lasting map effect
+		game.level.map:addEffect(self,
+			x, y, duration,
+			DamageType.NATURE, 4 + self:getMag(30),
+			radius,
+			5, nil,
+			engine.Entity.new{alpha=100, display='', color_br=30, color_bg=180, color_bb=60}
+		)
+		return true
+	end,
+	require = { stat = { mag=16 }, },
+	info = function(self)
+		return ([[Noxious fumes raises from the ground doing %0.2f nature damage in a radius of 3 each turns for %d turns.
+		Cooldown: 8 turns
+		The damage and duration will increase with the Magic stat]]):format(4 + self:getMag(30), 5 + self:getMag(10))
+	end,
+}
diff --git a/game/modules/tome/data/zones/ancient_ruins/npcs.lua b/game/modules/tome/data/zones/ancient_ruins/npcs.lua
index d974b1cc44..281cf80922 100644
--- a/game/modules/tome/data/zones/ancient_ruins/npcs.lua
+++ b/game/modules/tome/data/zones/ancient_ruins/npcs.lua
@@ -7,6 +7,7 @@ return {
 	autolevel = "warrior",
 	max_life = 20,
 	max_mana = 1000,
+	max_stamina = 1000,
 	energy = { mod=0.5 },
 	has_blood = true,
 	stats = { str=15, dex=8, mag=12, },
@@ -20,6 +21,7 @@ return {
 	autolevel = "caster",
 	max_life = 30,
 	max_mana = 1000,
+	max_stamina = 1000,
 	energy = { mod=0.3 },
 	has_blood = {nb=3, color={50,255,120}},
 	combat = { dam=5, atk=6, def=2, apr=1, armor=2},
-- 
GitLab