diff --git a/game/engines/default/engine/Trap.lua b/game/engines/default/engine/Trap.lua
index 45ef4525792563f2242140338f47f3b85e7eb1a1..739c5becdc4e493846d0b93f57f6f4f4b303e31d 100644
--- a/game/engines/default/engine/Trap.lua
+++ b/game/engines/default/engine/Trap.lua
@@ -28,6 +28,7 @@ module(..., package.seeall, class.inherit(Entity))
 _M.display_on_seen = true
 _M.display_on_remember = true
 _M.display_on_unknown = false
+_M.__is_trap = true
 
 function _M:init(t, no_default)
 	t = t or {}
@@ -88,7 +89,7 @@ end
 
 --- Get the known status for the given actor
 function _M:knownBy(actor)
-	return self.known_by[actor] or self.all_know
+	return self.all_know or self.known_by[actor]
 end
 
 --- Can we disarm this trap?
diff --git a/game/engines/default/engine/ui/Inventory.lua b/game/engines/default/engine/ui/Inventory.lua
index 2f6644f2386a69d1947c1c3168cb85e254a8da70..fca180d5f2c9b2d51aef247644c9fc554446e277 100644
--- a/game/engines/default/engine/ui/Inventory.lua
+++ b/game/engines/default/engine/ui/Inventory.lua
@@ -75,12 +75,26 @@ function _M:generate()
 		end
 
 		self.c_tabs.no_keyboard_focus = true
-		if _M._last_tabs then
-			for _, l in ipairs(_M._last_tabs) do self.c_tabs.dlist[l[1]][l[2]].selected = true end
-			if _M._last_tabs_i then self.c_tabs.sel_i = _M._last_tabs_i end
-		else
+
+		local found_tab = false
+		if _M._last_tabs then -- reselect previously selected tabs if possible
+			local sel_all = _M._last_tabs.all
+			local last_kinds = {}
+			for _, lt in ipairs(_M._last_tabs) do if lt.kind then last_kinds[lt.kind] = true end end
+			for j, row in ipairs(self.c_tabs.dlist) do for i, item in ipairs(row) do
+				if sel_all or last_kinds[item.data.kind] then
+					item.selected = true
+					found_tab = true
+					self.c_tabs.sel_i, self.c_tabs.sel_j = i, j
+					if sel_all and item.data.filter=="all" then _M._last_tabs_i = i end
+				end
+			end end
+		end
+		if not found_tab then
+			self.c_tabs.sel_i, self.c_tabs.sel_j = 1, 1
 			self.c_tabs.dlist[1][1].selected = true
 		end
+
 		self.uis[#self.uis+1] = {x=0, y=0, ui=self.c_tabs}
 		self.c_tabs.on_focus_change = function(ui_self, status)
 			if status == true then
@@ -241,14 +255,17 @@ function _M:updateTabFilterList(list)
 		return false
 	end
 
-	-- Save for next dialogs
+	-- Save for next dialog
 	if not self.dont_update_last_tabs then
 		_M._last_tabs = self.c_tabs:getAllSelectedKeys()
 		if not is_all then
 			local i = 1
-			for _, d in ipairs(_M._last_tabs) do i = math.max(i, d[2]) end
+			for _, d in ipairs(_M._last_tabs) do
+				i = math.max(i, d[2]) d.kind = self.c_tabs.dlist[d[1]][d[2]].data.kind
+			end
 			_M._last_tabs_i = i
 		else
+			_M._last_tabs.all = true
 			_M._last_tabs_i = #self.tabslist
 		end
 	end
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index f19901fe8bc63f711c7eb34a2d742790086d9fa8..1c497be76287cff7d13936313e3c715142a85022 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -251,9 +251,9 @@ function _M:init(t, no_default)
 		physspeed =1,
 		dammod = { str=1 },
 		damrange=1.1,
-		talented = "unarmed",
 	}
-	-- Insures we have certain values for gloves to modify
+	-- Ensures we have certain values for gloves to modify
+	self.combat.talented = self.combat.talented or "unarmed"
 	self.combat.damrange = self.combat.damrange or 1.1
 	self.combat.physspeed = self.combat.physspeed or 1
 	self.combat.dammod = self.combat.dammod or {str=0.6}
@@ -1330,11 +1330,7 @@ function _M:move(x, y, force)
 		local grids = core.fov.circle_grids(self.x, self.y, 1, true)
 		for x, yy in pairs(grids) do for y, _ in pairs(yy) do
 			local trap = game.level.map(x, y, Map.TRAP)
-			if trap and not trap:knownBy(self) and self:canSee(trap) and self:checkHit(power, trap.detect_power) then
-				trap:setKnown(self, true, x, y)
-				game.level.map:updateMap(x, y)
-				game.logPlayer(self, "You have found a trap (%s)!", trap:getName())
-			end
+			if trap then self:detectTrap(trap, x, y, power) end
 		end end
 	end
 
@@ -1571,6 +1567,32 @@ function _M:doQuake(tg, x, y)
 	end)
 end
 
+--- Attempt to detect a trap at x, y
+-- param trap the trap to be detected
+-- param x, y trap coordinates
+-- param power detection power (optional)
+function _M:detectTrap(trap, x, y, power)
+	power = power or self:callTalent(self.T_HEIGHTENED_SENSES, "trapPower")
+	if power <= 0 then return end
+	trap = trap or game.level.map(x, y, Map.TRAP)
+	if trap then
+		x, y = x or trap.x, y or trap.y
+--print("[Actor:detectTrap]", self.name, "attempting to detect trap at", x, y, trap.name, power, trap.detect_power)
+		local known = trap:knownBy(self)
+		if not known then
+			if self == trap.summoner and known == nil then trap:setKnown(self, true, x, y) return end
+			known = self:canSee(trap) and self:checkHit(power, trap.detect_power)
+			if known then 
+				trap:setKnown(self, true, x, y)
+				if self.player then
+					game.level.map:updateMap(x, y)
+					game.logPlayer(self, "#AQUAMARINE#You notice a trap (%s)!", trap:getName())
+				end
+			end
+		end
+	end
+end
+
 --- Reveals location surrounding the actor
 function _M:magicMap(radius, x, y, checker)
 	x = x or self.x
@@ -5978,27 +6000,31 @@ function _M:suffocate(value, src, death_message)
 	return false, true
 end
 
--- Can the actor see the target actor (or other entity)
+-- Can the actor see the target (Actor or other Entity), recomputes results (does not use can_see_cache)
 -- This does not check LOS or such, only the actual ability to see it.<br/>
--- Check for telepathy, invisibility, stealth, ...
+-- Checks for telepathy, invisibility, stealth, ...
+-- @param[type=Entity] actor the target Entity (usually Actor) to be seen
+-- @param[type=boolean] def the default result
+-- @param[type=number] def_pct the default percent chance
+-- @return[1] true or false
+-- @return[2] a number from 0 to 100 representing the percent "chance" to be seen
 function _M:canSeeNoCache(actor, def, def_pct)
 	if not actor then return false, 0 end
 
-	-- Full ESP
-	if self.esp_all and self.esp_all > 0 then
-		return true, 100
-	end
+	if actor.__is_actor then -- check ESP against actors
+		if self.esp_all and self.esp_all > 0 then return true, 100 end -- Full ESP
 
-	-- ESP, see all, or only types/subtypes
-	if self.esp then
-		local esp = self.esp
-		local t, st = tostring(rawget(actor, "type") or "???"), tostring(rawget(actor, "subtype") or "???")
-		-- Type based ESP
-		if esp[t] and esp[t] > 0 then
-			return true, 100
-		end
-		if esp[t.."/"..st] and esp[t.."/"..st] > 0 then
-			return true, 100
+		-- ESP, see all, or only types/subtypes
+		if self.esp then
+			local esp = self.esp
+			local t, st = tostring(rawget(actor, "type") or "???"), tostring(rawget(actor, "subtype") or "???")
+			-- Type based ESP
+			if esp[t] and esp[t] > 0 then
+				return true, 100
+			end
+			if esp[t.."/"..st] and esp[t.."/"..st] > 0 then
+				return true, 100
+			end
 		end
 	end
 
@@ -6007,33 +6033,38 @@ function _M:canSeeNoCache(actor, def, def_pct)
 		return false, 0
 	end
 
-	-- Check for stealth. Checks against the target cunning and level
-	if actor ~= self and actor.attr and actor:attr("stealth") then
-		local def = self:combatSeeStealth()
-		local hit, chance = self:checkHitOld(def, actor:attr("stealth") + (actor:attr("inc_stealth") or 0), 0, 100)
-		if not hit then
-			return false, chance
-		end
-	end
-
+	local chance, hit = 100
 	-- Check for invisibility. This is a "simple" checkHit between invisible and see_invisible attrs
 	if actor ~= self and actor.attr and actor:attr("invisible") then
 		-- Special case, 0 see invisible, can NEVER see invisible things
 		local def = self:combatSeeInvisible()
 		if def <= 0 then return false, 0 end
-		local hit, chance = self:checkHitOld(def, actor:attr("invisible"), 0, 100)
-		if not hit then
-			return false, chance
+		hit, chance = self:checkHitOld(def, actor:attr("invisible"), 0, 100)
 		end
+	-- Check for stealth. Applies cunning and level vs target's stealth attributes
+	if actor ~= self and actor.attr and actor:attr("stealth") then
+		local def, st_chance = self:combatSeeStealth()
+		hit, st_chance = self:checkHitOld(def, actor:attr("stealth") + (actor:attr("inc_stealth") or 0), 0, 100)
+		chance = chance*st_chance/100
 	end
+	if chance < 100 then hit = rng.percent(chance) else hit = true end
 
 	if def ~= nil then
 		return def, def_pct
 	else
-		return true, 100
+		return hit, chance
 	end
 end
 
+--- Can the actor see the target (Actor or other Entity)?
+-- This does not check LOS or such, only the actual ability to see it.<br/>
+-- Checks for telepathy, invisibility, stealth, ...
+-- Stores results in self.can_see_cache for later calls
+-- @param[type=Actor] actor the target actor to check
+-- @param[type=boolean] def the default result
+-- @param[type=number] def_pct the default percent chance
+-- @return[1] true or false
+-- @return[2] a number from 0 to 100 representing the "chance" to be seen
 function _M:canSee(actor, def, def_pct)
 	if not actor then return false, 0 end
 
@@ -6058,7 +6089,7 @@ function _M:resetCanSeeCache()
 	self.can_see_cache = setmetatable({}, {__mode="k"})
 end
 
---- Reset the cache of everything else that had see us on the level
+--- Reset the cache of everything else that had seen us on the level
 function _M:resetCanSeeCacheOf()
 	if not game.level then return end
 	for uid, e in pairs(game.level.entities) do
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 8386e58940f1c015063f8ec0b9f512adc3f274f0..a37be1a4cc303c917b607fc299e38e1d822ede5a 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -1381,28 +1381,44 @@ function _M:tick()
 end
 
 -- Game Log management functions:
--- logVisible to determine if a message should be visible to the player
--- logMessage to add a message to the display
--- delayedLogMessage to queue an actor-specific message for display at the end of the current game tick
--- displayDelayedLogMessages() to display the queued messages (before combat damage messages)
--- delayedLogDamage to queue a combat (damage) message for display at the end of the current game tick
--- displayDelayedLogDamage to display the queued combat messages
-
--- output a message to the log based on the visibility of an actor to the player
+-- logVisible: determines if a message should be visible to the player
+-- logMessage: creates the message to be passed to the display
+-- delayedLogMessage: queues an actor-specific message for display at the end of the current game tick
+-- displayDelayedLogMessages: displays the queued delayedLogMessage messages (before combat damage messages)
+-- delayedLogDamage: queues combat damage (and associated message) for display at the end of the current game tick
+-- displayDelayedLogDamage: collates and displays queued delayedLogDamage information
+
+--- Output a message to the log based on the visibility of an actor to the player
+-- @param e the actor(entity) to check visibility for
+-- @param style the message to display
+-- @param ... arguments to be passed to format for style
 function _M.logSeen(e, style, ...)
 	if e and e.player or (not e.dead and e.x and e.y and game.level and game.level.map.seens(e.x, e.y) and game.player:canSee(e)) then game.log(style, ...) end
 end
 
--- determine whether an action between 2 actors should produce a message in the log and if the player
--- can identify them
--- output: src, srcSeen: source display?, identify?
--- tgt, tgtSeen: target display?, identify?
--- output: Visible? and srcSeen (source is identified by the player), tgtSeen(target is identified by the player)
+--- Determine whether an action between 2 actors (or entities or effects) should produce a message in the log
+--		and if they should be identified to the player
+-- @param source: source of the action
+-- @param target: target of the action
+-- @return[1] [type=boolean] message visible to player
+-- @return[2] [type=boolean] source is identified by player
+-- @return[3] [type=boolean] target is identified by player
 function _M:logVisible(source, target)
-	-- target should display if it's the player, an actor (or projectile) in a seen tile, or a non-actor without coordinates
-	local tgt = target and (target.player or ((target.__is_actor or target.__is_projectile) and game.level.map.seens(target.x, target.y)) or (not target.__is_actor and not target.x))
-	local tgtSeen = tgt and (target.player or game.player:canSee(target)) or false
-	local src, srcSeen = false, false
+	-- target should display if it's the player, an acting entity (actor, projectile, or trap) in a seen tile, or a non-acting entity without coordinates
+	local tgt, tgtSeen
+	if target then
+		if target.player then tgt, tgtSeen = true, true
+		else
+			if target.__is_actor or target.__is_projectile or target.__is_trap then
+				tgt = game.level.map.seens(target.x, target.y)
+			else
+				tgt = not target.x
+			end
+			tgtSeen = tgt and game.player:canSee(target) or false
+		end
+	end
+	
+	local src, srcSeen, src_act = false, false
 	-- Special cases
 	if not source.x then -- special case: unpositioned source uses target parameters (for timed effects on target)
 		if tgtSeen then
@@ -1410,18 +1426,29 @@ function _M:logVisible(source, target)
 		else
 			src, tgt = nil, nil
 		end
-	else -- source should display if it's the player or an actor (or projectile) in a seen tile, or same as target for non-actors
-		src = source.player or ((source.__is_actor or source.__is_projectile) and game.level.map.seens(source.x, source.y)) or (not source.__is_actor and tgt)
-		srcSeen = src and game.player:canSee(source) or false
+	else -- source should display if it's the player or an acting entity in a seen tile, or same as target for non-acting entities
+		if source.player then src, srcSeen = true, true
+		else
+			if source.__is_actor or source.__is_projectile or source.__is_trap then
+				src = game.level.map.seens(source.x, source.y)
+			else
+				src = tgt
+			end
+			srcSeen = src and game.player:canSee(source) or false
+		end
 	end
-
 	return src or tgt or false, srcSeen, tgtSeen
 end
 
--- Generate a message (string) for the log with possible source and target,
--- highlighting the player and taking visibility into account
--- srcSeen, tgtSeen = can player see(identify) the source, target?
--- style text message to display, may contain:
+--- Generate a message (string) for the log with possible source and target,
+-- 		highlights the player and takes visibility into account
+-- @param source: source (primary) actor
+-- @param srcSeen: [type=boolean] source is identified
+-- @param target: target (secondary) actor
+-- @param tgtSeen: [type=boolean] target is identified
+-- @param style the message to display
+-- @param ... arguments to be passed to format for style
+-- @return the string with certain fields replaced:
 -- #source#|#Source# -> <displayString>..self.name|self.name:capitalize()
 -- #target#|#Target# -> target.name|target.name:capitalize()
 function _M:logMessage(source, srcSeen, target, tgtSeen, style, ...)
@@ -1449,10 +1476,14 @@ function _M:logMessage(source, srcSeen, target, tgtSeen, style, ...)
 	return style
 end
 
--- log an entity-specific message for display later with displayDelayedLogDamage
--- only one message (processed with logMessage) will be logged for each source and label
+--- Log an entity-specific message for display later with displayDelayedLogMessages
 -- useful to avoid spamming repeated messages
--- target is optional and is used only to resolve the msg
+-- @param source: source (primary) actor
+-- @param target [optional]: target (secondary) actor (used only to resolve msg)
+-- @param label: a unique tag for this message
+-- @param msg raw string passed to logMessage
+--	takes visibility into account
+-- 	only one message (processed with logMessage) will be logged for each source and label
 function _M:delayedLogMessage(source, target, label, msg, ...)
 	local visible, srcSeen, tgtSeen = self:logVisible(source, target)
 	if visible then
@@ -1462,7 +1493,8 @@ function _M:delayedLogMessage(source, target, label, msg, ...)
 	end
 end
 
--- display the delayed log messages
+--- Push all queued delayed log messages to the combat log
+-- Called at the end of each game tick
 function _M:displayDelayedLogMessages()
 	if not self.uiset or not self.uiset.logdisplay then return end
 	for src, msgs in pairs(self.delayed_log_messages) do
@@ -1473,7 +1505,8 @@ function _M:displayDelayedLogMessages()
 	self.delayed_log_messages = {}
 end
 
--- Note: There can be up to a 1 tick delay in displaying log information
+--- Collate and push all queued delayed log damage information to the combat log
+-- Called at the end of each game tick
 function _M:displayDelayedLogDamage()
 	if not self.uiset or not self.uiset.logdisplay then return end
 	for real_src, psrcs in pairs(self.delayed_log_damage) do
@@ -1514,7 +1547,13 @@ function _M:displayDelayedLogDamage()
 	self.delayed_log_damage = {}
 end
 
--- log and collate combat damage for later display with displayDelayedLogDamage
+--- Queue combat damage values and messages for later display with displayDelayedLogDamage
+-- @param src: source (primary) actor dealing the damage
+-- @param target: target (secondary) actor recieving the damage
+-- @param dam: [type=number] damage effectively dealt, added to total
+--		negative dam is counted as healing and summed separately
+-- @param desc: [type=string] text description of damage dealth, passed directly to log message
+-- @param crit: [type=boolean] set true if the damage was dealt via critcal hit
 function _M:delayedLogDamage(src, target, dam, desc, crit)
 	if not target or not src then return end
 	local psrc = src.__project_source or src -- assign message to indirect damage source if available
diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua
index a2e361bc8184379a9f212046cfdb2c7ace6f50e0..ea2a2f3390fefee04e5cf2d67353fc9f993b742b 100644
--- a/game/modules/tome/class/Object.lua
+++ b/game/modules/tome/class/Object.lua
@@ -41,6 +41,9 @@ _M.projectile_class = "mod.class.Projectile"
 
 _M.logCombat = Combat.logCombat
 
+-- ego fields that are appended as a list when the ego is applied (by Zone:applyEgo)
+_M._special_ego_rules = {special_on_hit=true, special_on_crit=true, special_on_kill=true, charm_on_use=true}
+
 function _M:getRequirementDesc(who)
 	local base_getRequirementDesc = engine.Object.getRequirementDesc
 	if self.subtype == "shield" and type(self.require) == "table" and who:knowTalent(who.T_SKIRMISHER_BUCKLER_EXPERTISE) then
diff --git a/game/modules/tome/class/Trap.lua b/game/modules/tome/class/Trap.lua
index d38eb06261e4dd532763f10e304bcbac3722d177..7b3fe8b1898d64e86c23bf482c0ae3a50072ae3b 100644
--- a/game/modules/tome/class/Trap.lua
+++ b/game/modules/tome/class/Trap.lua
@@ -65,6 +65,21 @@ function _M:resolveSource()
 	end
 end
 
+--- Called when the trap is added to the level
+function _M:added()
+	engine.Entity.added(self)
+	if self.x and self.y then --give adjacent actors a chance to detect the trap when it is placed
+		local grids = core.fov.circle_grids(self.x, self.y, 1, true)
+		local act
+		for x, yy in pairs(grids) do for y, _ in pairs(yy) do
+			act = game.level.map(x, y, engine.Map.ACTOR)
+			if act and not self:knownBy(act) then
+				act:detectTrap(self, self.x, self.y)
+			end
+		end end
+	end
+end
+
 -- Gets the full name of the trap
 function _M:getName()
 	local name = self.name or "trap"
diff --git a/game/modules/tome/class/Zone.lua b/game/modules/tome/class/Zone.lua
index 7a78aa8fcbee44cbb4b1fc16d5a646b712d35c64..aaf08bf5c24ce1e1a410d276b27f9cf6c388c847 100644
--- a/game/modules/tome/class/Zone.lua
+++ b/game/modules/tome/class/Zone.lua
@@ -28,10 +28,15 @@ _M:enableLastPersistZones(3)
  -- retain the room map after level generation (for runPostGeneration callbacks)
 _M._retain_level_room_map = true
 
+-- object ego fields that are appended as a list when the ego is applied
+-- overridden by mod.class.Object._special_ego_rules (defined here for backwards compatibility)
+_M._object_special_ego_rules = {special_on_hit=true, special_on_crit=true, special_on_kill=true}
+
 -- Merge special_on_crit values.
 _M:addEgoRule("object", function(dvalue, svalue, key, dst, src, rules, state)
-	-- Only work on the special_on_* keys.
-	if key ~= 'special_on_hit' and key ~= 'special_on_crit' and key ~= 'special_on_kill' then return end
+	-- Only apply to some special fields
+	local special_rule_egos = mod.class.Object._special_ego_rules or _M._object_special_ego_rules
+	if not special_rule_egos[key] then return end
 	-- If the special isn't a table, make it an empty one.
 	if type(dvalue) ~= 'table' then dvalue = {} end
 	if type(svalue) ~= 'table' then svalue = {} end
diff --git a/game/modules/tome/data/general/objects/egos/charms.lua b/game/modules/tome/data/general/objects/egos/charms.lua
index a5ae6f4f55b47fe4ef29c222ab8762a0ed09356e..e69ce495711f8c69c6dfd7498eec594a957dc22c 100644
--- a/game/modules/tome/data/general/objects/egos/charms.lua
+++ b/game/modules/tome/data/general/objects/egos/charms.lua
@@ -17,16 +17,35 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
+-- modify the power and cooldown of charm powers
+-- This makes adjustments after zone:finishEntity is finished, which handles any egos added via e.addons
+local function modify_charm(e, e, zone, level)
+	for i, c_mod in ipairs(e.charm_power_mods) do
+		c_mod(e, e, zone, level)
+	end
+	if e._old_finish and e._old_finish ~= e._modify_charm then return e._old_finish(e, e, zone, level) end
+end
+
 newEntity{
 	name = "quick ", prefix=true,
 	keywords = {quick=true},
 	level_range = {1, 50},
 	rarity = 15,
 	cost = 5,
+	_modify_charm = modify_charm,
 	resolvers.genericlast(function(e)
-		if not e.use_power or not e.charm_power then return end
-		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))
+		if e.finish ~= e._modify_charm then e._old_finish = e.finish end
+		e.finish = e._modify_charm
+		e.charm_power_mods = e.charm_power_mods or {}
+		table.insert(e.charm_power_mods, function(e, e, zone, level)
+			if e.charm_power and e.use_power and e.use_power.power then
+				print("\t Applying quick ego changes.")
+				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.6, 0.9))
+			else
+				print("\tquick ego changes aborted.")
+			end
+		end)
 	end),
 }
 
@@ -36,10 +55,20 @@ newEntity{
 	level_range = {1, 50},
 	rarity = 15,
 	cost = 5,
+	_modify_charm = modify_charm,
 	resolvers.genericlast(function(e)
-		if not e.use_power or not e.charm_power then return end
-		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))
+		if e.finish ~= e._modify_charm then e._old_finish = e.finish end
+		e.finish = e._modify_charm
+		e.charm_power_mods = e.charm_power_mods or {}
+		table.insert(e.charm_power_mods, function(e, e, zone, level)
+			if e.charm_power and e.use_power and e.use_power.power then
+				print("\t Applying supercharged ego changes.")
+				e.use_power.power = math.ceil(e.use_power.power * rng.float(1.1, 1.3))
+				e.charm_power = math.ceil(e.charm_power * rng.float(1.3, 1.5))
+			else
+				print("\tsupercharged ego changes aborted.")
+			end
+		end)
 	end),
 }
 
@@ -50,9 +79,19 @@ newEntity{
 	greater_ego = 1,
 	rarity = 16,
 	cost = 5,
+	_modify_charm = modify_charm,
 	resolvers.genericlast(function(e)
-		if not e.use_power or not e.charm_power then return end
-		e.use_power.power = math.ceil(e.use_power.power * rng.float(1.4, 1.7))
-		e.charm_power = math.ceil(e.charm_power * rng.float(1.6, 1.9))
+		if e.finish ~= e._modify_charm then e._old_finish = e.finish end
+		e.finish = e._modify_charm
+		e.charm_power_mods = e.charm_power_mods or {}
+		table.insert(e.charm_power_mods, function(e, e, zone, level)
+			if e.charm_power and e.use_power and e.use_power.power then
+				print("\t Applying overpowered ego changes.")
+				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.6, 1.9))
+			else
+				print("\toverpowered ego changes aborted.")
+			end
+		end)
 	end),
 }
diff --git a/game/modules/tome/data/general/objects/egos/torques.lua b/game/modules/tome/data/general/objects/egos/torques.lua
index 7b582276cfc3ef582545fa6e79eb02010ad4c3ef..37aa4fad657fc96f3e405710086db431f0f937cb 100644
--- a/game/modules/tome/data/general/objects/egos/torques.lua
+++ b/game/modules/tome/data/general/objects/egos/torques.lua
@@ -34,7 +34,7 @@ newEntity{
 			who:incPsi(self:getCharmPower(who, true) / 7)
 		end},
 	},
-	use_power = {tactical = {PSI = 1}}
+	use_power = {tactical = {PSI = 0.5}}
 }
 
 newEntity{
@@ -49,7 +49,7 @@ newEntity{
 			who:incHate(self:getCharmPower(who, true) / 7)
 		end},
 	},
-	use_power = {tactical = {HATE = 1}}
+	use_power = {tactical = {HATE = 0.5}}
 }
 
 newEntity{
@@ -79,7 +79,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
-		talent_cd_reduction={[Talents.T_SILENCE]=-5},
+		talent_cd_reduction={[Talents.T_SILENCE]=1},
 		learn_talent = {[Talents.T_SILENCE] = resolvers.mbonus_material(4, 1)},
 	},
 }
@@ -93,7 +93,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
-		talent_cd_reduction={[Talents.T_TELEKINETIC_BLAST]=-5},
+--		talent_cd_reduction={[Talents.T_TELEKINETIC_BLAST]=-5},
 		learn_talent = {[Talents.T_TELEKINETIC_BLAST] = resolvers.mbonus_material(4, 1)},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/totems-powers.lua b/game/modules/tome/data/general/objects/egos/totems-powers.lua
index a514f1eaa006c2205184c17be4864aff3c6545b4..36d256746bde3430a54c4b2a35f63d1c036158ca 100644
--- a/game/modules/tome/data/general/objects/egos/totems-powers.lua
+++ b/game/modules/tome/data/general/objects/egos/totems-powers.lua
@@ -21,7 +21,6 @@
 Totems
 *healing
 *cure illness
-*cure poisons
 *thorny skin
 ]]
 
@@ -79,7 +78,8 @@ newEntity{
 				end
 			end
 			return nb
-			end},
+			end,
+			},
 	}),
 }
 
@@ -122,7 +122,7 @@ newEntity{
 			who:project(tg, x, y, engine.DamageType.HEAL, dam)
 			game:playSoundNear(who, "talents/heal")
 			return {id=true, used=true}
-			end,
+		end,
 		"T_GLOBAL_CD",
 		{range = function(self, who) return math.floor(who:combatStatScale("wil", 6, 10)) end,
 		damage = function(self, who) return self:getCharmPower(who) end,
diff --git a/game/modules/tome/data/general/objects/egos/totems.lua b/game/modules/tome/data/general/objects/egos/totems.lua
index ab9e767f67679074b79d595a1ffc66e9266c9c16..eb206cf367523bb18fe4135a7effdbd439e6a493 100644
--- a/game/modules/tome/data/general/objects/egos/totems.lua
+++ b/game/modules/tome/data/general/objects/egos/totems.lua
@@ -34,7 +34,7 @@ newEntity{
 			who:incEquilibrium(-self:getCharmPower(who, true) / 5)
 		end},
 	},
-	use_power = {tactical = {EQUILIBRIUM = 1}}
+	use_power = {tactical = {EQUILIBRIUM = 0.5}}
 }
 
 newEntity{
@@ -49,7 +49,7 @@ newEntity{
 			who:incStamina(self:getCharmPower(who, true) / 6)
 		end},
 	},
-	use_power = {tactical = {STAMINA = 1}}
+	use_power = {tactical = {STAMINA = 0.5}}
 }
 
 newEntity{
@@ -79,6 +79,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
+		talent_cd_reduction={[Talents.T_RUSHING_CLAWS]=1},
 		learn_talent = {[Talents.T_RUSHING_CLAWS] = resolvers.mbonus_material(4, 1)},
 	},
 }
@@ -92,6 +93,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
+		talent_cd_reduction={[Talents.T_LAY_WEB]=1},
 		learn_talent = {[Talents.T_LAY_WEB] = resolvers.mbonus_material(4, 1)},
 	},
 }
@@ -105,7 +107,7 @@ newEntity{
 	cost = 15,
 
 	wielder = {
-		talent_cd_reduction={[Talents.T_INVOKE_TENTACLE]=-5},
+--		talent_cd_reduction={[Talents.T_INVOKE_TENTACLE]=-5},
 		learn_talent = {[Talents.T_INVOKE_TENTACLE] = 1},
 	},
 }
diff --git a/game/modules/tome/data/general/objects/egos/wands.lua b/game/modules/tome/data/general/objects/egos/wands.lua
index 3b8a8c671dea22e4671884727936625608c8d28a..a0f919d7ce526c6f73a4ebaaf82647854c353bb8 100644
--- a/game/modules/tome/data/general/objects/egos/wands.lua
+++ b/game/modules/tome/data/general/objects/egos/wands.lua
@@ -108,7 +108,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
-		talent_cd_reduction={[Talents.T_VOID_BLAST]=-6},
+--		talent_cd_reduction={[Talents.T_VOID_BLAST]=-6},
 		learn_talent = {[Talents.T_VOID_BLAST] = resolvers.mbonus_material(4, 1)},
 	},
 }
@@ -122,6 +122,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
+		talent_cd_reduction={[Talents.T_VOLCANO]=2},
 		learn_talent = {[Talents.T_VOLCANO] = resolvers.mbonus_material(4, 1)},
 	},
 }
@@ -135,6 +136,7 @@ newEntity{
 	cost = 5,
 
 	wielder = {
+		talent_cd_reduction={[Talents.T_STRIKE]=1},
 		learn_talent = {[Talents.T_STRIKE] = resolvers.mbonus_material(4, 1)},
 	},
 }
diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua
index 0eaa3d85d7ca9314472760ee5760d260f2e27c9c..afbf9c5744d7ddd6518d73c9912adf8f5d91c8a9 100644
--- a/game/modules/tome/resolvers.lua
+++ b/game/modules/tome/resolvers.lua
@@ -497,7 +497,7 @@ function resolvers.calc.charm(tt, e)
 	local cd = tt[2]
 	e.max_power = cd
 	e.power = e.max_power
-	e.use_power = {name=tt[1], power=cd, use=tt[3], __no_merge_add=true}
+	e.use_power = table.merge(e.use_power or {}, {name=tt[1], power=cd, use=tt[3], __no_merge_add=true})
 	if e.talent_cooldown == nil then e.talent_cooldown = tt[4] or "T_GLOBAL_CD" end
 	if tt[5] then table.merge(e.use_power, tt[5], true) end
 	return