From 0b6b1c9b2f4818bbfcdff7ca9e77c68d71399056 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Sun, 29 Nov 2009 22:51:12 +0000
Subject: [PATCH] actor resources talent cooldowns

git-svn-id: http://svn.net-core.org/repos/t-engine4@73 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engine/interface/ActorResource.lua   | 53 +++++++++++++++++++++++
 game/engine/interface/ActorTalents.lua    | 32 +++++++++++++-
 game/modules/tome/class/Actor.lua         | 48 ++++++++++++++------
 game/modules/tome/class/Game.lua          |  9 +++-
 game/modules/tome/class/NPC.lua           |  1 +
 game/modules/tome/class/Player.lua        |  2 +
 game/modules/tome/class/PlayerDisplay.lua |  8 +++-
 game/modules/tome/data/talents.lua        |  7 ++-
 8 files changed, 140 insertions(+), 20 deletions(-)
 create mode 100644 game/engine/interface/ActorResource.lua

diff --git a/game/engine/interface/ActorResource.lua b/game/engine/interface/ActorResource.lua
new file mode 100644
index 0000000000..6183ee7f3d
--- /dev/null
+++ b/game/engine/interface/ActorResource.lua
@@ -0,0 +1,53 @@
+require "engine.class"
+
+--- Handles actors life and death
+module(..., package.seeall, class.make)
+
+_M.resources_def = {}
+
+--- Defines resource
+-- Static!
+-- All actors will now have :getResourcename() and :incResourcename() methods as well as a .max_resourcename and .resourcename
+-- properties. It is advised to NOT access .resourcename directly and use the get/inc methods. They handle talent
+-- dependencies
+function _M:defineResource(name, short_name, talent, desc)
+	assert(name, "no resource name")
+	assert(short_name, "no resource short_name")
+	table.insert(self.resources_def, {
+		name = name,
+		short_name = short_name,
+		talent = talent,
+		description = desc,
+	})
+	self.resources_def[#self.resources_def].id = #self.resources_def
+	self.resources_def[short_name] = self.resources_def[#self.resources_def]
+	self["RS_"..short_name:upper()] = #self.resources_def
+	local maxname = "max_"..short_name
+	self["inc"..short_name:lower():capitalize()] = function(self, v)
+		self[short_name] = util.bound(self[short_name] + v, 0, self[maxname])
+	end
+	self["incMax"..short_name:lower():capitalize()] = function(self, v)
+		self[maxname] = self[maxname] + v
+	end
+	if talent then
+		-- if there is an associated talent, check for it
+		self["get"..short_name:lower():capitalize()] = function(self)
+			if self:knowTalent(talent) then
+				return self[short_name]
+			else
+				return 0
+			end
+		end
+	else
+		self["get"..short_name:lower():capitalize()] = function(self)
+			return self[short_name]
+		end
+	end
+end
+
+function _M:init(t)
+	for i, r in ipairs(_M.resources_def) do
+		self["max_"..r.short_name] = t["max_"..r.short_name] or 100
+		self[r.short_name] = t[r.short_name] or self["max_"..r.short_name]
+	end
+end
diff --git a/game/engine/interface/ActorTalents.lua b/game/engine/interface/ActorTalents.lua
index 8038cfe192..1745b6b113 100644
--- a/game/engine/interface/ActorTalents.lua
+++ b/game/engine/interface/ActorTalents.lua
@@ -37,8 +37,6 @@ function _M:newTalent(t)
 	assert(t.type, "no or unknown talent type")
 	t.short_name = t.short_name or t.name
 	t.short_name = t.short_name:upper():gsub("[ ]", "_")
-	t.mana = t.mana or 0
-	t.stamina = t.stamina or 0
 	t.mode = t.mode or "activated"
 	t.points = t.points or 1
 	assert(t.mode == "activated" or t.mode == "sustained", "wrong talent mode, requires either 'activated' or 'sustained'")
@@ -65,6 +63,7 @@ end
 function _M:init(t)
 	self.talents = t.talents or {}
 	self.talents_types = t.talents_types or {}
+	self.talents_cd = {}
 end
 
 --- Make the actor use the talent
@@ -73,11 +72,18 @@ function _M:useTalent(id)
 	assert(ab, "trying to cast talent "..tostring(id).." but it is not defined")
 
 	if ab.action then
+		if self:isTalentCoolingDown(ab) then
+			game.logPlayer(self, "%s is still on cooldown for %d turns.", ab.name:capitalize(), self.talents_cd[ab.id])
+			return
+		end
 		if not self:preUseTalent(ab) then return end
 		local co = coroutine.create(function()
 			local ret = ab.action(self)
 
 			if not self:postUseTalent(ab, ret) then return end
+
+			-- Everything went ok? then start cooldown if any
+			self:startTalentCooldown(ab)
 		end)
 		local ok, err = coroutine.resume(co)
 		if not ok and err then error(err) end
@@ -229,3 +235,25 @@ function _M:unlearnTalentType(tt)
 	self.talents_types[tt] = nil
 	return true
 end
+
+--- Starts a talent cooldown
+-- @param t the talent to cooldown
+function _M:startTalentCooldown(t)
+	if not t.cooldown then return end
+	self.talents_cd[t.id] = t.cooldown
+end
+
+--- Is talent in cooldown?
+function _M:isTalentCoolingDown(t)
+	if not t.cooldown then return false end
+	if self.talents_cd[t.id] and self.talents_cd[t.id] > 0 then return true else return false end
+end
+
+--- Cooldown all talents by one
+-- This should be called in your actors "act()" method
+function _M:cooldownTalents()
+	for tid, c in pairs(self.talents_cd) do
+		self.talents_cd[tid] = self.talents_cd[tid] - 1
+		if self.talents_cd[tid] == 0 then self.talents_cd[tid] = nil end
+	end
+end
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index abb263aeeb..7901c16f30 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -4,6 +4,7 @@ require "engine.interface.ActorLife"
 require "engine.interface.ActorLevel"
 require "engine.interface.ActorStats"
 require "engine.interface.ActorTalents"
+require "engine.interface.ActorResource"
 require "engine.interface.BloodyDeath"
 require "mod.class.interface.Combat"
 
@@ -14,7 +15,7 @@ module(..., package.seeall, class.inherit(
 	engine.interface.ActorLevel,
 	engine.interface.ActorStats,
 	engine.interface.ActorTalents,
---	engine.interface.ActorResource,
+	engine.interface.ActorResource,
 	engine.interface.BloodyDeath,
 	mod.class.interface.Combat
 ))
@@ -25,13 +26,18 @@ function _M:init(t)
 	engine.interface.ActorLevel.init(self, t)
 	engine.interface.ActorStats.init(self, t)
 	engine.interface.ActorTalents.init(self, t)
---	engine.interface.ActorResouce.init(self, t)
+	engine.interface.ActorResource.init(self, t)
 
 	self.unused_stats = 0
 	self.unused_talents = 0
 	self.unused_talents_types = 0
 end
 
+function _M:act()
+	-- Cooldown talents
+	self:cooldownTalents()
+end
+
 function _M:move(x, y, force)
 	local moved = false
 	if force or self:enoughEnergy() then
@@ -67,7 +73,8 @@ function _M:onStatChange(stat, v)
 	if stat == self.STAT_CON then
 		self.max_life = self.max_life + 5 * v
 	elseif stat == self.STAT_WIL then
-		self.max_mana = self.max_mana + 5 * v
+		self:incMaxMana(5 * v)
+		self:incMaxStamina(5 * v)
 	end
 end
 
@@ -85,17 +92,24 @@ end
 -- @param ab the talent (not the id, the table)
 -- @return true to continue, false to stop
 function _M:preUseTalent(ab)
-	local ret = self:enoughEnergy()
-	if ret == true then
-		if ab.message then
-			game.logSeen(self, "%s", self:useTalentMessage(ab))
-		elseif ab.type[1]:find("^spell/") then
-			game.logSeen(self, "%s casts %s.", self.name:capitalize(), ab.name)
-		else
-			game.logSeen(self, "%s uses %s.", self.name:capitalize(), ab.name)
-		end
+	if not self:enoughEnergy() then return end
+	if ab.mana and self:getMana() < ab.mana then
+		game.logPlayer(self, "You do not have enough mana to cast %s.", ab.name)
+		return
+	end
+	if ab.stamina and self:getStamina() < ab.stamina then
+		game.logPlayer(self, "You do not have enough stamina to use %s.", ab.name)
+		return
+	end
+
+	if ab.message then
+		game.logSeen(self, "%s", self:useTalentMessage(ab))
+	elseif ab.type[1]:find("^spell/") then
+		game.logSeen(self, "%s casts %s.", self.name:capitalize(), ab.name)
+	else
+		game.logSeen(self, "%s uses %s.", self.name:capitalize(), ab.name)
 	end
-	return ret
+	return true
 end
 
 --- Called before a talent is used
@@ -106,5 +120,13 @@ end
 function _M:postUseTalent(ab, ret)
 	if ret == nil then return end
 	self:useEnergy()
+
+	if ab.mana then
+		self:incMana(-ab.mana)
+	end
+	if ab.stamina then
+		self:incStamina(-ab.stamina)
+	end
+
 	return true
 end
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 3e0e1ed3db..0dbac4a1ba 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -11,6 +11,7 @@ local Level = require "engine.Level"
 local Grid = require "engine.Grid"
 local Actor = require "mod.class.Actor"
 local ActorStats = require "engine.interface.ActorStats"
+local ActorResource = require "engine.interface.ActorResource"
 local ActorTalents = require "engine.interface.ActorTalents"
 local Player = require "mod.class.Player"
 local NPC = require "mod.class.NPC"
@@ -39,6 +40,11 @@ end
 function _M:run()
 	-- Damage types
 	DamageType:loadDefinition("/data/damage_types.lua")
+	-- Talents
+	ActorTalents:loadDefinition("/data/talents.lua")
+	-- Actor resources
+	ActorResource:defineResource("Mana", "mana", ActorTalents.T_MANA_POOL, "Mana represents your reserve of magical energies. Each spell cast consumes mana and each sustained spell reduces your maximun mana.")
+	ActorResource:defineResource("Stamina", "stamina", ActorTalents.T_STAMINA_POOL, "Stamina represents your physical fatigue. Each physical ability used reduces it.")
 	-- Actor stats
 	ActorStats:defineStat("Strength",	"str", 10, 1, 100, "Strength defines your character's ability to apply physical force. It increases your melee damage, damage with heavy weapons, your chance to resist physical effects, and carrying capacity.")
 	ActorStats:defineStat("Dexterity",	"dex", 10, 1, 100, "Dexterity defines your character's ability to be agile and alert. It increases your chance to hit, your ability to avoid attacks and your damage with light weapons.")
@@ -46,8 +52,6 @@ function _M:run()
 	ActorStats:defineStat("Willpower",	"wil", 10, 1, 100, "Willpower defines your character's ability to concentrate. It increases your mana and stamina capacity, and your chance to resist mental attacks.")
 	ActorStats:defineStat("Cunning",	"cun", 10, 1, 100, "Cunning defines your character's ability to learn and think. It allows you to learn many wordly abilities, increases your mental resistance and armor penetration.")
 	ActorStats:defineStat("Constitution",	"con", 10, 1, 100, "Constitution defines your character's ability to withstand and resist damage. It increases your maximun life and physical resistance.")
-	-- Talents
-	ActorTalents:loadDefinition("/data/talents.lua")
 
 	self.log = LogDisplay.new(0, self.h * 0.80, self.w * 0.5, self.h * 0.20, nil, nil, nil, {255,255,255}, {30,30,30})
 	self.player_display = PlayerDisplay.new(0, 0, self.w * 0.2, self.h * 0.8, {30,30,0})
@@ -58,6 +62,7 @@ function _M:run()
 
 	self.log("Welcome to #00FF00#Tales of Middle Earth!")
 	self.logSeen = function(e, ...) if e and self.level.map.seens(e.x, e.y) then self.log(...) end end
+	self.logPlayer = function(e, ...) if e == game.player then self.log(...) end end
 
 	-- Setup inputs
 	self:setupCommands()
diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua
index 2b1a4ee9bc..b983b5880a 100644
--- a/game/modules/tome/class/NPC.lua
+++ b/game/modules/tome/class/NPC.lua
@@ -8,5 +8,6 @@ function _M:init(t)
 end
 
 function _M:act()
+	mod.class.Actor.act(self)
 	self:move(self.x + 1, self.y)
 end
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 3e2fd3855b..e6cf6425aa 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -21,6 +21,8 @@ function _M:move(x, y, force)
 end
 
 function _M:act()
+	mod.class.Actor.act(self)
+
 	game.paused = true
 end
 
diff --git a/game/modules/tome/class/PlayerDisplay.lua b/game/modules/tome/class/PlayerDisplay.lua
index e25e602007..559a1b8611 100644
--- a/game/modules/tome/class/PlayerDisplay.lua
+++ b/game/modules/tome/class/PlayerDisplay.lua
@@ -25,7 +25,13 @@ function _M:display()
 	self.surface:drawColorString(self.font, "Level: #00ff00#"..game.player.level, 0, h, 255, 255, 255) h = h + self.font_h
 	self.surface:drawColorString(self.font, ("Exp: #00ff00#%2d%%"):format(100 * cur_exp / max_exp), 0, h, 255, 255, 255) h = h + self.font_h
 	h = h + self.font_h
-	self.surface:drawColorString(self.font, ("#c00000#Life: #00ff00#%d/%d"):format(game.player.life, game.player.max_life), 0, h, 255, 255, 255) h = h + self.font_h
+	self.surface:drawColorString(self.font, ("#c00000#Life:    #00ff00#%d/%d"):format(game.player.life, game.player.max_life), 0, h, 255, 255, 255) h = h + self.font_h
+	if game.player:knowTalent(game.player.T_MANA_POOL) then
+		self.surface:drawColorString(self.font, ("#7fffd4#Mana:    #00ff00#%d/%d"):format(game.player:getMana(), game.player.max_mana), 0, h, 255, 255, 255) h = h + self.font_h
+	end
+	if game.player:knowTalent(game.player.T_STAMINA_POOL) then
+		self.surface:drawColorString(self.font, ("#ffcc80#Stamina: #00ff00#%d/%d"):format(game.player:getMana(), game.player.max_mana), 0, h, 255, 255, 255) h = h + self.font_h
+	end
 	h = h + self.font_h
 	self.surface:drawColorString(self.font, ("STR: #00ff00#%3d"):format(game.player:getStr()), 0, h, 255, 255, 255) h = h + self.font_h
 	self.surface:drawColorString(self.font, ("DEX: #00ff00#%3d"):format(game.player:getDex()), 0, h, 255, 255, 255) h = h + self.font_h
diff --git a/game/modules/tome/data/talents.lua b/game/modules/tome/data/talents.lua
index a1468efea7..6bd02d39bf 100644
--- a/game/modules/tome/data/talents.lua
+++ b/game/modules/tome/data/talents.lua
@@ -51,7 +51,8 @@ newTalent{
 newTalent{
 	name = "Disruption Shield",
 	type = {"spell/arcane",2},
-	mana = 80,
+	mode = "sustained",
+	sustain_mana = 60,
 	tactical = {
 		DEFEND = 10,
 	},
@@ -87,7 +88,8 @@ newTalent{
 newTalent{
 	name = "Fireflash",
 	type = {"spell/fire",2},
-	mana = 45,
+	mana = 35,
+	cooldown = 6,
 	tactical = {
 		ATTACKAREA = 10,
 	},
@@ -101,6 +103,7 @@ newTalent{
 	require = { stat = { mag=16 }, },
 	info = function(self)
 		return ([[Conjures up a flash of fire doing %0.2f fire damage in a radius of %d.
+		Cooldown: 6 turns
 		The damage will increase with the Magic stat]]):format(8 + self:getMag(70), math.min(6, 3 + self:getMag(6)))
 	end,
 }
-- 
GitLab