From 15f888aad5fa7308c7e8d486597f14a3de24fd8a Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Thu, 26 Apr 2012 16:52:34 +0000
Subject: [PATCH] Wands have been redesigned into a new cooldown, chargeless
 system. All wands are now on the same cooldown, when activating one all are
 on cooldown for X turns

git-svn-id: http://svn.net-core.org/repos/t-engine4@5050 51575b47-30f0-44d4-a5cc-537603b46e54
---
 .../default/engine/HotkeysIconsDisplay.lua    | 11 ++-
 .../default/engine/interface/ActorTalents.lua |  2 +
 .../engine/interface/ObjectActivable.lua      | 24 +++--
 game/modules/tome/class/Actor.lua             |  4 +-
 game/modules/tome/class/Object.lua            | 21 ++++-
 .../tome/data/general/objects/egos/wands.lua  | 87 +++++++++++--------
 .../tome/data/general/objects/objects.lua     |  1 +
 .../tome/data/general/objects/totems.lua      | 80 +++++++++++++++++
 .../tome/data/general/objects/wands.lua       | 15 ++--
 .../tome/data/general/stores/basic.lua        |  2 +-
 .../tome/data/talents/cursed/fears.lua        |  2 +-
 .../tome/data/talents/misc/objects.lua        | 16 ++++
 .../tome/data/zones/ardhungol/npcs.lua        |  2 +-
 game/modules/tome/data/zones/arena/npcs.lua   |  8 +-
 game/modules/tome/resolvers.lua               | 15 ++--
 15 files changed, 219 insertions(+), 71 deletions(-)
 create mode 100644 game/modules/tome/data/general/objects/totems.lua

diff --git a/game/engines/default/engine/HotkeysIconsDisplay.lua b/game/engines/default/engine/HotkeysIconsDisplay.lua
index e38deb9f98..1c17cb0fe6 100644
--- a/game/engines/default/engine/HotkeysIconsDisplay.lua
+++ b/game/engines/default/engine/HotkeysIconsDisplay.lua
@@ -179,7 +179,16 @@ function _M:display()
 					local t = a:getTalentFromId(o.use_talent.id)
 					display_entity = t.display_entity
 				end
-				if o and (o.use_talent or o.use_power) then
+				if o and o.talent_cooldown then
+					local t = a:getTalentFromId(o.talent_cooldown)
+					angle = 360
+					if a:isTalentCoolingDown(t) then
+						color = {255,0,0}
+						angle = 360 * (1 - (a.talents_cd[t.id] / a:getTalentCooldown(t)))
+						frame = "cooldown"
+						txt = tostring(a:isTalentCoolingDown(t))
+					end
+				elseif o and (o.use_talent or o.use_power) then
 					angle = 360 * ((o.power / o.max_power))
 					color = {255,0,0}
 					local need = (o.use_talent and o.use_talent.power) or (o.use_power and o.use_power.power) or 0
diff --git a/game/engines/default/engine/interface/ActorTalents.lua b/game/engines/default/engine/interface/ActorTalents.lua
index c1ea896cdc..d1d7ac2270 100644
--- a/game/engines/default/engine/interface/ActorTalents.lua
+++ b/game/engines/default/engine/interface/ActorTalents.lua
@@ -541,6 +541,7 @@ end
 --- Starts a talent cooldown
 -- @param t the talent to cooldown
 function _M:startTalentCooldown(t)
+	t = self:getTalentFromId(t)
 	if not t.cooldown then return end
 	local cd = t.cooldown
 	if type(cd) == "function" then cd = cd(self, t) end
@@ -550,6 +551,7 @@ end
 
 --- Is talent in cooldown?
 function _M:isTalentCoolingDown(t)
+	t = self:getTalentFromId(t)
 	if not t.cooldown then return false end
 	if self.talents_cd[t.id] and self.talents_cd[t.id] > 0 then return self.talents_cd[t.id] else return false end
 end
diff --git a/game/engines/default/engine/interface/ObjectActivable.lua b/game/engines/default/engine/interface/ObjectActivable.lua
index da37901696..ddc961cccb 100644
--- a/game/engines/default/engine/interface/ObjectActivable.lua
+++ b/game/engines/default/engine/interface/ObjectActivable.lua
@@ -66,13 +66,19 @@ function _M:useObject(who, ...)
 	if not game:hasEntity(self) then game:addEntity(self) end
 
 	if self.use_power then
-		if self.power >= self.use_power.power then
+		if (self.talent_cooldown and not who:isTalentCoolingDown(self.talent_cooldown)) or (not self.talent_cooldown and self.power >= self.use_power.power) then
 			local ret = self.use_power.use(self, who, ...) or {}
 			local no_power = not ret.used or ret.no_power
-			if not no_power then self.power = self.power - self.use_power.power end
+			if not no_power then 
+				if self.talent_cooldown then
+					who.talents_cd[self.talent_cooldown] = self.use_power.power
+				else
+					self.power = self.power - self.use_power.power 
+				end
+			end
 			return ret
 		else
-			if self.power_regen and self.power_regen ~= 0 then
+			if self.talent_cooldown or (self.power_regen and self.power_regen ~= 0) then
 				game.logPlayer(who, "%s is still recharging.", self:getName{no_count=true})
 			else
 				game.logPlayer(who, "%s can not be used anymore.", self:getName{no_count=true})
@@ -82,18 +88,24 @@ function _M:useObject(who, ...)
 	elseif self.use_simple then
 		return self.use_simple.use(self, who, ...) or {}
 	elseif self.use_talent then
-		if not self.use_talent.power or self.power >= self.use_talent.power then
+		if (self.talent_cooldown and not who:isTalentCoolingDown(self.talent_cooldown)) or (not self.talent_cooldown and (not self.use_talent.power or self.power >= self.use_talent.power)) then
 			local id = self.use_talent.id
 			local ab = self:getTalentFromId(id)
 			local old_level = who.talents[id]; who.talents[id] = self.use_talent.level
 			local ret = ab.action(who, ab)
 			who.talents[id] = old_level
 
-			if ret then self.power = self.power - self.use_talent.power end
+			if ret then 
+				if self.talent_cooldown then
+					who.talents_cd[self.talent_cooldown] = self.use_talent.power
+				else
+					self.power = self.power - self.use_talent.power 
+				end
+			end
 
 			return {used=ret}
 		else
-			if self.power_regen and self.power_regen ~= 0 then
+			if self.talent_cooldown or (self.power_regen and self.power_regen ~= 0) then
 				game.logPlayer(who, "%s is still recharging.", self:getName{no_count=true})
 			else
 				game.logPlayer(who, "%s can not be used anymore.", self:getName{no_count=true})
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 03d5bb27f4..a226d0564e 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -2294,7 +2294,7 @@ function _M:checkMindstar(o)
 		local nm = {}
 		for s, v in pairs(o.combat.dammod) do nm[s] = v * (1.3 + pv / 10) end
 		o.combat.dammod = nm
-		o.comba.apr = o.comba.apr * (1 + pv / 6.3)
+		o.combat.apr = o.combat.apr * (1 + pv / 6.3)
 
 		print("Activating psiblade", o.name)
 	elseif not new and old then
@@ -2303,7 +2303,7 @@ function _M:checkMindstar(o)
 		local nm = {}
 		for s, v in pairs(o.combat.dammod) do nm[s] = v / (1.3 + pv / 10) end
 		o.combat.dammod = nm
-		o.comba.apr = o.comba.apr / (1 + pv / 6.3)
+		o.combat.apr = o.combat.apr / (1 + pv / 6.3)
 
 		o.moddable_tile_ornament = nil
 		o.psiblade_active = false
diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua
index 01529c2f8e..b88174c416 100644
--- a/game/modules/tome/class/Object.lua
+++ b/game/modules/tome/class/Object.lua
@@ -151,9 +151,13 @@ function _M:descAttribute(attr)
 		return self:getTalentFromId(self.use_talent.id).name:lower()
 	elseif attr == "DIGSPEED" then
 		return ("dig speed %d turns"):format(self.digspeed)
+	elseif attr == "CHARM" then
+		return (" [power %d]"):format(self:getCharmPower())
 	elseif attr == "CHARGES" then
-		if self.use_power then
-			return (" (%d/%d)"):format(math.floor(self.power / self.use_power.power), math.floor(self.max_power / self.use_power.power))
+		if self.talent_cooldown and (self.use_power or self.use_talent) then
+			return " ("..(self.use_power or self.use_talent).power.." cooldown)"
+		elseif self.use_power or self.use_talent then
+			return (" (%d/%d)"):format(math.floor(self.power / (self.use_power or self.use_talent).power), math.floor(self.max_power / (self.use_power or self.use_talent).power))
 		else
 			return ""
 		end
@@ -1060,9 +1064,11 @@ end
 function _M:getUseDesc()
 	if self.use_power then
 		if self.show_charges then
-			return tstring{{"color","YELLOW"}, ("It can be used to %s, with %d charges out of %d."):format(self.use_power.name, math.floor(self.power / self.use_power.power), math.floor(self.max_power / self.use_power.power)), {"color","LAST"}}
+			return tstring{{"color","YELLOW"}, ("It can be used to %s, with %d charges out of %d."):format(util.getval(self.use_power.name, self), math.floor(self.power / self.use_power.power), math.floor(self.max_power / self.use_power.power)), {"color","LAST"}}
+		elseif self.talent_cooldown then
+			return tstring{{"color","YELLOW"}, ("It can be used to %s, placing all other charms into a %d cooldown."):format(util.getval(self.use_power.name, self):format(self:getCharmPower()), self.use_power.power), {"color","LAST"}}
 		else
-			return tstring{{"color","YELLOW"}, ("It can be used to %s, costing %d power out of %d/%d."):format(self.use_power.name, self.use_power.power, self.power, self.max_power), {"color","LAST"}}
+			return tstring{{"color","YELLOW"}, ("It can be used to %s, costing %d power out of %d/%d."):format(util.getval(self.use_power.name, self), self.use_power.power, self.power, self.max_power), {"color","LAST"}}
 		end
 	elseif self.use_simple then
 		return tstring{{"color","YELLOW"}, ("It can be used to %s."):format(self.use_simple.name), {"color","LAST"}}
@@ -1318,3 +1324,10 @@ function _M:specialSetAdd(prop, value)
 	self._special_set = self._special_set or {}
 	self._special_set[prop] = self:addTemporaryValue(prop, value)
 end
+
+function _M:getCharmPower()
+	local def = self.charm_power_def or {add=0, max=100}
+	local v = def.add + (self.charm_power * def.max / 100)
+	if def.floor then v = math.floor(v) end
+	return v
+end
diff --git a/game/modules/tome/data/general/objects/egos/wands.lua b/game/modules/tome/data/general/objects/egos/wands.lua
index 62e70d28fd..e608f87595 100644
--- a/game/modules/tome/data/general/objects/egos/wands.lua
+++ b/game/modules/tome/data/general/objects/egos/wands.lua
@@ -18,11 +18,25 @@
 -- darkgod@te4.org
 
 newEntity{
-	name = "solid ", prefix=true,
+	name = "quick ", prefix=true,
 	level_range = {1, 50},
-	rarity = 4,
+	rarity = 15,
 	cost = 5,
-	elec_proof = true,
+	resolvers.genericlast(function(e) 
+		e.use_power.power = math.ceil(e.use_power.power * rng.float(0.6, 0.8))
+		e.charm_power = math.ceil(e.charm_power * rng.float(0.4, 0.7))
+	end),
+}
+
+newEntity{
+	name = "supercharded ", prefix=true,
+	level_range = {1, 50},
+	rarity = 15,
+	cost = 5,
+	resolvers.genericlast(function(e) 
+		e.use_power.power = math.ceil(e.use_power.power * rng.float(1.2, 1.5))
+		e.charm_power = math.ceil(e.charm_power * rng.float(1.3, 1.5))
+	end),
 }
 
 --[[
@@ -41,46 +55,46 @@ newEntity{
 	name = " of detection", suffix=true, instant_resolve=true,
 	level_range = {1, 50},
 	rarity = 8,
-	cost_per_charge = 1,
 
-	use_power = { name = "detect the presence of creatures around you", power = 6, use = function(self, who)
-		local rad = 15 + who:getMag(20)
+	charm_power_def = {add=5, max=10, floor=true},
+	resolvers.charm("detect the presence of creatures around you (rad %d)", 15, function(self, who)
+		local rad = self:getCharmPower()
 		who:setEffect(who.EFF_SENSE, 2, {
 			range = rad,
 			actor = 1,
 		})
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
 newEntity{
 	name = " of illumination", suffix=true, instant_resolve=true,
 	level_range = {1, 50},
 	rarity = 8,
-	cost_per_charge = 0.4,
 
-	use_power = { name = "light the area", power = 3, use = function(self, who)
-		who:project({type="ball", range=0, selffire=true, radius=15}, who.x, who.y, engine.DamageType.LITE, 1)
+	charm_power_def = {add=4, max=15, floor=true},
+	resolvers.charm("light the area (rad %d)", 5, function(self, who)
+		who:project({type="ball", range=0, selffire=true, radius=self:getCharmPower()}, who.x, who.y, engine.DamageType.LITE, 1)
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
 newEntity{
 	name = " of trap destruction", suffix=true, instant_resolve=true,
 	level_range = {1, 50},
 	rarity = 14,
-	cost_per_charge = 1,
 
-	use_power = { name = "try to disarm any known traps in a line", power = 6, use = function(self, who)
+	charm_power_def = {add=resolvers.genericlast(function(e) return e.material_level * 8 end), max=100, floor=true},
+	resolvers.charm("try to disarm any known traps in a line (disarm power %d)", 15, function(self, who)
 		local tg = {type="beam", range=2 + who:getMag(2)}
 		local x, y = who:getTarget(tg)
 		if not x or not y then return nil end
 		who:project(tg, x, y, function(px, py)
 			local trap = game.level.map(px, py, engine.Map.TRAP)
 			if not trap then return end
-			local inc = self.material_level * 10 + who:getMag(80)
+			local inc = self:getCharmPower()
 			who:attr("can_disarm", 1)
 			who:attr("disarm_bonus", inc)
 
@@ -91,73 +105,74 @@ newEntity{
 		end)
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
 newEntity{
 	name = " of teleportation", suffix=true, instant_resolve=true,
 	level_range = {15, 50},
 	rarity = 10,
-	cost_per_charge = 1,
 
-	use_power = { name = "teleport randomly", power = 6, use = function(self, who)
+	charm_power_def = {add=15, max=60, floor=true},
+	resolvers.charm("teleport randomly (rad %d)", 30, function(self, who)
 		game.level.map:particleEmitter(who.x, who.y, 1, "teleport")
-		who:teleportRandom(who.x, who.y, 100)
+		who:teleportRandom(who.x, who.y, self:getCharmPower())
 		game.level.map:particleEmitter(who.x, who.y, 1, "teleport")
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
+
 newEntity{
 	name = " of lightning", suffix=true, instant_resolve=true,
 	level_range = {15, 50},
 	rarity = 10,
-	cost_per_charge = 1,
 
-	use_power = { name = "fire a beam of lightning", power = 6, use = function(self, who)
+	charm_power_def = {add=45, max=300, floor=true},
+	resolvers.charm(function(self) return ("fire a beam of lightning (dam %d-%d)"):format(self:getCharmPower()/3, self:getCharmPower()) end, 6, function(self, who)
 		local tg = {type="beam", range=6 + who:getMag(4)}
 		local x, y = who:getTarget(tg)
 		if not x or not y then return nil end
-		local dam = (40 + who:getMag(20, true)) * self.material_level
+		local dam = self:getCharmPower()
 		who:project(tg, x, y, engine.DamageType.LIGHTNING, rng.avg(dam / 3, dam, 3))
 		local _ _, x, y = who:canProject(tg, x, y)
 		game.level.map:particleEmitter(who.x, who.y, math.max(math.abs(x-who.x), math.abs(y-who.y)), "lightning", {tx=x-who.x, ty=y-who.y})
 		game:playSoundNear(who, "talents/lightning")
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
 newEntity{
 	name = " of flames", suffix=true, instant_resolve=true,
 	level_range = {15, 50},
 	rarity = 10,
-	cost_per_charge = 1,
 
-	use_power = { name = "fire a beam of fire", power = 6, use = function(self, who)
+	charm_power_def = {add=25, max=250, floor=true},
+	resolvers.charm("fire a beam of flames (dam %d)", 6, function(self, who)
 		local tg = {type="beam", range=6 + who:getMag(4)}
 		local x, y = who:getTarget(tg)
 		if not x or not y then return nil end
-		local dam = (35 + who:getMag(20, true)) * self.material_level
+		local dam = self:getCharmPower()
 		who:project(tg, x, y, engine.DamageType.FIRE, dam, {type="flame"})
 		game:playSoundNear(who, "talents/fire")
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
 newEntity{
 	name = " of conjuration", suffix=true, instant_resolve=true,
 	level_range = {10, 50},
 	rarity = 6,
-	cost_per_charge = 0.5,
 
-	use_power = { name = "fire a bolt of a random element", power = 6, use = function(self, who)
+	charm_power_def = {add=25, max=250, floor=true},
+	resolvers.charm(function(self) return ("fire a bolt of a random element (dam %d-%d)"):format(self:getCharmPower()/2, self:getCharmPower()) end, 6, function(self, who)
 		local tg = {type="bolt", range=10 + who:getMag(10)}
 		local x, y = who:getTarget(tg)
 		if not x or not y then return nil end
-		local dam = (45 + who:getMag(25, true)) * self.material_level
+		local dam = self:getCharmPower()
 		local elem = rng.table{
 			{engine.DamageType.FIRE, "flame"},
 			{engine.DamageType.COLD, "freeze"},
@@ -170,23 +185,23 @@ newEntity{
 		game:playSoundNear(who, "talents/fire")
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
 
 newEntity{
 	name = " of healing", suffix=true, instant_resolve=true,
 	level_range = {25, 50},
 	rarity = 20,
-	cost_per_charge = 4,
 
-	use_power = { name = "heal", power = 12, use = function(self, who)
-		local tg = {default_target=who, type="hit", nowarning=true, range=6 + who:getMag(4), first_target="friend"}
+	charm_power_def = {add=50, max=250, floor=true},
+	resolvers.charm("heals the target for %d", 35, function(self, who)
+		local tg = {default_target=who, type="hit", nowarning=true, range=6 + who:getWil(4), first_target="friend"}
 		local x, y = who:getTarget(tg)
 		if not x or not y then return nil end
-		local dam = (80 + who:getMag(50, true)) * self.material_level
+		local dam = self:getCharmPower()
 		who:project(tg, x, y, engine.DamageType.HEAL, dam)
 		game:playSoundNear(who, "talents/heal")
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
-	end}
+	end),
 }
diff --git a/game/modules/tome/data/general/objects/objects.lua b/game/modules/tome/data/general/objects/objects.lua
index 0ee760c4d2..d2a5f29004 100644
--- a/game/modules/tome/data/general/objects/objects.lua
+++ b/game/modules/tome/data/general/objects/objects.lua
@@ -31,6 +31,7 @@ loadIfNot("/data/general/objects/lites.lua")
 loadIfNot("/data/general/objects/potions.lua")
 loadIfNot("/data/general/objects/scrolls.lua")
 loadIfNot("/data/general/objects/wands.lua")
+loadIfNot("/data/general/objects/totems.lua")
 
 -- Tools
 loadIfNot("/data/general/objects/digger.lua")
diff --git a/game/modules/tome/data/general/objects/totems.lua b/game/modules/tome/data/general/objects/totems.lua
new file mode 100644
index 0000000000..9db98ac064
--- /dev/null
+++ b/game/modules/tome/data/general/objects/totems.lua
@@ -0,0 +1,80 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012 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
+
+newEntity{
+	define_as = "BASE_TOTEM",
+	type = "charm", subtype="totem",
+	unided_name = "totem", id_by_type = true,
+	display = "-", color=colors.WHITE, image = resolvers.image_material("wand", "wood"),
+	encumber = 2,
+	rarity = 9,
+	add_name = "#CHARM# #CHARGES#",
+	use_sound = "talents/spell_generic",
+	is_magic_device = true,
+	elec_destroy = {{20,1}, {30,2}, {60,5}, {90,10}, {170,20}},
+	desc = [[Natural totems are made by powerful wilders to store nature power.]],
+	egos = "/data/general/objects/egos/totems.lua", egos_chance = { prefix=resolvers.mbonus(20, 5), suffix=100 }, ego_first_type = "suffix",
+	power_source = {nature=true},
+	talent_cooldown = "T_GLOBAL_CD",
+}
+
+newEntity{ base = "BASE_TOTEM",
+	name = "elm totem",
+	color = colors.UMBER,
+	level_range = {1, 10},
+	cost = 1,
+	material_level = 1,
+	charm_power = resolvers.mbonus_material(15, 10),
+}
+
+newEntity{ base = "BASE_TOTEM",
+	name = "ash totem",
+	color = colors.UMBER,
+	level_range = {10, 20},
+	cost = 2,
+	material_level = 2,
+	charm_power = resolvers.mbonus_material(20, 20),
+}
+
+newEntity{ base = "BASE_TOTEM",
+	name = "yew totem",
+	color = colors.UMBER,
+	level_range = {20, 30},
+	cost = 3,
+	material_level = 3,
+	charm_power = resolvers.mbonus_material(25, 30),
+}
+
+newEntity{ base = "BASE_TOTEM",
+	name = "elven-wood totem",
+	color = colors.UMBER,
+	level_range = {30, 40},
+	cost = 4,
+	material_level = 4,
+	charm_power = resolvers.mbonus_material(30, 40),
+}
+
+newEntity{ base = "BASE_TOTEM",
+	name = "dragonbone totem",
+	color = colors.UMBER,
+	level_range = {40, 50},
+	cost = 5,
+	material_level = 5,
+	charm_power = resolvers.mbonus_material(35, 50),
+}
diff --git a/game/modules/tome/data/general/objects/wands.lua b/game/modules/tome/data/general/objects/wands.lua
index d53c8cde45..5fbe165538 100644
--- a/game/modules/tome/data/general/objects/wands.lua
+++ b/game/modules/tome/data/general/objects/wands.lua
@@ -19,18 +19,19 @@
 
 newEntity{
 	define_as = "BASE_WAND",
-	type = "wand", subtype="wand",
+	type = "charm", subtype="wand",
 	unided_name = "wand", id_by_type = true,
 	display = "-", color=colors.WHITE, image = resolvers.image_material("wand", "wood"),
 	encumber = 2,
 	rarity = 9,
-	add_name = "#CHARGES#",
+	add_name = "#CHARM# #CHARGES#",
 	use_sound = "talents/spell_generic",
 	is_magic_device = true,
 	elec_destroy = {{20,1}, {30,2}, {60,5}, {90,10}, {170,20}},
 	desc = [[Magical wands are made by powerful Alchemists and Archmagi to store spells. Anybody can use them to release the spells.]],
 	egos = "/data/general/objects/egos/wands.lua", egos_chance = { prefix=resolvers.mbonus(20, 5), suffix=100 }, ego_first_type = "suffix",
 	power_source = {arcane=true},
+	talent_cooldown = "T_GLOBAL_CD",
 }
 
 newEntity{ base = "BASE_WAND",
@@ -39,7 +40,7 @@ newEntity{ base = "BASE_WAND",
 	level_range = {1, 10},
 	cost = 1,
 	material_level = 1,
-	resolvers.charges(10, 30),
+	charm_power = resolvers.mbonus_material(15, 10),
 }
 
 newEntity{ base = "BASE_WAND",
@@ -48,7 +49,7 @@ newEntity{ base = "BASE_WAND",
 	level_range = {10, 20},
 	cost = 2,
 	material_level = 2,
-	resolvers.charges(25, 45),
+	charm_power = resolvers.mbonus_material(20, 20),
 }
 
 newEntity{ base = "BASE_WAND",
@@ -57,7 +58,7 @@ newEntity{ base = "BASE_WAND",
 	level_range = {20, 30},
 	cost = 3,
 	material_level = 3,
-	resolvers.charges(40, 60),
+	charm_power = resolvers.mbonus_material(25, 30),
 }
 
 newEntity{ base = "BASE_WAND",
@@ -66,7 +67,7 @@ newEntity{ base = "BASE_WAND",
 	level_range = {30, 40},
 	cost = 4,
 	material_level = 4,
-	resolvers.charges(55, 75),
+	charm_power = resolvers.mbonus_material(30, 40),
 }
 
 newEntity{ base = "BASE_WAND",
@@ -75,5 +76,5 @@ newEntity{ base = "BASE_WAND",
 	level_range = {40, 50},
 	cost = 5,
 	material_level = 5,
-	resolvers.charges(70, 90),
+	charm_power = resolvers.mbonus_material(35, 50),
 }
diff --git a/game/modules/tome/data/general/stores/basic.lua b/game/modules/tome/data/general/stores/basic.lua
index 1ea0656783..0f63ac3ef1 100644
--- a/game/modules/tome/data/general/stores/basic.lua
+++ b/game/modules/tome/data/general/stores/basic.lua
@@ -228,7 +228,7 @@ newEntity{
 				{type="weapon", subtype="staff", id=true, tome_drops="store"},
 				{type="weapon", subtype="staff", id=true, tome_drops="store"},
 				{type="weapon", subtype="staff", id=true, tome_drops="store"},
-				{type="wand", subtype="wand", id=true, tome_drops="store"},
+				{type="charm", subtype="wand", id=true, tome_drops="store"},
 			}
 		end,
 	},
diff --git a/game/modules/tome/data/talents/cursed/fears.lua b/game/modules/tome/data/talents/cursed/fears.lua
index 4dee4faf05..93c0ccead2 100644
--- a/game/modules/tome/data/talents/cursed/fears.lua
+++ b/game/modules/tome/data/talents/cursed/fears.lua
@@ -60,7 +60,7 @@ newTalent{
 		
 		local mindpower = self:combatMindpower(1, mindpowerChange)
 		if not target:checkHit(mindpower, target:combatMentalResist()) then
-			game:logSeen(target, "%s resists the fear!", target.name:capitalize())
+			game.logSeen(target, "%s resists the fear!", target.name:capitalize())
 			return nil
 		end
 		
diff --git a/game/modules/tome/data/talents/misc/objects.lua b/game/modules/tome/data/talents/misc/objects.lua
index ed91d48a21..263b5b9065 100644
--- a/game/modules/tome/data/talents/misc/objects.lua
+++ b/game/modules/tome/data/talents/misc/objects.lua
@@ -23,6 +23,22 @@ newTalentType{ no_silence=true, is_spell=true, type="spell/objects", name = "obj
 --local oldTalent = newTalent
 --local newTalent = function(t) if type(t.hide) == "nil" then t.hide = true end return oldTalent(t) end
 
+newTalent{
+	name = "charms", short_name = "GLOBAL_CD",
+	type = {"spell/objects",1},
+	points = 1,
+	cooldown = 1,
+	no_npc_use = true,
+	hide = true,
+	action = function(self, t)
+		return true
+	end,
+	info = function(self, t)
+		return ""
+	end,
+}
+
+
 newTalent{
 	name = "Arcane Supremacy",
 	type = {"spell/objects",1},
diff --git a/game/modules/tome/data/zones/ardhungol/npcs.lua b/game/modules/tome/data/zones/ardhungol/npcs.lua
index cc5fa45284..95d58745cb 100644
--- a/game/modules/tome/data/zones/ardhungol/npcs.lua
+++ b/game/modules/tome/data/zones/ardhungol/npcs.lua
@@ -46,7 +46,7 @@ newEntity{ define_as = "UNGOLE", base = "BASE_NPC_SPIDER",
 
 	body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1 },
 	resolvers.drops{chance=100, nb=5, {tome_drops="boss"} },
-	resolvers.drops{chance=100, nb=1, {type="wand", subtype="wand", defined="ROD_SPYDRIC_POISON"} },
+	resolvers.drops{chance=100, nb=1, {defined="ROD_SPYDRIC_POISON"} },
 	resolvers.drops{chance=100, nb=1, {unique=true} },
 
 	resolvers.talents{
diff --git a/game/modules/tome/data/zones/arena/npcs.lua b/game/modules/tome/data/zones/arena/npcs.lua
index b707eab65c..841e472e4c 100644
--- a/game/modules/tome/data/zones/arena/npcs.lua
+++ b/game/modules/tome/data/zones/arena/npcs.lua
@@ -155,7 +155,7 @@ newEntity{ name = "master alchemist",
 		{type="weapon", subtype="staff", force_drop=true, tome_drops="boss", autoreq=true},
 		{type="armor", subtype="cloth", force_drop=true, tome_drops="boss", autoreq=true},
 	},
-	resolvers.drops{chance=100, nb=1, {type="wand", ego_chance=100}},
+	resolvers.drops{chance=100, nb=1, {type="charm", subtype="wand", ego_chance=100}},
 	autolevel = "dexmage",
 	combat_def = 3,
 	resolvers.talents{
@@ -656,7 +656,7 @@ newEntity{ name = "alchemist",
 		{type="weapon", subtype="staff", autoreq=true},
 		{type="armor", subtype="cloth", autoreq=true},
 	},
-	resolvers.drops{chance=40, {type="wand", ego_chance=100}},
+	resolvers.drops{chance=40, {type="charm", subtype="wand", ego_chance=100}},
 	autolevel = "dexmage", ai_tactic = resolvers.tactic("ranged"),
 	combat_def = 2,
 	resolvers.talents{
@@ -690,7 +690,7 @@ newEntity{ name = "blood mage",
 		{type="weapon", subtype="staff", autoreq=true},
 		{type="armor", subtype="cloth", autoreq=true},
 	},
-	resolvers.drops{chance=40, {type="wand", ego_chance=100}},
+	resolvers.drops{chance=40, {type="charm", subtype="wand", ego_chance=100}},
 	autolevel = "caster", ai_tactic = resolvers.tactic("ranged"),
 	resolvers.talents{
 		[Talents.T_BLOOD_GRASP] = 4,
@@ -715,7 +715,7 @@ newEntity{ name = "hexer",
 		{type="weapon", subtype="staff", autoreq=true},
 		{type="armor", subtype="cloth", autoreq=true},
 	},
-	resolvers.drops{chance=40, {type="wand", ego_chance=100}},
+	resolvers.drops{chance=40, {type="charm", subtype="wand", ego_chance=100}},
 	autolevel = "caster", ai_tactic = resolvers.tactic("ranged"),
 	resolvers.talents{
 		[Talents.T_BURNING_HEX]=3,
diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua
index 09a8c28389..7eb7d778d0 100644
--- a/game/modules/tome/resolvers.lua
+++ b/game/modules/tome/resolvers.lua
@@ -343,16 +343,15 @@ function resolvers.calc.random_use_talent(tt, e)
 	return { id=tid, level=level, power=tt[2] }
 end
 
---- Charges resolver
-function resolvers.charges(min, max, cost)
-	return {__resolver="charges", __resolve_last=true, min, max, cost}
+--- Charms resolver
+function resolvers.charm(desc, cd, fct)
+	return {__resolver="charm", desc, cd, fct}
 end
-function resolvers.calc.charges(tt, e)
-	e.max_power = rng.range(tt[1], tt[2])
+function resolvers.calc.charm(tt, e)
+	local cd = tt[2]
+	e.max_power = cd
 	e.power = e.max_power
-	e.recharge_cost = (e.cost_per_charge or 0) * 4
-	e.cost = e.cost + (e.cost_per_charge or 0) * e.max_power
-	e.show_charges = true
+	e.use_power = {name=tt[1], power=cd, use=tt[3]}
 	return
 end
 
-- 
GitLab